From 7d127815cfa09d7c7af43023c258c58e1ca80bcb Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Fri, 25 Jun 2021 11:09:41 +0200 Subject: [PATCH 01/25] Namespaces --- src/rust/ide/lib/args/src/lib.rs | 1 + .../lib/enso-protocol/src/project_manager.rs | 92 +++++++---- src/rust/ide/lib/parser/build.rs | 2 +- src/rust/ide/lib/parser/tests/macros.rs | 6 +- src/rust/ide/src/config.rs | 15 +- src/rust/ide/src/controller/graph.rs | 23 +-- src/rust/ide/src/controller/graph/executed.rs | 2 + src/rust/ide/src/controller/ide.rs | 2 +- src/rust/ide/src/controller/ide/desktop.rs | 6 +- src/rust/ide/src/controller/ide/plain.rs | 14 +- src/rust/ide/src/controller/module.rs | 4 +- src/rust/ide/src/controller/project.rs | 22 +-- src/rust/ide/src/controller/searcher.rs | 75 +++++---- .../ide/src/controller/searcher/action.rs | 2 +- src/rust/ide/src/double_representation.rs | 1 + .../ide/src/double_representation/module.rs | 79 ++++----- .../ide/src/double_representation/project.rs | 153 ++++++++++++++++++ src/rust/ide/src/double_representation/tp.rs | 32 ++-- src/rust/ide/src/ide/initializer.rs | 17 +- .../ide/src/model/execution_context/plain.rs | 6 +- src/rust/ide/src/model/module.rs | 16 +- src/rust/ide/src/model/project.rs | 25 ++- .../ide/src/model/project/synchronized.rs | 71 ++++---- .../src/model/suggestion_database/entry.rs | 8 +- src/rust/ide/src/test.rs | 33 ++-- src/rust/ide/tests/language_server.rs | 16 +- 26 files changed, 496 insertions(+), 227 deletions(-) create mode 100644 src/rust/ide/src/double_representation/project.rs diff --git a/src/rust/ide/lib/args/src/lib.rs b/src/rust/ide/lib/args/src/lib.rs index ace721d6ba..7bb626fd0f 100644 --- a/src/rust/ide/lib/args/src/lib.rs +++ b/src/rust/ide/lib/args/src/lib.rs @@ -27,6 +27,7 @@ ensogl::read_args! { project_manager : String, language_server_rpc : String, language_server_data : String, + namespace : String, platform : web::platform::Platform, frame : bool, theme : String, diff --git a/src/rust/ide/lib/enso-protocol/src/project_manager.rs b/src/rust/ide/lib/enso-protocol/src/project_manager.rs index 299657a664..7f1740b5f6 100644 --- a/src/rust/ide/lib/enso-protocol/src/project_manager.rs +++ b/src/rust/ide/lib/enso-protocol/src/project_manager.rs @@ -121,13 +121,18 @@ impl From for String { /// Project information, such as name, its id and last time it was opened. #[derive(Debug,Clone,Serialize,Deserialize,PartialEq)] +#[serde(rename_all="camelCase")] pub struct ProjectMetadata { /// Project's name. - pub name : ProjectName, + pub name:ProjectName, + /// Project's namespace, + pub namespace:String, /// Project's uuid. - pub id : Uuid, + pub id:Uuid, + /// Engine version to use for the project, represented by a semver version string. + pub engine_version:String, /// Last time the project was opened. - pub last_opened : Option + pub last_opened:Option } /// This type specifies what action should be taken if an Engine's component required to complete @@ -167,11 +172,15 @@ pub mod response { #[serde(rename_all="camelCase")] pub struct OpenProject { /// The version of the started language server represented by a semver version string. - pub engine_version : String, + pub engine_version:String, /// Address of the endpoint for JSON-RPC communication. - pub language_server_json_address : IpWithSocket, + pub language_server_json_address:IpWithSocket, /// Address of the endpoint for binary FlatBuffers communication. - pub language_server_binary_address : IpWithSocket, + pub language_server_binary_address:IpWithSocket, + /// The name of the project as it is opened. + pub project_name:ProjectName, + /// The namespace of the project. + pub project_namespace:String, } } @@ -218,6 +227,8 @@ mod mock_client_tests { engine_version : "0.2.1".to_owned(), language_server_json_address : language_server_address.clone(), language_server_binary_address : language_server_address, + project_name : ProjectName::new("Test"), + project_namespace : "local".to_owned(), }; let open_result = Ok(expected_open_result.clone()); let missing_component_action = MissingComponentAction::Fail; @@ -255,25 +266,33 @@ mod mock_client_tests { fn list_projects() { let mock_client = MockClient::default(); let project1 = ProjectMetadata { - name : ProjectName::new("project1"), - id : Uuid::default(), - last_opened : Some(DateTime::parse_from_rfc3339("2020-01-07T21:25:26Z").unwrap()) + name : ProjectName::new("project1"), + id : Uuid::default(), + last_opened : Some(DateTime::parse_from_rfc3339("2020-01-07T21:25:26Z").unwrap()), + engine_version : "0.2.21".to_owned(), + namespace : "local".to_owned(), }; let project2 = ProjectMetadata { name : ProjectName::new("project2"), id : Uuid::default(), - last_opened : Some(DateTime::parse_from_rfc3339("2020-02-02T13:15:20Z").unwrap()) + last_opened : Some(DateTime::parse_from_rfc3339("2020-02-02T13:15:20Z").unwrap()), + engine_version : "0.2.22".to_owned(), + namespace : "local".to_owned(), }; let expected_recent_projects = response::ProjectList { projects : vec![project1,project2] }; let sample1 = ProjectMetadata { - name : ProjectName::new("sample1"), - id : Uuid::default(), - last_opened : Some(DateTime::parse_from_rfc3339("2019-11-23T05:30:12Z").unwrap()) + name : ProjectName::new("sample1"), + id : Uuid::default(), + last_opened : Some(DateTime::parse_from_rfc3339("2019-11-23T05:30:12Z").unwrap()), + engine_version : "0.2.21".to_owned(), + namespace : "test".to_owned(), }; let sample2 = ProjectMetadata { - name : ProjectName::new("sample2"), - id : Uuid::default(), - last_opened : Some(DateTime::parse_from_rfc3339("2019-12-25T00:10:58Z").unwrap()) + name : ProjectName::new("sample2"), + id : Uuid::default(), + last_opened : Some(DateTime::parse_from_rfc3339("2019-12-25T00:10:58Z").unwrap()), + engine_version : "0.2.21".to_owned(), + namespace : "test".to_owned(), }; let expected_sample_projects = response::ProjectList { projects : vec![sample1,sample2] }; expect_call!(mock_client.list_projects(count=Some(2)) => @@ -370,8 +389,11 @@ mod remote_client_tests { let engine_version = "0.2.1".to_owned(); let language_server_json_address = IpWithSocket{host:"localhost".to_string(),port:27015}; let language_server_binary_address = IpWithSocket{host:"localhost".to_string(),port:27016}; + let project_name = ProjectName::new("Test"); + let project_namespace = "test_ns".to_owned(); let open_result = response::OpenProject {engine_version - ,language_server_json_address,language_server_binary_address}; + ,language_server_json_address,language_server_binary_address,project_name + ,project_namespace}; let open_result_json = json!({ "engineVersion" : "0.2.1", "languageServerJsonAddress" : { @@ -381,7 +403,9 @@ mod remote_client_tests { "languageServerBinaryAddress" : { "host" : "localhost", "port" : 27016 - } + }, + "projectName" : "Test", + "projectNamespace" : "test_ns", }); let project_name = String::from("HelloWorld"); let project_create_json = json!({ @@ -393,27 +417,35 @@ mod remote_client_tests { let number_of_projects_json = json!({"numberOfProjects":number_of_projects}); let num_projects_json = json!({"numProjects":number_of_projects}); let project1 = ProjectMetadata { - name : ProjectName::new("project1"), - id : Uuid::default(), - last_opened : Some(DateTime::parse_from_rfc3339("2020-01-07T21:25:26Z").unwrap()) + name : ProjectName::new("project1"), + id : Uuid::default(), + last_opened : Some(DateTime::parse_from_rfc3339("2020-01-07T21:25:26Z").unwrap()), + engine_version : "0.2.21".to_owned(), + namespace : "local".to_owned(), }; let project2 = ProjectMetadata { - name : ProjectName::new("project2"), - id : Uuid::default(), - last_opened : Some(DateTime::parse_from_rfc3339("2020-02-02T13:15:20Z").unwrap()) + name : ProjectName::new("project2"), + id : Uuid::default(), + last_opened : Some(DateTime::parse_from_rfc3339("2020-02-02T13:15:20Z").unwrap()), + engine_version : "0.2.22".to_owned(), + namespace : "local".to_owned(), }; let project_list = response::ProjectList { projects : vec![project1,project2] }; let project_list_json = json!({ "projects" : [ { - "id" : "00000000-0000-0000-0000-000000000000", - "last_opened" : "2020-01-07T21:25:26+00:00", - "name" : "project1" + "id" : "00000000-0000-0000-0000-000000000000", + "lastOpened" : "2020-01-07T21:25:26+00:00", + "name" : "project1", + "engineVersion" : "0.2.21", + "namespace" : "local" }, { - "id" : "00000000-0000-0000-0000-000000000000", - "last_opened" : "2020-02-02T13:15:20+00:00", - "name" : "project2" + "id" : "00000000-0000-0000-0000-000000000000", + "lastOpened" : "2020-02-02T13:15:20+00:00", + "name" : "project2", + "engineVersion" : "0.2.22", + "namespace" : "local" } ] }); diff --git a/src/rust/ide/lib/parser/build.rs b/src/rust/ide/lib/parser/build.rs index 67c62af935..48d8872fac 100644 --- a/src/rust/ide/lib/parser/build.rs +++ b/src/rust/ide/lib/parser/build.rs @@ -25,7 +25,7 @@ use std::path::PathBuf; const PARSER_PATH: &str = "./pkg/scala-parser.js"; /// Commit from `enso` repository that will be used to obtain parser from. -const PARSER_COMMIT: &str = "e53ee305d18d070c715205ba4a5758f53b4ef23b"; +const PARSER_COMMIT: &str = "44ef29a3b70ccada491ac71e199f323211c997d3"; /// Magic code that needs to be prepended to ScalaJS generated parser due to: /// https://github.com/scala-js/scala-js/issues/3677/ diff --git a/src/rust/ide/lib/parser/tests/macros.rs b/src/rust/ide/lib/parser/tests/macros.rs index 0d0153be24..f164843017 100644 --- a/src/rust/ide/lib/parser/tests/macros.rs +++ b/src/rust/ide/lib/parser/tests/macros.rs @@ -15,7 +15,7 @@ fn import_utilities() { let parser = Parser::new_or_panic(); let expect_import = |code:&str| { let ast = parser.parse_line(code).unwrap(); - assert!(is_ast_import(&ast)); + assert!(is_ast_import(&ast), "Not Ast import: {:?}", ast); let ast_match = ast_as_import_match(&ast).unwrap(); assert_eq!(&ast,ast_match.ast()); assert!(is_match_import(&ast_match)); @@ -29,10 +29,12 @@ fn import_utilities() { expect_import("import"); expect_import("import Foo"); + expect_import("import foo.Foo.Bar"); + expect_import("import foo.Foo.Bar"); expect_import("import Foo.Bar"); expect_import("import Foo.Bar.Baz"); expect_import("from Foo import Bar"); - expect_import("from Foo import all hiding Bar"); + expect_import("from foo.Foo import all hiding Bar"); expect_import("from Base.Data.List import all hiding Cons, Nil"); expect_not_import("type Foo"); diff --git a/src/rust/ide/src/config.rs b/src/rust/ide/src/config.rs index 101893c2e8..f2b0dcd0a1 100644 --- a/src/rust/ide/src/config.rs +++ b/src/rust/ide/src/config.rs @@ -41,6 +41,7 @@ pub enum BackendService { LanguageServer { json_endpoint : String, binary_endpoint : String, + namespace : String, } } @@ -62,15 +63,17 @@ impl BackendService { Ok(Self::ProjectManager {endpoint}) } } else { - match (&args.language_server_rpc,&args.language_server_data) { - (Some(json_endpoint),Some(binary_endpoint)) => { + match (&args.language_server_rpc,&args.language_server_data,&args.namespace) { + (Some(json_endpoint),Some(binary_endpoint),Some(namespace)) => { let json_endpoint = json_endpoint.clone(); let binary_endpoint = binary_endpoint.clone(); - Ok(Self::LanguageServer {json_endpoint,binary_endpoint}) + let namespace = namespace.clone(); + Ok(Self::LanguageServer {json_endpoint,binary_endpoint,namespace}) } - (None,None) => Ok(default()), - (Some(_),None) => Err(MissingOption(args.names().language_server_data()).into()), - (None,Some(_)) => Err(MissingOption(args.names().language_server_rpc()).into()) + (None,None,None) => Ok(default()), + (None,_,_) => Err(MissingOption(args.names().language_server_rpc()).into()), + (_,None,_) => Err(MissingOption(args.names().language_server_data()).into()), + (_,_,None) => Err(MissingOption(args.names().namespace()).into()), } } } diff --git a/src/rust/ide/src/controller/graph.rs b/src/rust/ide/src/controller/graph.rs index 4b74f494a7..4bb18a4ae4 100644 --- a/src/rust/ide/src/controller/graph.rs +++ b/src/rust/ide/src/controller/graph.rs @@ -484,7 +484,7 @@ impl Handle { let root_id = project.content_root_id(); let module_path = model::module::Path::from_method(root_id,&method)?; let module = project.module(module_path).await?; - let definition = module.lookup_method(project.name().as_ref(),&method)?; + let definition = module.lookup_method(project.qualified_name(),&method)?; Self::new(parent,module,project.suggestion_db(),project.parser(),definition) } @@ -909,19 +909,22 @@ pub mod tests { use super::*; use crate::double_representation::identifier::NormalizedName; + use crate::double_representation::project; use crate::executor::test_utils::TestWithLocalPoolExecutor; use crate::model::module::Position; + use crate::model::suggestion_database; + use crate::test::mock::data; use ast::crumbs; use ast::test_utils::expect_shape; - use data::text::Index; - use data::text::TextChange; + use enso_data::text::Index; + use enso_data::text::TextChange; use enso_protocol::language_server::MethodPointer; use parser::Parser; use utils::test::ExpectTuple; use wasm_bindgen_test::wasm_bindgen_test; - use crate::model::suggestion_database; + /// Returns information about all the connections between graph's nodes. /// @@ -935,7 +938,7 @@ pub mod tests { pub struct MockData { pub module_path : model::module::Path, pub graph_id : Id, - pub project_name : String, + pub project_name : project::QualifiedName, pub code : String, pub suggestions : HashMap, } @@ -945,10 +948,10 @@ pub mod tests { /// node. pub fn new() -> Self { MockData { - module_path : crate::test::mock::data::module_path(), - graph_id : crate::test::mock::data::graph_id(), - project_name : crate::test::mock::data::PROJECT_NAME.to_owned(), - code : crate::test::mock::data::CODE.to_owned(), + module_path : data::module_path(), + graph_id : data::graph_id(), + project_name : data::project_qualified_name(), + code : data::CODE.to_owned(), suggestions : default(), } } @@ -984,7 +987,7 @@ pub mod tests { } pub fn method(&self) -> MethodPointer { - self.module_path.method_pointer(&self.project_name,self.graph_id.to_string()) + self.module_path.method_pointer(self.project_name.clone(),self.graph_id.to_string()) } pub fn suggestion_db(&self) -> Rc { diff --git a/src/rust/ide/src/controller/graph/executed.rs b/src/rust/ide/src/controller/graph/executed.rs index 9206165c62..22e9be36ba 100644 --- a/src/rust/ide/src/controller/graph/executed.rs +++ b/src/rust/ide/src/controller/graph/executed.rs @@ -338,7 +338,9 @@ pub mod tests { let method = self.graph.method(); let mut project = model::project::MockAPI::new(); let ctx = Rc::new(self.ctx.create()); + let proj_name = test::mock::data::project_qualified_name(); model::project::test::expect_name(&mut project,test::mock::data::PROJECT_NAME); + model::project::test::expect_qualified_name(&mut project,&proj_name); model::project::test::expect_parser(&mut project,&parser); model::project::test::expect_module(&mut project,module); model::project::test::expect_execution_ctx(&mut project,ctx); diff --git a/src/rust/ide/src/controller/ide.rs b/src/rust/ide/src/controller/ide.rs index 419cd62839..80f68ca42b 100644 --- a/src/rust/ide/src/controller/ide.rs +++ b/src/rust/ide/src/controller/ide.rs @@ -118,7 +118,7 @@ pub trait ManagingProjectAPI { fn list_projects(&self) -> BoxFuture>>; /// Open the project with given id and name. - fn open_project(&self, id:Uuid, name:ProjectName) -> BoxFuture; + fn open_project(&self, id:Uuid) -> BoxFuture; } diff --git a/src/rust/ide/src/controller/ide/desktop.rs b/src/rust/ide/src/controller/ide/desktop.rs index bd499f50d0..5ca1cc66f5 100644 --- a/src/rust/ide/src/controller/ide/desktop.rs +++ b/src/rust/ide/src/controller/ide/desktop.rs @@ -105,7 +105,7 @@ impl ManagingProjectAPI for Handle { let create_result = self.project_manager.create_project(&name,&version,&action).await?; let new_project_id = create_result.project_id; let project_mgr = self.project_manager.clone_ref(); - let new_project = Project::new_opened(&self.logger,project_mgr,new_project_id,name); + let new_project = Project::new_opened(&self.logger,project_mgr,new_project_id); self.current_project.set(new_project.await?); executor::global::spawn(self.notifications.publish(Notification::NewProjectCreated)); Ok(()) @@ -119,11 +119,11 @@ impl ManagingProjectAPI for Handle { }.boxed_local() } - fn open_project(&self, id: Uuid, name: ProjectName) -> BoxFuture { + fn open_project(&self, id: Uuid) -> BoxFuture { async move { let logger = &self.logger; let project_mgr = self.project_manager.clone_ref(); - let new_project = model::project::Synchronized::new_opened(logger,project_mgr,id,name); + let new_project = model::project::Synchronized::new_opened(logger,project_mgr,id); self.current_project.set(new_project.await?); executor::global::spawn(self.notifications.publish(Notification::ProjectOpened)); Ok(()) diff --git a/src/rust/ide/src/controller/ide/plain.rs b/src/rust/ide/src/controller/ide/plain.rs index 66ee8a093f..718c094772 100644 --- a/src/rust/ide/src/controller/ide/plain.rs +++ b/src/rust/ide/src/controller/ide/plain.rs @@ -3,9 +3,12 @@ //! See [`crate::controller::ide`] for more detailed description of IDE Controller API. use crate::prelude::*; + use crate::controller::ide::ManagingProjectAPI; use crate::controller::ide::Notification; use crate::controller::ide::StatusNotificationPublisher; +use crate::double_representation::project; +use crate::model::project::synchronized::Properties; use enso_protocol::project_manager::ProjectName; use parser::Parser; @@ -51,17 +54,22 @@ impl Handle { /// Create IDE Controller from Language Server endpoints, describing the opened project. pub async fn from_ls_endpoints - ( project_name : ProjectName + ( namespace : String + , project_name : ProjectName , version : semver::Version , json_endpoint : String , binary_endpoint : String ) -> FallibleResult { let logger = Logger::new("controller::ide::Plain"); + let properties = Properties { //TODO [ao]: this should be not the default; instead project model should not need the id. // See https://github.com/enso-org/ide/issues/1572 - let project_id = default(); + id : default(), + name : project::QualifiedName::from_segments(namespace,project_name)?, + engine_version : version + }; let project = model::project::Synchronized::new_connected - (&logger,None,json_endpoint,binary_endpoint,version,project_id,project_name).await?; + (&logger,None,json_endpoint,binary_endpoint,properties).await?; let status_notifications = default(); let parser = Parser::new_or_panic(); Ok(Self{logger,status_notifications,parser,project}) diff --git a/src/rust/ide/src/controller/module.rs b/src/rust/ide/src/controller/module.rs index 221e4de61c..c814daf787 100644 --- a/src/rust/ide/src/controller/module.rs +++ b/src/rust/ide/src/controller/module.rs @@ -2,9 +2,9 @@ use crate::prelude::*; -use crate::double_representation::identifier::ReferentName; use crate::double_representation::text::apply_code_change_to_id_map; use crate::double_representation::module; +use crate::double_representation::project; use crate::model::module::Path; use ast; @@ -111,7 +111,7 @@ impl Handle { } /// Get the module's qualified name. - pub fn qualified_name(&self, project_name:ReferentName) -> module::QualifiedName { + pub fn qualified_name(&self, project_name:project::QualifiedName) -> module::QualifiedName { module::QualifiedName::new(project_name,self.model.id()) } diff --git a/src/rust/ide/src/controller/project.rs b/src/rust/ide/src/controller/project.rs index 66cd1add76..ea1c633e5b 100644 --- a/src/rust/ide/src/controller/project.rs +++ b/src/rust/ide/src/controller/project.rs @@ -4,6 +4,7 @@ use crate::prelude::*; use crate::controller::graph::executed::Notification as GraphNotification; use crate::controller::ide::StatusNotificationPublisher; +use crate::double_representation::project; use enso_frp::web::platform; use enso_frp::web::platform::Platform; @@ -52,7 +53,8 @@ pub fn default_main_module_code() -> String { /// Method pointer that described the main method, i.e. the method that project view wants to open /// and which presence is currently required. -pub fn main_method_ptr(project_name:impl Str, module_path:&model::module::Path) -> MethodPointer { +pub fn main_method_ptr +(project_name:project::QualifiedName, module_path:&model::module::Path) -> MethodPointer { module_path.method_pointer(project_name,MAIN_DEFINITION_NAME) } @@ -125,9 +127,9 @@ impl Project { // TODO [mwu] This solution to recreate missing main file should be considered provisional // until proper decision is made. See: https://github.com/enso-org/enso/issues/1050 self.recreate_if_missing(&file_path,default_main_method_code()).await?; - let method = main_method_ptr(project.name(),&module_path); + let method = main_method_ptr(project.qualified_name(),&module_path); let module = self.model.module(module_path).await?; - Self::add_main_if_missing(project.name().as_ref(),&module,&method,&parser)?; + Self::add_main_if_missing(project.qualified_name(),&module,&method,&parser)?; // Here, we should be relatively certain (except race conditions in case of multiple // clients that we currently do not support) that main module exists and contains main @@ -164,7 +166,7 @@ impl Project { /// /// The lookup will be done using the given `main_ptr` value. pub fn add_main_if_missing - (project_name:&str, module:&model::Module, main_ptr:&MethodPointer, parser:&Parser) + (project_name:project::QualifiedName, module:&model::Module, main_ptr:&MethodPointer, parser:&Parser) -> FallibleResult { if module.lookup_method(project_name,main_ptr).is_err() { let mut info = module.info(); @@ -192,7 +194,7 @@ impl Project { fn display_warning_on_unsupported_engine_version(&self) -> FallibleResult { let requirements = semver::VersionReq::parse(ENGINE_VERSION_SUPPORTED)?; let version = self.model.engine_version(); - if !requirements.matches(version) { + if !requirements.matches(&version) { let message = format!("Unsupported Engine version. Please update engine_version in {} \ to {}.",package_yaml_path(&self.model.name()),ENGINE_VERSION_FOR_NEW_PROJECTS); self.status_notifications.publish_event(message); @@ -226,22 +228,22 @@ mod tests { let parser = parser::Parser::new_or_panic(); let mut data = crate::test::mock::Unified::new(); let module_name = data.module_path.module_name(); - let main_ptr = main_method_ptr(&data.project_name,&data.module_path); + let main_ptr = main_method_ptr(data.project_name.clone(),&data.module_path); // Check that module without main gets it after the call. let empty_module_code = ""; data.set_code(empty_module_code); let urm = data.undo_redo_manager(); let module = data.module(urm.clone_ref()); - assert!(module.lookup_method(&data.project_name,&main_ptr).is_err()); - Project::add_main_if_missing(&data.project_name, &module, &main_ptr, &parser).unwrap(); - assert!(module.lookup_method(&data.project_name,&main_ptr).is_ok()); + assert!(module.lookup_method(data.project_name.clone(),&main_ptr).is_err()); + Project::add_main_if_missing(data.project_name.clone(), &module, &main_ptr, &parser).unwrap(); + assert!(module.lookup_method(data.project_name.clone(),&main_ptr).is_ok()); // Now check that modules that have main already defined won't get modified. let mut expect_intact = move |code:&str| { data.set_code(code); let module = data.module(urm.clone_ref()); - Project::add_main_if_missing(&data.project_name, &module, &main_ptr, &parser).unwrap(); + Project::add_main_if_missing(data.project_name.clone(), &module, &main_ptr, &parser).unwrap(); assert_eq!(code,module.ast().repr()); }; expect_intact("main = 5"); diff --git a/src/rust/ide/src/controller/searcher.rs b/src/rust/ide/src/controller/searcher.rs index 2d26a8100b..b91c3d2402 100644 --- a/src/rust/ide/src/controller/searcher.rs +++ b/src/rust/ide/src/controller/searcher.rs @@ -10,6 +10,7 @@ use crate::double_representation::graph::GraphInfo; use crate::double_representation::graph::LocationHint; use crate::double_representation::module::QualifiedName; use crate::double_representation::node::NodeInfo; +use crate::double_representation::project; use crate::double_representation::tp; use crate::model::module::MethodId; use crate::model::module::NodeMetadata; @@ -416,7 +417,7 @@ impl Data { /// Additionally searcher should restore information about intended method, so we will be able /// to suggest arguments. fn new_with_edited_node - ( project_name : &str + ( project_name : project::QualifiedName , graph : &controller::Graph , database : &model::SuggestionDatabase , edited_node_id : ast::Id @@ -501,7 +502,7 @@ impl Searcher { let logger = Logger::sub(parent,"Searcher Controller"); let database = project.suggestion_db(); let data = if let Mode::EditNode{node_id} = mode { - Data::new_with_edited_node(&*project.name(),&graph.graph(),&*database,node_id)? + Data::new_with_edited_node(project.qualified_name(),&graph.graph(),&*database,node_id)? } else { default() }; @@ -587,6 +588,7 @@ impl Searcher { let id = self.data.borrow().input.next_completion_id(); let picked_completion = FragmentAddedByPickingSuggestion {id,picked_suggestion}; let code_to_insert = self.code_to_insert(&picked_completion).code; + debug!(self.logger, "Code to insert: \"{code_to_insert}\""); let added_ast = self.ide.parser().parse_line(&code_to_insert)?; let pattern_offset = self.data.borrow().input.pattern_offset; let new_expression = match self.data.borrow_mut().input.expression.take() { @@ -655,8 +657,8 @@ impl Searcher { let result = match action { action::ProjectManagement::CreateNewProject => manage_projects.create_new_project(), - action::ProjectManagement::OpenProject {id,name} => - manage_projects.open_project(*id,name.to_string().into()), + action::ProjectManagement::OpenProject {id,..} => + manage_projects.open_project(*id), }; if let Err(err) = result.await { error!(logger, "Error when creating new project: {err}"); @@ -997,7 +999,8 @@ impl Searcher { } fn module_qualified_name(&self) -> QualifiedName { - self.graph.graph().module.path().qualified_module_name(&*self.ide.current_project().name()) + let project_name = self.ide.current_project().qualified_name(); + self.graph.graph().module.path().qualified_module_name(project_name) } /// Get the user action basing of current input (see `UserAction` docs). @@ -1128,7 +1131,7 @@ pub mod test { use crate::model::suggestion_database::entry::Scope; use crate::test::mock::data::MAIN_FINISH; use crate::test::mock::data::MODULE_NAME; - use crate::test::mock::data::PROJECT_NAME; + use crate::test::mock::data::project_qualified_name; use enso_protocol::language_server::types::test::value_update_with_type; use json_rpc::expect_call; @@ -1208,23 +1211,25 @@ pub mod test { let mut client = language_server::MockClient::default(); client.require_all_calls(); client_setup(&mut data,&mut client); - let end_of_code = TextLocation::at_document_end(&data.graph.module.code); - let code_range = TextLocation::at_document_begin()..=end_of_code; - let graph = data.graph.controller(); - let node = &graph.graph().nodes().unwrap()[0]; - let this = ThisNode::new(vec![node.info.id()],&graph.graph()); - let this = data.selected_node.and_option(this); - let logger = Logger::new("Searcher");// new_empty - let database = Rc::new(SuggestionDatabase::new_empty(&logger)); - let mut ide = controller::ide::MockAPI::new(); - let mut project = model::project::MockAPI::new(); - let project_name = ImString::new(&data.graph.graph.project_name); - project.expect_name().returning_st(move || project_name.clone_ref()); + let end_of_code = TextLocation::at_document_end(&data.graph.module.code); + let code_range = TextLocation::at_document_begin()..=end_of_code; + let graph = data.graph.controller(); + let node = &graph.graph().nodes().unwrap()[0]; + let this = ThisNode::new(vec![node.info.id()],&graph.graph()); + let this = data.selected_node.and_option(this); + let logger = Logger::new("Searcher");// new_empty + let database = Rc::new(SuggestionDatabase::new_empty(&logger)); + let mut ide = controller::ide::MockAPI::new(); + let mut project = model::project::MockAPI::new(); + let project_qname = project_qualified_name(); + let project_name = project_qname.project.clone(); + project.expect_qualified_name().returning_st(move || project_qname.clone()); + project.expect_name().returning_st(move || project_name.clone()); let project = Rc::new(project); ide.expect_parser().return_const(Parser::new_or_panic()); ide.expect_current_project().returning_st(move || project.clone_ref()); ide.expect_manage_projects().returning_st(move || Err(ProjectOperationsNotSupported.into())); - let module_name = QualifiedName::from_segments(PROJECT_NAME, &[MODULE_NAME]).unwrap(); + let module_name = QualifiedName::from_segments(data.graph.graph.project_name.clone(), &[MODULE_NAME]).unwrap(); let searcher = Searcher { graph,logger,database, ide : Rc::new(ide), @@ -1274,8 +1279,8 @@ pub mod test { ..entry1.clone() }; let entry4 = model::suggestion_database::Entry { - self_type : Some("Test.Test".to_owned().try_into().unwrap()), - module : "Test.Test".to_owned().try_into().unwrap(), + self_type : Some("test.Test.Test".to_owned().try_into().unwrap()), + module : "test.Test.Test".to_owned().try_into().unwrap(), arguments : vec![ Argument { repr_type : "Any".to_string(), @@ -1316,7 +1321,7 @@ pub mod test { }; let entry10 = model::suggestion_database::Entry { name : "testFunction3".to_string(), - module : "Test.Other".to_owned().try_into().unwrap(), + module : "test.Test.Other".to_owned().try_into().unwrap(), scope : Scope::Everywhere, ..entry9.clone() }; @@ -1439,7 +1444,7 @@ pub mod test { #[wasm_bindgen_test] fn non_picked_function_arg_suggestions() { let mut fixture = Fixture::new_custom(|data,client| { - data.graph.module.code.insert_str(0,"import Test.Test\n\n"); + data.graph.module.code.insert_str(0,"import test.Test.Test\n\n"); data.code_location.line += 2; data.expect_completion(client,None,Some("String"),&[1]); data.expect_completion(client,None,Some("Number"),&[]); @@ -1468,7 +1473,7 @@ pub mod test { let requested_types:Rc>>> = default(); let requested_types2 = requested_types.clone(); let mut fixture = Fixture::new_custom(move |data,client| { - data.graph.module.code.insert_str(0,"import Test.Test\n\n"); + data.graph.module.code.insert_str(0,"import test.Test.Test\n\n"); data.code_location.line += 2; for _ in 0..EXPECTED_REQUESTS { let requested_types = requested_types2.clone(); @@ -1793,12 +1798,12 @@ pub mod test { searcher.mode = Immutable(Mode::NewNode {position}); searcher.commit_node().unwrap(); - let expected_code = "import Test.Test\nmain = \n 2 + 2\n operator1 = Test.testMethod1"; + let expected_code = "import test.Test.Test\nmain = \n 2 + 2\n operator1 = Test.testMethod1"; assert_eq!(module.ast().repr(), expected_code); let (node1,node2) = searcher.graph.graph().nodes().unwrap().expect_tuple(); let expected_intended_method = Some(MethodId { - module : "Test.Test".to_string().try_into().unwrap(), - defined_on_type : "Test.Test".to_string().try_into().unwrap(), + module : "test.Test.Test".to_string().try_into().unwrap(), + defined_on_type : "test.Test.Test".to_string().try_into().unwrap(), name : "testMethod1".to_string(), }); assert_eq!(node2.metadata.unwrap().intended_method, expected_intended_method); @@ -1806,7 +1811,7 @@ pub mod test { // Edit existing node. searcher.mode = Immutable(Mode::EditNode {node_id:node1.info.id()}); searcher.commit_node().unwrap(); - let expected_code = "import Test.Test\nmain = \n Test.testMethod1\n operator1 = Test.testMethod1"; + let expected_code = "import test.Test.Test\nmain = \n Test.testMethod1\n operator1 = Test.testMethod1"; let (node1,_) = searcher.graph.graph().nodes().unwrap().expect_tuple(); assert_eq!(node1.metadata.unwrap().intended_method, expected_intended_method); assert_eq!(module.ast().repr(), expected_code); @@ -1822,21 +1827,21 @@ pub mod test { let database = searcher.database; // Node had not intended method. - let searcher_data = Data::new_with_edited_node(PROJECT_NAME,&graph,&database,node_id).unwrap(); + let searcher_data = Data::new_with_edited_node(project_qualified_name(),&graph,&database,node_id).unwrap(); assert_eq!(searcher_data.input.repr(), node.info.expression().repr()); assert!(searcher_data.fragments_added_by_picking.is_empty()); assert!(searcher_data.actions.is_loading()); // Node had intended method, but it's outdated. let intended_method = MethodId { - module : "Test.Test".to_string().try_into().unwrap(), - defined_on_type : "Test.Test".to_string().try_into().unwrap(), + module : "test.Test.Test".to_string().try_into().unwrap(), + defined_on_type : "test.Test.Test".to_string().try_into().unwrap(), name : "testMethod1".to_string() }; graph.module.with_node_metadata(node_id, Box::new(|md| { md.intended_method = Some(intended_method); })).unwrap(); - let searcher_data = Data::new_with_edited_node(PROJECT_NAME,&graph,&database,node_id).unwrap(); + let searcher_data = Data::new_with_edited_node(project_qualified_name(),&graph,&database,node_id).unwrap(); assert_eq!(searcher_data.input.repr(), node.info.expression().repr()); assert!(searcher_data.fragments_added_by_picking.is_empty()); assert!(searcher_data.actions.is_loading()); @@ -1844,7 +1849,7 @@ pub mod test { // Node had up-to-date intended method. graph.set_expression(node_id,"Test.testMethod1 12").unwrap(); // We set metadata in previous section. - let searcher_data = Data::new_with_edited_node(PROJECT_NAME,&graph,&database,node_id).unwrap(); + let searcher_data = Data::new_with_edited_node(project_qualified_name(),&graph,&database,node_id).unwrap(); assert_eq!(searcher_data.input.repr(), "Test.testMethod1 12"); assert!(searcher_data.actions.is_loading()); let (initial_fragment,) = searcher_data.fragments_added_by_picking.expect_tuple(); @@ -1903,10 +1908,10 @@ pub mod test { let example = model::suggestion_database::example::Example { name : "Test Example".to_owned(), code : "[1,2,3,4,5]".to_owned(), - imports : vec!["Base.Network.Http".to_owned()], + imports : vec!["std.Base.Network.Http".to_owned()], documentation : "Lorem ipsum".to_owned() }; - let expected_code = "import Base.Network.Http\n\ + let expected_code = "import std.Base.Network.Http\n\ test_example1 = [1,2,3,4,5]\n\ntest_example2 = [1,2,3,4,5]\n\n\ main = \n 2 + 2\n here.test_example1\n here.test_example2"; let example = Rc::new(example); diff --git a/src/rust/ide/src/controller/searcher/action.rs b/src/rust/ide/src/controller/searcher/action.rs index 0970c4d25c..9d9e9048e6 100644 --- a/src/rust/ide/src/controller/searcher/action.rs +++ b/src/rust/ide/src/controller/searcher/action.rs @@ -46,7 +46,7 @@ impl Display for Action { let should_put_project_name = self_type.name == constants::PROJECTS_MAIN_MODULE && self_type.module_segments.is_empty(); let self_type_name = if should_put_project_name { - self_type.project_name.as_ref() + self_type.project_name.project.as_ref() } else { &self_type.name }; write!(f,"{}.{}",self_type_name,completion.name) } else { diff --git a/src/rust/ide/src/double_representation.rs b/src/rust/ide/src/double_representation.rs index fb4b0d6f52..012751a981 100644 --- a/src/rust/ide/src/double_representation.rs +++ b/src/rust/ide/src/double_representation.rs @@ -8,6 +8,7 @@ pub mod graph; pub mod identifier; pub mod module; pub mod node; +pub mod project; pub mod refactorings; pub mod text; pub mod tp; diff --git a/src/rust/ide/src/double_representation/module.rs b/src/rust/ide/src/double_representation/module.rs index 72edc390c1..8a87948d0b 100644 --- a/src/rust/ide/src/double_representation/module.rs +++ b/src/rust/ide/src/double_representation/module.rs @@ -10,6 +10,7 @@ use crate::double_representation::identifier; use crate::double_representation::identifier::Identifier; use crate::double_representation::identifier::LocatedName; use crate::double_representation::identifier::ReferentName; +use crate::double_representation::project; use crate::double_representation::tp; use ast::crumbs::ChildAst; @@ -147,15 +148,15 @@ impl Id { #[serde(into="String")] #[serde(try_from="String")] pub struct QualifiedName { - /// The first segment in the full qualified name. - pub project_name : ReferentName, + /// The first segment in the full qualified name. May be a project name or a keyword like + pub project_name : project::QualifiedName, /// The module id: all segments in full qualified name but the first (which is a project name). pub id : Id } impl QualifiedName { /// Build a module's qualified name from the project name and module's path. - pub fn new(project_name:ReferentName, id:Id) -> QualifiedName { + pub fn new(project_name:project::QualifiedName, id:Id) -> QualifiedName { QualifiedName {project_name,id} } @@ -163,7 +164,7 @@ impl QualifiedName { /// /// It is special, as its name consists only from the project name, unlike other modules' /// qualified names. - pub fn new_main(project_name:ReferentName) -> QualifiedName { + pub fn new_main(project_name:project::QualifiedName) -> QualifiedName { Self::new(project_name, Id::new(std::iter::empty())) } @@ -174,9 +175,9 @@ impl QualifiedName { use ast::opr::predefined::ACCESS; let text = text.as_ref(); - let segments = text.split(ACCESS); - if let [ref project_name,ref id_segments @ ..] = *segments.collect_vec().as_slice() { - let project_name = ReferentName::new(*project_name)?; + let segments = text.split(ACCESS).collect_vec(); + if let [namespace_name,project_name,id_segments @ ..] = segments.as_slice() { + let project_name = project::QualifiedName::from_segments(*namespace_name,*project_name)?; let id = Id::try_new(id_segments)?; Ok(Self::new(project_name,id)) } else { @@ -187,13 +188,14 @@ impl QualifiedName { /// Build a module's full qualified name from its name segments and the project name. /// /// ``` - /// use ide::model::module::QualifiedName; + /// # use enso_prelude::*; + /// # use ide::model::module::QualifiedName; /// - /// let name = QualifiedName::from_segments("Project",&["Main"]).unwrap(); - /// assert_eq!(name.to_string(), "Project.Main"); + /// let name = QualifiedName::from_segments("local.Project".try_into().unwrap(),&["Main"]).unwrap(); + /// assert_eq!(name.to_string(), "local.Project.Main"); /// ``` pub fn from_segments - (project_name:impl Into, module_segments:impl IntoIterator>) + (project_name:project::QualifiedName, module_segments:impl IntoIterator>) -> FallibleResult { let project_name = std::iter::once(project_name.into()); let module_segments = module_segments.into_iter(); @@ -214,20 +216,24 @@ impl QualifiedName { pub fn from_all_segments (segments:impl IntoIterator>) -> FallibleResult { let mut iter = segments.into_iter(); + let namespace = iter.next().map(|name| name.as_ref().to_owned()); let project_name = iter.next().map(|name| name.as_ref().to_owned()); - let project_name = project_name.ok_or(InvalidQualifiedName::NoModuleSegment)?; - Self::from_segments(project_name,iter) + let typed_project_name = match (namespace,project_name) { + (Some(ns),Some(name)) => project::QualifiedName::from_segments(ns,name), + _ => Err(InvalidQualifiedName::NoModuleSegment.into()), + }; + Self::from_segments(typed_project_name?,iter) } /// Get the module's name. It is also the module's typename. pub fn name(&self) -> ReferentName { - if self.id.segments.is_empty() { self.project_name.clone() } + if self.id.segments.is_empty() { self.project_name.project.clone() } else { self.id.name() } } /// Get the name of project owning this module. pub fn project_name(&self) -> &ReferentName { - &self.project_name + &self.project_name.project } /// Get the module's identifier. @@ -236,8 +242,8 @@ impl QualifiedName { } /// Get all segments of the fully qualified name. - pub fn segments(&self) -> impl Iterator { - std::iter::once(&self.project_name).chain(self.id.segments.iter()) + pub fn segments(&self) -> impl Iterator { + self.project_name.segments().chain(self.id.segments.iter().map(|seg| seg.as_ref())) } /// Remove the main module segment from the qualified name. @@ -247,17 +253,17 @@ impl QualifiedName { /// /// ``` /// # use ide::model::module::QualifiedName; - /// let mut name_with_main = QualifiedName::from_text("Project.Main").unwrap(); - /// let mut name_without_main = QualifiedName::from_text("Project.Foo.Bar").unwrap(); - /// let mut main_but_not_project_main = QualifiedName::from_text("Project.Foo.Main").unwrap(); + /// let mut name_with_main = QualifiedName::from_text("ns.Proj.Main").unwrap(); + /// let mut name_without_main = QualifiedName::from_text("ns.Proj.Foo.Bar").unwrap(); + /// let mut main_but_not_project_main = QualifiedName::from_text("ns.Proj.Foo.Main").unwrap(); /// /// name_with_main .remove_main_module_segment(); /// name_without_main .remove_main_module_segment(); /// main_but_not_project_main .remove_main_module_segment(); /// - /// assert_eq!(name_with_main .to_string(), "Project"); - /// assert_eq!(name_without_main .to_string(), "Project.Foo.Bar"); - /// assert_eq!(main_but_not_project_main.to_string(), "Project.Foo.Main"); + /// assert_eq!(name_with_main .to_string(), "ns.Proj"); + /// assert_eq!(name_without_main .to_string(), "ns.Proj.Foo.Bar"); + /// assert_eq!(main_but_not_project_main.to_string(), "ns.Proj.Foo.Main"); /// ``` pub fn remove_main_module_segment(&mut self) { if self.id.segments == [PROJECTS_MAIN_MODULE] { @@ -306,9 +312,8 @@ impl From for String { impl From<&QualifiedName> for String { fn from(name:&QualifiedName) -> Self { - let project_name = std::iter::once(&name.project_name); - let segments = name.id.segments.iter(); - project_name.chain(segments).join(ast::opr::predefined::ACCESS) + let segments = name.id.segments.iter().map(|rn| rn.as_ref()); + name.project_name.segments().chain(segments).join(ast::opr::predefined::ACCESS) } } @@ -488,6 +493,8 @@ impl Info { /// Add a new import if the module is not already imported. pub fn add_module_import (&mut self, here:&QualifiedName, parser:&parser::Parser, to_add:&QualifiedName) { + let imports = self.iter_imports().collect_vec(); + DEBUG!("add_module_import: {to_add} in {imports:?}"); let is_here = to_add == here; let import = ImportInfo::from_qualified_name(&to_add); let already_imported = self.iter_imports().any(|imp| imp == import); @@ -732,14 +739,14 @@ mod tests { #[test] fn qualified_name_validation() { - assert!(QualifiedName::try_from("project.Name").is_err()); - assert!(QualifiedName::try_from("Project.name").is_err()); - assert!(QualifiedName::try_from("Project.").is_err()); + assert!(QualifiedName::try_from("namespace.project.Name").is_err()); + assert!(QualifiedName::try_from("namespace.Project.name").is_err()); + assert!(QualifiedName::try_from("namespace.").is_err()); assert!(QualifiedName::try_from(".Name").is_err()); assert!(QualifiedName::try_from(".").is_err()); assert!(QualifiedName::try_from("").is_err()); - assert!(QualifiedName::try_from("Project.Name").is_ok()); - assert!(QualifiedName::try_from("Project.Name.Sub").is_ok()); + assert!(QualifiedName::try_from("namespace.Project.Name").is_ok()); + assert!(QualifiedName::try_from("namespace.Project.Name.Sub").is_ok()); } #[wasm_bindgen_test] @@ -795,7 +802,7 @@ mod tests { #[wasm_bindgen_test] fn implicit_method_resolution() { let parser = parser::Parser::new_or_panic(); - let module_name = QualifiedName::from_segments("ProjectName",&["Main"]).unwrap(); + let module_name = QualifiedName::from_all_segments(&["local","ProjectName","Main"]).unwrap(); let expect_find = |method:&MethodPointer, code,expected:&definition::Id| { let module = parser.parse_module(code,default()).unwrap(); let result = lookup_method(&module_name,&module,method); @@ -817,8 +824,8 @@ mod tests { // === Lookup the Main (local module type) extension method === let ptr = MethodPointer { - defined_on_type : "ProjectName.Main".into(), - module : "ProjectName.Main".into(), + defined_on_type : "local.ProjectName.Main".into(), + module : "local.ProjectName.Main".into(), name : "foo".into(), }; @@ -840,8 +847,8 @@ mod tests { // === Lookup the Int (non-local type) extension method === let ptr = MethodPointer { - defined_on_type : "Base.Main.Number".into(), - module : "ProjectName.Main".into(), + defined_on_type : "std.Base.Main.Number".into(), + module : "local.ProjectName.Main".into(), name : "foo".into(), }; diff --git a/src/rust/ide/src/double_representation/project.rs b/src/rust/ide/src/double_representation/project.rs new file mode 100644 index 0000000000..e4545b0799 --- /dev/null +++ b/src/rust/ide/src/double_representation/project.rs @@ -0,0 +1,153 @@ +//! A set of structures describing Project for double representation. + +use crate::prelude::*; + +use crate::double_representation::identifier::ReferentName; + +use serde::Deserialize; +use serde::Serialize; + + + +// ============== +// === Errors === +// ============== + +#[allow(missing_docs)] +#[derive(Clone,Debug,Fail)] +pub enum InvalidQualifiedName { + #[fail(display="The qualified name is empty.")] + EmptyName{source:String}, + #[fail(display="No namespace in project qualified name.")] + NoNamespace{source:String}, + #[fail(display="Invalid namespace in project qualified name.")] + InvalidNamespace{source:String}, + #[fail(display="Too many segments in project qualified name.")] + TooManySegments{source:String}, +} + + +// ===================== +// === QualifiedName === +// ===================== + +/// The project qualified name has a form of `.`. It serves as +/// a prefix for qualified names of other entities (modules, types, etc.). +#[derive(Clone,Debug,Deserialize,Eq,Hash,Ord,PartialEq,PartialOrd,Serialize)] +#[serde(into="String")] +#[serde(try_from="String")] +pub struct QualifiedName { + /// The name of project's namespace. + pub namespace:String, + /// The actual project name. + pub project:ReferentName, +} + +impl QualifiedName { + /// Create qualified name from typed components. + pub fn new(namespace:String, project:ReferentName) -> Self { + Self{namespace,project} + } + + /// Create qualified name from string segments. May fail if the segments are invalid. + pub fn from_segments + (namespace:impl Into, project:impl Into) -> FallibleResult { + let namespace = namespace.into(); + if namespace.is_empty() { + let source = format!("{}.{}",namespace,project.into()); + Err(InvalidQualifiedName::InvalidNamespace {source}.into()) + } else { + let project = ReferentName::new(project.into())?; + Ok(Self {namespace,project}) + } + } + + /// Create from a text representation. May fail if the text is not valid Qualified. + pub fn from_text(text:impl Into) -> FallibleResult { + let source:String = text.into(); + let all_segments = source.split('.').collect_vec(); + match all_segments.as_slice() { + [namespace,project] => Self::from_segments(*namespace,*project), + [] => Err(InvalidQualifiedName::EmptyName {source}.into()), + [_] => Err(InvalidQualifiedName::NoNamespace {source}.into()), + _ => Err(InvalidQualifiedName::TooManySegments {source}.into()), + } + } + + /// The iterator over name's segments: the namespace and project name. + pub fn segments(&self) -> impl Iterator { + std::iter::once(self.namespace.as_ref()).chain(std::iter::once(self.project.as_ref())) + } +} + + +// === Conversions === + +impl TryFrom<&str> for QualifiedName { + type Error = failure::Error; + + fn try_from(text:&str) -> Result { + Self::from_text(text) + } +} + +impl TryFrom for QualifiedName { + type Error = failure::Error; + + fn try_from(text:String) -> Result { + Self::from_text(text) + } +} + +impl From for String { + fn from(name:QualifiedName) -> Self { + String::from(&name) + } +} + +impl From<&QualifiedName> for String { + fn from(name:&QualifiedName) -> Self { + name.to_string() + } +} + +impl Display for QualifiedName { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f,"{}.{}",self.namespace,self.project) + } +} + + + +// ============= +// === Tests === +// ============= + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn qualified_name_from_string() { + fn valid_case(text:&str, namespace:&str, project:&str) { + let qualified_name = QualifiedName::from_text(text).unwrap(); + assert_eq!(qualified_name.namespace, namespace); + assert_eq!(qualified_name.project , project ); + } + + fn invalid_case(text:&str) { + assert!(QualifiedName::from_text(text).is_err()); + } + + valid_case("ns.Project", "ns", "Project"); + valid_case("n.Proj" , "n" , "Proj" ); + + invalid_case("namespace"); + invalid_case("Project"); + invalid_case("namespace.project"); + invalid_case("namespace.Project.Main"); + invalid_case(".Project"); + invalid_case("namespace."); + invalid_case("."); + } +} diff --git a/src/rust/ide/src/double_representation/tp.rs b/src/rust/ide/src/double_representation/tp.rs index 897b30ca96..a4a5907bf3 100644 --- a/src/rust/ide/src/double_representation/tp.rs +++ b/src/rust/ide/src/double_representation/tp.rs @@ -4,6 +4,7 @@ use crate::prelude::*; use crate::double_representation::identifier::ReferentName; use crate::double_representation::module; +use crate::double_representation::project; use serde::Deserialize; use serde::Serialize; @@ -19,6 +20,8 @@ use serde::Serialize; pub enum InvalidQualifiedName { #[fail(display="The qualified name is empty.")] EmptyName{source:String}, + #[fail(display="The qualified name has no namespace.")] + NoNamespaceName{source:String}, #[fail(display="No module in type qualified name.")] NoModuleName{source:String}, } @@ -42,7 +45,7 @@ pub enum InvalidQualifiedName { #[serde(try_from="String")] pub struct QualifiedName { /// The first segment in the full qualified name. - pub project_name : ReferentName, + pub project_name : project::QualifiedName, /// All segments between the project name (the first) and the entity name (the last). pub module_segments : Vec, /// The last segment in the full qualified name. @@ -69,11 +72,13 @@ impl QualifiedName { /// Create from a text representation. May fail if the text is not valid Qualified name of any /// type. pub fn from_text(text:impl Str) -> FallibleResult { + use InvalidQualifiedName::*; let text:String = text.into(); let mut all_segments = text.split('.'); - let project_name_str = all_segments.next().ok_or_else(|| InvalidQualifiedName::EmptyName{source:text.clone()})?; - let project_name = ReferentName::new(project_name_str)?; - let name_str = all_segments.next_back().ok_or_else(||InvalidQualifiedName::NoModuleName{source:text.clone()})?; + let namespace = all_segments.next().ok_or_else(|| EmptyName{source:text.clone()})?; + let project_name = all_segments.next().ok_or_else(|| NoNamespaceName{source:text.clone()})?; + let project_name = project::QualifiedName::from_segments(namespace,project_name)?; + let name_str = all_segments.next_back().ok_or_else(||NoModuleName{source:text.clone()})?; let name = name_str.to_owned(); let mut module_segments = Vec::new(); for segment in all_segments { @@ -121,7 +126,7 @@ impl From for String { impl From<&QualifiedName> for String { fn from(name:&QualifiedName) -> Self { - let project_name = std::iter::once(name.project_name.as_ref()); + let project_name = name.project_name.segments(); let segments = name.module_segments.iter().map(AsRef::::as_ref); let name = std::iter::once(name.name.as_ref()); project_name.chain(segments).chain(name).join(".") @@ -143,13 +148,15 @@ impl Display for QualifiedName { #[cfg(test)] mod test { - // use super::*; + use super::*; use crate::double_representation::tp::QualifiedName; + #[test] fn qualified_name_from_string() { - let valid_case = |text:&str, project_name:&str, segments:Vec<&str>, name:&str| { + let valid_case = |text:&str, ns_name:&str, project_name:&str, segments:Vec<&str>, name:&str| { + let project_name = project::QualifiedName::from_segments(ns_name,project_name).unwrap(); let result = QualifiedName::from_text(text).unwrap(); assert_eq!(result.project_name , project_name); assert_eq!(result.module_segments , segments ); @@ -160,12 +167,13 @@ mod test { assert!(QualifiedName::from_text(text).is_err()); }; - valid_case("Project.Main.Test.foo" , "Project", vec!["Main", "Test"], "foo"); - valid_case("Project.Main.Bar" , "Project", vec!["Main"] , "Bar"); - valid_case("Project.Baz" , "Project", vec![] , "Baz"); + valid_case("local.Project.Main.Test.foo" , "local" , "Project", vec!["Main", "Test"], "foo"); + valid_case("local.Project.Main.Bar" , "local" , "Project", vec!["Main"] , "Bar"); + valid_case("local.Project.Baz" , "local" , "Project", vec![] , "Baz"); - invalid_case("Project"); - invalid_case("Project.module.foo"); + invalid_case("local"); + invalid_case("local.Project"); + invalid_case("local.Project.module.foo"); invalid_case("..."); invalid_case(""); } diff --git a/src/rust/ide/src/ide/initializer.rs b/src/rust/ide/src/ide/initializer.rs index 45d6283140..aeb8e9d620 100644 --- a/src/rust/ide/src/ide/initializer.rs +++ b/src/rust/ide/src/ide/initializer.rs @@ -116,15 +116,16 @@ impl Initializer { (project_manager,project_name).await?; Ok(Rc::new(controller)) } - LanguageServer {json_endpoint,binary_endpoint} => { + LanguageServer {json_endpoint,binary_endpoint,namespace} => { let json_endpoint = json_endpoint.clone(); let binary_endpoint = binary_endpoint.clone(); + let namespace = namespace.clone(); let project_name = self.config.project_name.clone(); // TODO[ao]: we should think how to handle engine's versions in cloud. // https://github.com/enso-org/ide/issues/1195 let version = semver::Version::parse(ENGINE_VERSION_FOR_NEW_PROJECTS)?; let controller = controller::ide::Plain::from_ls_endpoints - (project_name,version,json_endpoint,binary_endpoint).await?; + (namespace,project_name,version,json_endpoint,binary_endpoint).await?; Ok(Rc::new(controller)) } } @@ -179,9 +180,7 @@ impl WithProjectManager { let project_id = self.get_project_or_create_new().await?; let logger = &self.logger; let project_manager = self.project_manager; - let project_name = self.project_name; - model::project::Synchronized::new_opened(logger,project_manager,project_id,project_name) - .await + model::project::Synchronized::new_opened(logger,project_manager,project_id).await } /// Creates a new project and returns its id, so the newly connected project can be opened. @@ -249,9 +248,11 @@ mod test { let mock_client = project_manager::MockClient::default(); let project_name = ProjectName::new("TestProject"); let project = project_manager::ProjectMetadata { - name : project_name.clone(), - id : uuid::Uuid::new_v4(), - last_opened : default(), + name : project_name.clone(), + id : uuid::Uuid::new_v4(), + last_opened : default(), + engine_version : "127.0.01".to_owned(), + namespace : "local".to_owned(), }; let expected_id = project.id; let projects = vec![project]; diff --git a/src/rust/ide/src/model/execution_context/plain.rs b/src/rust/ide/src/model/execution_context/plain.rs index 35c396caa6..d6b6242ba2 100644 --- a/src/rust/ide/src/model/execution_context/plain.rs +++ b/src/rust/ide/src/model/execution_context/plain.rs @@ -215,6 +215,7 @@ pub mod test { use super::*; use crate::double_representation::definition::DefinitionName; + use crate::double_representation::project; #[derive(Clone,Derivative)] #[derivative(Debug)] @@ -222,6 +223,7 @@ pub mod test { pub module_path : model::module::Path, pub context_id : model::execution_context::Id, pub root_definition : DefinitionName, + pub namespace : String, pub project_name : String, } @@ -237,12 +239,14 @@ pub mod test { context_id : model::execution_context::Id::new_v4(), module_path : crate::test::mock::data::module_path(), root_definition : crate::test::mock::data::definition_name(), + namespace : crate::test::mock::data::NAMESPACE_NAME.to_owned(), project_name : crate::test::mock::data::PROJECT_NAME.to_owned(), } } pub fn module_qualified_name(&self) -> model::module::QualifiedName { - self.module_path.qualified_module_name(&self.project_name) + let project_name = project::QualifiedName::from_segments(&self.namespace,&self.project_name); + self.module_path.qualified_module_name(project_name.unwrap()) } pub fn definition_id(&self) -> model::execution_context::DefinitionId { diff --git a/src/rust/ide/src/model/module.rs b/src/rust/ide/src/model/module.rs index bfe4ce9329..00f5c3f18a 100644 --- a/src/rust/ide/src/model/module.rs +++ b/src/rust/ide/src/model/module.rs @@ -14,6 +14,7 @@ use crate::constants::SOURCE_DIRECTORY; use crate::controller::FilePath; use crate::double_representation::identifier::ReferentName; use crate::double_representation::definition::DefinitionInfo; +use crate::double_representation::project; use data::text::TextChange; use data::text::TextLocation; @@ -192,7 +193,8 @@ impl Path { /// Obtain a pointer to a method of the module (i.e. extending the module's atom). /// /// Note that this cannot be used for a method extending other atom than this module. - pub fn method_pointer(&self, project_name:impl Str, method_name:impl Str) -> MethodPointer { + pub fn method_pointer + (&self, project_name:project::QualifiedName, method_name:impl Str) -> MethodPointer { let module = String::from(self.qualified_module_name(project_name)); let defined_on_type = module.clone(); let name = method_name.into(); @@ -208,10 +210,10 @@ impl Path { /// /// let path = Path::from_name_segments(default(),&["Main"]).unwrap(); /// assert_eq!(path.to_string(),"//00000000-0000-0000-0000-000000000000/src/Main.enso"); - /// let name = path.qualified_module_name("Project"); - /// assert_eq!(name.to_string(),"Project.Main"); + /// let name = path.qualified_module_name("local.Project".try_into().unwrap()); + /// assert_eq!(name.to_string(),"local.Project.Main"); /// ``` - pub fn qualified_module_name(&self, project_name:impl Str) -> QualifiedName { + pub fn qualified_module_name(&self, project_name:project::QualifiedName) -> QualifiedName { let non_src_directories = &self.file_path.segments[1..self.file_path.segments.len()-1]; let non_src_directories = non_src_directories.iter().map(|dirname| dirname.as_str()); let module_name = self.module_name(); @@ -516,7 +518,7 @@ pub trait API:Debug+model::undo_redo::Aware { /// The module is assumed to be in the file identified by the `method.file` (for the purpose of /// desugaring implicit extensions methods for modules). fn lookup_method - (&self, project_name:&str, method:&MethodPointer) + (&self, project_name:project::QualifiedName, method:&MethodPointer) -> FallibleResult { let name = self.path().qualified_module_name(project_name); let ast = self.ast(); @@ -613,12 +615,14 @@ pub mod test { #[test] fn module_qualified_name() { + let namespace = "n"; let project_name = "P"; + let project_name = project::QualifiedName::from_segments(namespace,project_name).unwrap(); let root_id = default(); let file_path = FilePath::new(root_id, &["src", "Foo", "Bar.enso"]); let module_path = Path::from_file_path(file_path).unwrap(); let qualified = module_path.qualified_module_name(project_name); - assert_eq!(qualified.to_string(), "P.Foo.Bar"); + assert_eq!(qualified.to_string(), "n.P.Foo.Bar"); } #[wasm_bindgen_test] diff --git a/src/rust/ide/src/model/project.rs b/src/rust/ide/src/model/project.rs index ced5e50231..98bbaf544e 100644 --- a/src/rust/ide/src/model/project.rs +++ b/src/rust/ide/src/model/project.rs @@ -9,6 +9,9 @@ pub mod synchronized; use crate::prelude::*; +use crate::double_representation::project::QualifiedName; +use crate::double_representation::identifier::ReferentName; + use enso_protocol::binary; use enso_protocol::language_server; use flo_stream::Subscriber; @@ -27,7 +30,10 @@ use uuid::Uuid; pub trait API:Debug { /// Project's name // TODO [mwu] This should return Rc. - fn name(&self) -> ImString; + fn name(&self) -> ReferentName; + + /// Project's qualified name + fn qualified_name(&self) -> QualifiedName; /// Get Language Server JSON-RPC Connection for this project. fn json_rpc(&self) -> Rc; @@ -36,7 +42,7 @@ pub trait API:Debug { fn binary_rpc(&self) -> Rc; /// Get the engine's version of the project. - fn engine_version(&self) -> &semver::Version; + fn engine_version(&self) -> semver::Version; /// Get the instance of parser that is set up for this project. fn parser(&self) -> Parser; @@ -71,7 +77,7 @@ pub trait API:Debug { /// Generates full module's qualified name that includes the leading project name segment. fn qualified_module_name (&self, path:&model::module::Path) -> crate::model::module::QualifiedName { - path.qualified_module_name(self.name().deref()) + path.qualified_module_name(self.qualified_name()) } /// Get qualified name of the project's `Main` module. @@ -79,7 +85,7 @@ pub trait API:Debug { /// This module is special, as it needs to be referred by the project name itself. fn main_module(&self) -> FallibleResult { let main = std::iter::once(controller::project::INITIAL_MODULE_NAME); - model::module::QualifiedName::from_segments(self.name(),main) + model::module::QualifiedName::from_segments(self.qualified_name(),main) // TODO [mwu] The code below likely should be preferred but does not work // because language server does not support using project name @@ -194,7 +200,14 @@ pub mod test { /// Sets up name expectation on the mock project, returning a given name. pub fn expect_name(project:&mut MockAPI, name:impl Into) { - let name = ImString::new(name); - project.expect_name().returning_st(move || name.clone_ref()); + let name = ReferentName::new(name.into()).unwrap(); + project.expect_name().returning_st(move || name.clone()); + } + + /// Sets up name expectation on the mock project, returning a given name. + pub fn expect_qualified_name + (project:&mut MockAPI, name:&QualifiedName) { + let name = name.clone(); + project.expect_qualified_name().returning_st(move || name.clone()); } } diff --git a/src/rust/ide/src/model/project/synchronized.rs b/src/rust/ide/src/model/project/synchronized.rs index 289295a588..a18a538776 100644 --- a/src/rust/ide/src/model/project/synchronized.rs +++ b/src/rust/ide/src/model/project/synchronized.rs @@ -2,6 +2,8 @@ use crate::prelude::*; +use crate::double_representation::identifier::ReferentName; +use crate::double_representation::project::QualifiedName; use crate::model::execution_context::VisualizationUpdateData; use crate::model::execution_context; use crate::model::module; @@ -108,9 +110,9 @@ pub struct UnsupportedEngineVersion { } impl UnsupportedEngineVersion { - fn error_wrapper - (project_name:String, engine_version:semver::Version) - -> impl Fn(failure::Error) -> failure::Error { + fn error_wrapper(properties:&Properties) -> impl Fn(failure::Error) -> failure::Error { + let engine_version = properties.engine_version.clone(); + let project_name = properties.name.project.as_str().to_owned(); move |root_cause| { let requirements = semver::VersionReq::parse(controller::project::ENGINE_VERSION_SUPPORTED); match requirements { @@ -143,7 +145,7 @@ impl Display for UnsupportedEngineVersion { pub struct Properties { /// ID of the project, as used by the Project Manager service. pub id : Uuid, - pub name : CloneRefCell, + pub name : QualifiedName, pub engine_version : semver::Version, } @@ -155,7 +157,7 @@ pub struct Properties { #[derive(Derivative)] #[derivative(Debug)] pub struct Project { - pub properties : Rc, + pub properties : Rc>, #[derivative(Debug = "ignore")] pub project_manager : Option>, pub language_server_rpc : Rc, @@ -177,13 +179,11 @@ impl Project { , project_manager : Option> , language_server_rpc : Rc , language_server_bin : Rc - , engine_version : semver::Version - , id : Uuid - , name : impl Str + , properties : Properties ) -> FallibleResult { - let wrap = UnsupportedEngineVersion::error_wrapper(name.as_ref().to_owned(),engine_version.clone()); + let wrap = UnsupportedEngineVersion::error_wrapper(&properties); let logger = Logger::sub(parent,"Project Controller"); - info!(logger,"Creating a model of project {name.as_ref()}"); + info!(logger,"Creating a model of project {properties.name}"); let binary_protocol_events = language_server_bin.event_stream(); let json_rpc_events = language_server_rpc.events(); let embedded_visualizations = default(); @@ -191,15 +191,13 @@ impl Project { let module_registry = default(); let execution_contexts = default(); let visualization = controller::Visualization::new(language_server,embedded_visualizations); - let name = CloneRefCell::new(ImString::new(name.into())); let parser = Parser::new_or_panic(); let language_server = &*language_server_rpc; let suggestion_db = SuggestionDatabase::create_synchronized(language_server); let suggestion_db = Rc::new(suggestion_db.await.map_err(&wrap)?); let notifications = notification::Publisher::default(); let urm = Rc::new(model::undo_redo::Manager::new(&logger)); - let engine_version = engine_version.clone(); - let properties = Rc::new(Properties {id,name,engine_version}); + let properties = Rc::new(RefCell::new(properties)); let ret = Project {properties,project_manager,language_server_rpc,language_server_bin,module_registry @@ -221,11 +219,9 @@ impl Project { , project_manager : Option> , language_server_rpc : String , language_server_bin : String - , engine_version : semver::Version - , id : Uuid - , name : impl Str + , properties : Properties ) -> FallibleResult { - let wrap = UnsupportedEngineVersion::error_wrapper(name.as_ref().to_owned(),engine_version.clone()); + let wrap = UnsupportedEngineVersion::error_wrapper(&properties); let client_id = Uuid::new_v4(); let json_ws = WebSocket::new_opened(&parent,&language_server_rpc).await?; let binary_ws = WebSocket::new_opened(&parent,&language_server_bin).await?; @@ -240,7 +236,7 @@ impl Project { let language_server_rpc = Rc::new(connection_json); let language_server_bin = Rc::new(connection_binary); let model = Self::new(parent,project_manager,language_server_rpc - ,language_server_bin,engine_version,id,name).await?; + ,language_server_bin,properties).await?; Ok(Rc::new(model)) } @@ -250,15 +246,20 @@ impl Project { ( parent : &Logger , project_manager : Rc , id : Uuid - , name : impl Str ) -> FallibleResult { let action = MissingComponentAction::Install; let opened = project_manager.open_project(&id,&action).await?; - let version = semver::Version::parse(&opened.engine_version)?; + let namespace = opened.project_namespace; + let name = opened.project_name; let project_manager = Some(project_manager); let json_endpoint = opened.language_server_json_address.to_string(); let binary_endpoint = opened.language_server_binary_address.to_string(); - Self::new_connected(parent,project_manager,json_endpoint,binary_endpoint,version,id,name).await + let properties = Properties { + id, + name : QualifiedName::from_segments(namespace,name)?, + engine_version : semver::Version::parse(&opened.engine_version)?, + }; + Self::new_connected(parent,project_manager,json_endpoint,binary_endpoint,properties).await } /// Returns a handling function capable of processing updates from the binary protocol. @@ -385,8 +386,12 @@ impl Project { } impl model::project::API for Project { - fn name(&self) -> ImString { - self.properties.name.get() + fn name(&self) -> ReferentName { + self.properties.borrow().name.project.clone() + } + + fn qualified_name(&self) -> QualifiedName { + self.properties.borrow().name.clone() } fn json_rpc(&self) -> Rc { @@ -397,7 +402,9 @@ impl model::project::API for Project { self.language_server_bin.clone_ref() } - fn engine_version(&self) -> &semver::Version { &self.properties.engine_version } + fn engine_version(&self) -> semver::Version { + self.properties.borrow().engine_version.clone() + } fn parser(&self) -> Parser { self.parser.clone_ref() @@ -435,9 +442,11 @@ impl model::project::API for Project { fn rename_project(&self, name:String) -> BoxFuture { async move { + let referent_name = name.as_str().try_into()?; let project_manager = self.project_manager.as_ref().ok_or(ProjectManagerUnavailable)?; - project_manager.rename_project(&self.properties.id, &name).await?; - self.properties.name.set(name.into()); + let project_id = self.properties.borrow().id; + project_manager.rename_project(&project_id,&name).await?; + self.properties.borrow_mut().name.project = referent_name; Ok(()) }.boxed_local() } @@ -465,7 +474,6 @@ impl model::project::API for Project { mod test { use super::*; - use crate::constants::DEFAULT_PROJECT_NAME; use crate::executor::test_utils::TestWithLocalPoolExecutor; use enso_protocol::types::Sha3_224; @@ -516,10 +524,13 @@ mod test { let binary_connection = Rc::new(binary::Connection::new_mock(binary_client)); let project_manager = Rc::new(project_manager); let logger = Logger::new("Fixture"); - let id = Uuid::new_v4(); - let engine_version = semver::Version::new(0,2,1); + let properties = Properties { + id : Uuid::new_v4(), + name : crate::test::mock::data::project_qualified_name(), + engine_version : semver::Version::new(0,2,1), + }; let project_fut = Project::new(logger,Some(project_manager), - json_connection,binary_connection,engine_version,id,DEFAULT_PROJECT_NAME).boxed_local(); + json_connection,binary_connection,properties).boxed_local(); let project = test.expect_completion(project_fut).unwrap(); Fixture {test,project,binary_events_sender,json_events_sender} } diff --git a/src/rust/ide/src/model/suggestion_database/entry.rs b/src/rust/ide/src/model/suggestion_database/entry.rs index 9528f3a8b5..1325edb4c7 100644 --- a/src/rust/ide/src/model/suggestion_database/entry.rs +++ b/src/rust/ide/src/model/suggestion_database/entry.rs @@ -150,7 +150,7 @@ impl Entry { None } } else { - // No this expression unless we have been requested to add one. + // No "this" expression unless we have been requested to add one. None }; @@ -439,8 +439,8 @@ mod test { #[test] fn code_from_entry() { - let main_module = module::QualifiedName::from_text("Project.Main").unwrap(); - let another_module = module::QualifiedName::from_text("Project.Another_Module").unwrap(); + let main_module = module::QualifiedName::from_text("local.Project.Main").unwrap(); + let another_module = module::QualifiedName::from_text("local.Project.Another_Module").unwrap(); let atom = Entry { name : "Atom".to_owned(), kind : Kind::Atom, @@ -454,7 +454,7 @@ mod test { let method = Entry { name : "method".to_string(), kind : Kind::Method, - self_type : Some("Base.Main.Number".to_string().try_into().unwrap()), + self_type : Some("std.Base.Main.Number".to_string().try_into().unwrap()), ..atom.clone() }; let module_method = Entry { diff --git a/src/rust/ide/src/test.rs b/src/rust/ide/src/test.rs index b91dfd0a54..13e209500a 100644 --- a/src/rust/ide/src/test.rs +++ b/src/rust/ide/src/test.rs @@ -4,6 +4,7 @@ use crate::prelude::*; use crate::double_representation::module; +use crate::double_representation::project; use crate::model::suggestion_database; use crate::model::undo_redo; use crate::executor::test_utils::TestWithLocalPoolExecutor; @@ -34,11 +35,12 @@ pub mod mock { use uuid::Uuid; pub const ROOT_ID : Uuid = Uuid::from_u128(100); - pub const PROJECT_NAME : &str = "MockProject"; + pub const NAMESPACE_NAME : &str = "mock_namespace"; + pub const PROJECT_NAME : &str = "Mock_Project"; pub const MODULE_NAME : &str = "Mock_Module"; pub const CODE : &str = "main = \n 2 + 2"; pub const DEFINITION_NAME : &str = "main"; - pub const TYPE_NAME : &str = "MockProject.Mock_Module.Mock_Type"; + pub const TYPE_NAME : &str = "mock_namespace.MockProject.Mock_Module.Mock_Type"; pub const MAIN_FINISH : Position = Position {line:1, character:9}; pub const CONTEXT_ID : Uuid = Uuid::from_u128(0xFE); @@ -46,8 +48,12 @@ pub mod mock { crate::model::module::Path::from_name_segments(ROOT_ID, &[MODULE_NAME]).unwrap() } + pub fn project_qualified_name() -> project::QualifiedName { + project::QualifiedName::from_segments(NAMESPACE_NAME,PROJECT_NAME).unwrap() + } + pub fn module_qualified_name() -> module::QualifiedName { - module_path().qualified_module_name(PROJECT_NAME) + module_path().qualified_module_name(project_qualified_name()) } pub fn definition_name() -> crate::double_representation::definition::DefinitionName { @@ -89,10 +95,11 @@ pub mod mock { } pub fn suggestion_entry_foo() -> suggestion_database::Entry { + let project_name = project::QualifiedName::from_segments("std","Base").unwrap(); suggestion_database::Entry { name : "foo".to_owned(), - module : module::QualifiedName::from_segments("Std",&["Base"]).unwrap(), - self_type : Some("Std.Base".to_owned().try_into().unwrap()), + module : module::QualifiedName::from_segments(project_name,&["Main"]).unwrap(), + self_type : Some("std.Base.Main".to_owned().try_into().unwrap()), arguments : vec![foo_method_parameter(),foo_method_parameter2()], return_type : "Any".to_owned(), kind : suggestion_database::entry::Kind::Method, @@ -102,10 +109,11 @@ pub mod mock { } pub fn suggestion_entry_bar() -> suggestion_database::Entry { + let project_name = project::QualifiedName::from_segments("std","Base").unwrap(); suggestion_database::Entry { name : "bar".to_owned(), - module : module::QualifiedName::from_segments("Std",&["Other"]).unwrap(), - self_type : Some("Std.Other".to_owned().try_into().unwrap()), + module : module::QualifiedName::from_segments(project_name,&["Other"]).unwrap(), + self_type : Some("std.Base.Other".to_owned().try_into().unwrap()), arguments : vec![bar_method_parameter()], return_type : "Any".to_owned(), kind : suggestion_database::entry::Kind::Method, @@ -121,7 +129,7 @@ pub mod mock { #[derive(Clone,Debug)] pub struct Unified { pub logger : Logger, - pub project_name : String, + pub project_name : project::QualifiedName, pub module_path : model::module::Path, pub suggestions : HashMap, pub context_id : model::execution_context::Id, @@ -156,7 +164,7 @@ pub mod mock { let logger = Logger::new("UnifiedMock"); Unified { suggestions, - project_name : PROJECT_NAME.to_owned(), + project_name : project_qualified_name(), module_path : module_path(), code : CODE.to_owned(), id_map : default(), @@ -184,7 +192,7 @@ pub mod mock { } pub fn module_qualified_name(&self) -> module::QualifiedName { - self.module_path.qualified_module_name(&self.project_name) + self.module_path.qualified_module_name(self.project_name.clone()) } pub fn definition_id(&self) -> double_representation::definition::Id { @@ -205,7 +213,7 @@ pub mod mock { -> crate::controller::Graph { let parser = self.parser.clone_ref(); let method = self.method_pointer(); - let definition = module.lookup_method(&self.project_name,&method).expect("Lookup failed."); + let definition = module.lookup_method(self.project_name.clone(),&method).expect("Lookup failed."); crate::controller::Graph::new(logger,module,db,parser,definition).expect("Graph could not be created") } @@ -224,7 +232,8 @@ pub mod mock { , binary_client : binary::MockClient ) -> model::Project { let mut project = model::project::MockAPI::new(); - model::project::test::expect_name(&mut project,&self.project_name); + model::project::test::expect_name(&mut project,&self.project_name.project); + model::project::test::expect_qualified_name(&mut project,&self.project_name); model::project::test::expect_parser(&mut project,&self.parser); model::project::test::expect_module(&mut project,module); model::project::test::expect_execution_ctx(&mut project,execution_context); diff --git a/src/rust/ide/tests/language_server.rs b/src/rust/ide/tests/language_server.rs index eb513c746e..f0b19bd465 100644 --- a/src/rust/ide/tests/language_server.rs +++ b/src/rust/ide/tests/language_server.rs @@ -14,7 +14,6 @@ use ide::prelude::*; use enso_protocol::language_server::*; use enso_protocol::types::*; -use ide::double_representation::identifier::ReferentName; use ide::model::module; use ide::model::execution_context::Visualization; use ide::transport::web::WebSocket; @@ -63,12 +62,13 @@ wasm_bindgen_test_configure!(run_in_browser); //#[wasm_bindgen_test::wasm_bindgen_test(async)] #[allow(dead_code)] async fn ls_text_protocol_test() { - let _guard = ide::initializer::setup_global_executor(); - let ide = setup_ide().await; - let project = ide.current_project(); - let client = project.json_rpc(); - let root_id = project.content_root_id(); - let project_name = ReferentName::new(project.name()).unwrap(); + + let _guard = ide::initializer::setup_global_executor(); + let ide = setup_ide().await; + let project = ide.current_project(); + let client = project.json_rpc(); + let root_id = project.content_root_id(); + let project_name = project.qualified_name(); // Initialize files. let file = Path::new(root_id,&["src","Main.enso"]); @@ -333,7 +333,7 @@ async fn binary_visualization_updates_test_hlp() { let logger = Logger::new("Test"); let module_path = ide::initial_module_path(&project).unwrap(); - let method = module_path.method_pointer(project.name(),MAIN_DEFINITION_NAME); + let method = module_path.method_pointer(project.qualified_name(),MAIN_DEFINITION_NAME); let module_qualified_name = project.qualified_module_name(&module_path); let module = project.module(module_path).await.unwrap(); info!(logger,"Got module: {module:?}"); From 822ece2bad662040621d023836712945202a92fe Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Thu, 1 Jul 2021 09:40:01 +0200 Subject: [PATCH 02/25] WIP --- .../src/language_server/types.rs | 19 ++++-- src/rust/ide/src/controller/graph.rs | 2 +- src/rust/ide/src/controller/upload.rs | 4 +- src/rust/ide/src/ide.rs | 2 +- src/rust/ide/src/model/project.rs | 5 +- .../ide/src/model/project/synchronized.rs | 64 ++++++++++++++++++- src/rust/ide/tests/language_server.rs | 3 +- 7 files changed, 85 insertions(+), 14 deletions(-) diff --git a/src/rust/ide/lib/enso-protocol/src/language_server/types.rs b/src/rust/ide/lib/enso-protocol/src/language_server/types.rs index 8d60030a7b..7344ee3587 100644 --- a/src/rust/ide/lib/enso-protocol/src/language_server/types.rs +++ b/src/rust/ide/lib/enso-protocol/src/language_server/types.rs @@ -109,8 +109,7 @@ impl Path { // ==================== /// Notification generated by the Language Server. -#[derive(Clone,Debug,PartialEq)] -#[derive(Serialize,Deserialize)] +#[derive(Clone,Debug,Deserialize,PartialEq,Serialize)] #[serde(tag="method", content="params")] pub enum Notification { /// Filesystem event occurred for a watched path. @@ -139,6 +138,16 @@ pub enum Notification { /// Sent from server to the client to inform abouth the change in the suggestions database. #[serde(rename = "search/suggestionsDatabaseUpdates")] SuggestionDatabaseUpdates(SuggestionDatabaseUpdatesEvent), + + /// Sent from server to the client to inform that a content root has been added. + #[allow(missing_docs)] + #[serde(rename = "file/rootAdded")] + ContentRootAdded {root:ContentRoot} , + + /// Sent from server to the client to inform that a content root has been removed. + #[allow(missing_docs)] + #[serde(rename = "file/rootRemoved")] + ContentRootRemoved {id:Uuid}, } /// Sent from the server to the client to inform about a failure during execution of an execution @@ -264,9 +273,11 @@ pub struct StackTraceElement { -// ================= +// ================================= +// === File System Notifications === +// ================================= + // === FileEvent === -// ================= /// The `file/event` notification parameters. #[derive(Clone,Debug,PartialEq)] diff --git a/src/rust/ide/src/controller/graph.rs b/src/rust/ide/src/controller/graph.rs index 4bb18a4ae4..1189e172b4 100644 --- a/src/rust/ide/src/controller/graph.rs +++ b/src/rust/ide/src/controller/graph.rs @@ -481,7 +481,7 @@ impl Handle { (parent:impl AnyLogger, project:&model::Project, method:&language_server::MethodPointer) -> FallibleResult { let method = method.clone(); - let root_id = project.content_root_id(); + let root_id = project.project_content_root_id(); let module_path = model::module::Path::from_method(root_id,&method)?; let module = project.module(module_path).await?; let definition = module.lookup_method(project.qualified_name(),&method)?; diff --git a/src/rust/ide/src/controller/upload.rs b/src/rust/ide/src/controller/upload.rs index 4aa9a24d96..1bb2ce4de8 100644 --- a/src/rust/ide/src/controller/upload.rs +++ b/src/rust/ide/src/controller/upload.rs @@ -283,7 +283,7 @@ impl NodeFromDroppedFileHandler { if !self.data_directory_exists().await? { let to_create = FileSystemObject::Directory { name : DATA_DIR_NAME.to_owned(), - path : Path::new_root(self.project.content_root_id()) + path : Path::new_root(self.project.project_content_root_id()) }; self.project.json_rpc().create_file(&to_create).await? } @@ -311,7 +311,7 @@ impl NodeFromDroppedFileHandler { } fn data_path(&self) -> Path { - Path::new(self.project.content_root_id(),&[DATA_DIR_NAME]) + Path::new(self.project.project_content_root_id(), &[DATA_DIR_NAME]) } } diff --git a/src/rust/ide/src/ide.rs b/src/rust/ide/src/ide.rs index 9538f106f1..2dd3583b7d 100644 --- a/src/rust/ide/src/ide.rs +++ b/src/rust/ide/src/ide.rs @@ -88,5 +88,5 @@ impl Ide { /// The Path of the module initially opened after opening project in IDE. pub fn initial_module_path(project:&model::Project) -> FallibleResult { - model::module::Path::from_name_segments(project.content_root_id(),&[INITIAL_MODULE_NAME]) + model::module::Path::from_name_segments(project.project_content_root_id(), &[INITIAL_MODULE_NAME]) } diff --git a/src/rust/ide/src/model/project.rs b/src/rust/ide/src/model/project.rs index 98bbaf544e..dc8fbe15e1 100644 --- a/src/rust/ide/src/model/project.rs +++ b/src/rust/ide/src/model/project.rs @@ -14,6 +14,7 @@ use crate::double_representation::identifier::ReferentName; use enso_protocol::binary; use enso_protocol::language_server; +use enso_protocol::language_server::ContentRoot; use flo_stream::Subscriber; use mockall::automock; use parser::Parser; @@ -53,6 +54,8 @@ pub trait API:Debug { /// Get the suggestions database. fn suggestion_db(&self) -> Rc; + fn content_roots(&self) -> Vec>; + /// Returns a model of module opened from file. #[allow(clippy::needless_lifetimes)] // Note: Needless lifetimes fn module<'a> @@ -70,7 +73,7 @@ pub trait API:Debug { fn rename_project<'a>(&'a self, name:String) -> BoxFuture<'a,FallibleResult<()>>; /// Returns the primary content root id for this project. - fn content_root_id(&self) -> Uuid { + fn project_content_root_id(&self) -> Uuid { self.json_rpc().project_root().id } diff --git a/src/rust/ide/src/model/project/synchronized.rs b/src/rust/ide/src/model/project/synchronized.rs index a18a538776..62bda6dd80 100644 --- a/src/rust/ide/src/model/project/synchronized.rs +++ b/src/rust/ide/src/model/project/synchronized.rs @@ -15,7 +15,7 @@ use crate::transport::web::WebSocket; use enso_protocol::binary; use enso_protocol::binary::message::VisualisationContext; use enso_protocol::language_server; -use enso_protocol::language_server::CapabilityRegistration; +use enso_protocol::language_server::{CapabilityRegistration, ContentRoot}; use enso_protocol::language_server::MethodPointer; use enso_protocol::project_manager; use enso_protocol::project_manager::MissingComponentAction; @@ -90,6 +90,45 @@ impl ExecutionContextsRegistry { +// ==================== +// === ContentRoots === +// ==================== + +#[derive(Clone,Debug)] +pub struct ContentRoots { + logger : Logger, + roots : RefCell>> +} + +impl ContentRoots { + pub fn new_from_connection + (parent:impl AnyLogger, connection:&language_server::Connection) -> Self { + let logger = Logger::sub(parent,"ContentRoots"); + let roots_vec = connection.content_roots().map(|r| (r.id,Rc::new(r.clone()))).collect(); + let roots = RefCell::new(roots_vec); + Self{logger,roots} + } + + pub fn all_content_roots(&self) -> Vec> { + self.roots.borrow().values().cloned().collect() + } + + pub fn add_content_root(&self, content_root:ContentRoot) { + let content_root = Rc::new(content_root); + if let Some(existing) = self.roots.borrow_mut().insert(content_root.id,content_root) { + warning!(self.logger,"Adding content root: there is already content root with given \ + id: {existing:?}"); + } + } + + pub fn remove_content_root(&self, id:Uuid) { + if self.roots.borrow_mut().remove(&id).is_none() { + warning!(self.logger,"Removing content root: no content root with given id: {id}"); + } + } +} + + // ============= // === Model === // ============= @@ -166,6 +205,7 @@ pub struct Project { pub execution_contexts : Rc, pub visualization : controller::Visualization, pub suggestion_db : Rc, + pub content_roots : Rc, pub parser : Parser, pub logger : Logger, pub notifications : notification::Publisher, @@ -195,13 +235,16 @@ impl Project { let language_server = &*language_server_rpc; let suggestion_db = SuggestionDatabase::create_synchronized(language_server); let suggestion_db = Rc::new(suggestion_db.await.map_err(&wrap)?); + let content_roots = ContentRoots::new_from_connection(&logger,&*language_server); + let content_roots = Rc::new(content_roots); let notifications = notification::Publisher::default(); let urm = Rc::new(model::undo_redo::Manager::new(&logger)); let properties = Rc::new(RefCell::new(properties)); let ret = Project {properties,project_manager,language_server_rpc,language_server_bin,module_registry - ,execution_contexts,visualization,suggestion_db,parser,logger,notifications,urm}; + ,execution_contexts,visualization,suggestion_db,content_roots,parser,logger + ,notifications,urm}; let binary_handler = ret.binary_event_handler(); crate::executor::global::spawn(binary_protocol_events.for_each(binary_handler)); @@ -320,6 +363,7 @@ impl Project { let publisher = self.notifications.clone_ref(); let weak_execution_contexts = Rc::downgrade(&self.execution_contexts); let weak_suggestion_db = Rc::downgrade(&self.suggestion_db); + let weak_content_roots = Rc::downgrade(&self.content_roots); move |event| { debug!(logger, "Received an event from the json-rpc protocol: {event:?}"); use enso_protocol::language_server::Event; @@ -348,6 +392,16 @@ impl Project { suggestion_db.apply_update_event(update); } } + Event::Notification(Notification::ContentRootAdded {root}) => { + if let Some(content_roots) = weak_content_roots.upgrade() { + content_roots.add_content_root(root); + } + } + Event::Notification(Notification::ContentRootRemoved {id}) => { + if let Some(content_roots) = weak_content_roots.upgrade() { + content_roots.remove_content_root(id); + } + } Event::Closed => { error!(logger,"Lost JSON-RPC connection with the Language Server!"); let which = model::project::BackendConnection::LanguageServerJson; @@ -418,6 +472,10 @@ impl model::project::API for Project { self.suggestion_db.clone_ref() } + fn content_roots(&self) -> Vec> { + self.content_roots.all_content_roots() + } + fn module(&self, path: module::Path) -> BoxFuture> { async move { info!(self.logger,"Obtaining module for {path}"); @@ -451,7 +509,7 @@ impl model::project::API for Project { }.boxed_local() } - fn content_root_id(&self) -> Uuid { + fn project_content_root_id(&self) -> Uuid { self.language_server_rpc.project_root().id } diff --git a/src/rust/ide/tests/language_server.rs b/src/rust/ide/tests/language_server.rs index f0b19bd465..91ffd3fbef 100644 --- a/src/rust/ide/tests/language_server.rs +++ b/src/rust/ide/tests/language_server.rs @@ -62,12 +62,11 @@ wasm_bindgen_test_configure!(run_in_browser); //#[wasm_bindgen_test::wasm_bindgen_test(async)] #[allow(dead_code)] async fn ls_text_protocol_test() { - let _guard = ide::initializer::setup_global_executor(); let ide = setup_ide().await; let project = ide.current_project(); let client = project.json_rpc(); - let root_id = project.content_root_id(); + let root_id = project.project_content_root_id(); let project_name = project.qualified_name(); // Initialize files. From 1f0303eab56d7a780d9d8ba9aa73789f1f290cdc Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Fri, 2 Jul 2021 10:47:12 +0200 Subject: [PATCH 03/25] WIP --- src/rust/Cargo.lock | 20 +--- src/rust/Cargo.toml | 20 ++-- src/rust/ide/src/ide/integration.rs | 1 + .../ide/src/ide/integration/file_system.rs | 99 +++++++++++++++++++ 4 files changed, 112 insertions(+), 28 deletions(-) create mode 100644 src/rust/ide/src/ide/integration/file_system.rs diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index b5eeafa757..9698ab6915 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "Inflector" version = "0.11.4" @@ -570,8 +572,6 @@ dependencies = [ [[package]] name = "enso-automata" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9b028792f442d36cdd2df02a29ef988c219a9ebce952015bb1c2bcb5942d261" dependencies = [ "enso-prelude", ] @@ -595,8 +595,6 @@ dependencies = [ [[package]] name = "enso-data" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39dba144366e08671b102fd6feca76be1623e05816a3ba43ab05b2aaa45a625a" dependencies = [ "enso-prelude", "rustversion", @@ -625,8 +623,6 @@ dependencies = [ [[package]] name = "enso-generics" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345a68488069ed550c31127513445628bcaff9da467aa8e833067149cf8bc445" dependencies = [ "nalgebra 0.21.1", "serde", @@ -635,8 +631,6 @@ dependencies = [ [[package]] name = "enso-logger" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed27bf8ac2768a9224fd66863de4384b42bf16e079e02dd507798ce71dd4d2d" dependencies = [ "enso-prelude", "enso-shapely", @@ -648,8 +642,6 @@ dependencies = [ [[package]] name = "enso-macro-utils" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e4c3aca9d82b782043ad1378929e03813ee00e444858caddd6ec32580eff08" dependencies = [ "proc-macro2 1.0.26", "quote 1.0.9", @@ -659,8 +651,6 @@ dependencies = [ [[package]] name = "enso-optics" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4a34423408c57e6285d19ae88b53b9e0d254983bbcbf301d3f4a5c38f15802" dependencies = [ "enso-prelude", ] @@ -668,8 +658,6 @@ dependencies = [ [[package]] name = "enso-prelude" version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8a93f83e03fd9db4819f4258bc17d05dace04ec6ad2dd44aea9eb67936c601" dependencies = [ "anyhow", "backtrace", @@ -730,8 +718,6 @@ dependencies = [ [[package]] name = "enso-shapely" version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061a335e6068e8960a315f62813a7196c3cde2c650ebd0e744f26b479baf3cd8" dependencies = [ "derivative", "enso-shapely-macros", @@ -743,8 +729,6 @@ dependencies = [ [[package]] name = "enso-shapely-macros" version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3362771ca6e5a077479ae310c28e28abb56f4f62f2fe649719292227685dece0" dependencies = [ "Inflector", "boolinator", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 3b4cb81aa2..8f4e5384da 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -57,13 +57,13 @@ debug = true ## These patch versions exist to allow local development of these libraries alongside the IDE. It ## assumes you have `rust-lib` in the same directory as `ide`. See: ## https://github.com/enso-org/rust-lib/blob/main/docs/CONTRIBUTING.md#developing-in-conjunction-with-enso--ide -#[patch.crates-io] -#enso-automata = { path = '../../../rust-lib/src/automata' } -#enso-data = { path = '../../../rust-lib/src/data' } -#enso-generics = { path = '../../../rust-lib/src/generics' } -#enso-logger = { path = '../../../rust-lib/src/logger' } -#enso-macro-utils = { path = '../../../rust-lib/src/macro-utils' } -#enso-optics = { path = '../../../rust-lib/src/optics' } -#enso-prelude = { path = '../../../rust-lib/src/prelude' } -#enso-shapely = { path = '../../../rust-lib/src/shapely/impl' } -#enso-shapely-macros = { path = '../../../rust-lib/src/shapely/macros' } +[patch.crates-io] +enso-automata = { path = '../../../rust-lib/src/automata' } +enso-data = { path = '../../../rust-lib/src/data' } +enso-generics = { path = '../../../rust-lib/src/generics' } +enso-logger = { path = '../../../rust-lib/src/logger' } +enso-macro-utils = { path = '../../../rust-lib/src/macro-utils' } +enso-optics = { path = '../../../rust-lib/src/optics' } +enso-prelude = { path = '../../../rust-lib/src/prelude' } +enso-shapely = { path = '../../../rust-lib/src/shapely/impl' } +enso-shapely-macros = { path = '../../../rust-lib/src/shapely/macros' } diff --git a/src/rust/ide/src/ide/integration.rs b/src/rust/ide/src/ide/integration.rs index 501a5b924d..b641567910 100644 --- a/src/rust/ide/src/ide/integration.rs +++ b/src/rust/ide/src/ide/integration.rs @@ -1,6 +1,7 @@ //! The integration layer between IDE controllers and the view. pub mod project; +pub mod file_system; use crate::prelude::*; diff --git a/src/rust/ide/src/ide/integration/file_system.rs b/src/rust/ide/src/ide/integration/file_system.rs new file mode 100644 index 0000000000..bd2aacb89d --- /dev/null +++ b/src/rust/ide/src/ide/integration/file_system.rs @@ -0,0 +1,99 @@ +use crate::prelude::*; + +use enso_protocol::language_server; +use ensogl_gui_components::file_browser::model::{Folder, FolderEntry, FolderEntryType, FileSystem, ContentRoot, ContentRootType}; +use enso_frp as frp; +use enso_protocol::language_server::{FileSystemObject,}; + + +#[derive(Clone,Debug)] +pub struct FileProvider { + pub connection : Rc, + pub content_roots : Vec>, +} + +impl FileSystem for FileProvider { + fn request_content_roots(&self, entries_loaded: frp::Source>) { + let entries = self.content_roots.iter().map(|root| { + ContentRoot { + name: root.name.clone(), + path: root.id.to_string().into(), + type_: match root.content_root_type { + language_server::ContentRootType::Project => ContentRootType::Project, + language_server::ContentRootType::Root => ContentRootType::Root, + language_server::ContentRootType::Home => ContentRootType::Home, + language_server::ContentRootType::Library => ContentRootType::Library, + language_server::ContentRootType::Custom => ContentRootType::Custom, + }, + content: { + let connection = self.connection.clone_ref(); + DirectoryView::new_from_root(connection,root.clone_ref()).into() + } + } + }); + entries_loaded.emit(entries.collect_vec()); + } +} + +#[derive(Clone,CloneRef,Debug)] +pub struct DirectoryView { + connection : Rc, + content_root : Rc, + path : Rc, +} + +impl DirectoryView { + fn new_from_root + ( connection : Rc + , content_root : Rc + ) -> Self { + let path = Rc::new(language_server::Path::new_root(content_root.id)); + Self{connection,content_root,path} + } + + fn sub_view(&self, segment:impl Str) -> DirectoryView { + DirectoryView { + connection : self.connection.clone_ref(), + content_root : self.content_root.clone_ref(), + path : Rc::new(self.path.append_im(segment)) + } + } + + async fn get_entries_list(&self) -> FallibleResult> { + let response = self.connection.file_list(&self.path).await?; + let entries = response.paths.into_iter().map(|fs_obj| { + match fs_obj { + FileSystemObject::Directory {name,path} | + FileSystemObject::DirectoryTruncated {name,path} | + FileSystemObject::SymlinkLoop {name,path,..} => { + let path = path.to_string().into(); + let sub = self.sub_view(&name); + let type_ = FolderEntryType::Folder(sub.into()); + FolderEntry {name,path,type_} + } + FileSystemObject::File {name,path} | + FileSystemObject::Other {name,path} => { + let path = path.to_string().into(); + let type_ = FolderEntryType::File; + FolderEntry{name,path,type_} + } + } + }); + Ok(entries.collect()) + } +} + +impl Folder for DirectoryView { + fn request_entries + (&self, entries_loaded:frp::Source>, error_occurred:frp::Source) { + let this = self.clone_ref(); + executor::global::spawn(async move { + match this.get_entries_list().await { + Ok (entries) => entries_loaded.emit(entries), + Err(error) => error_occurred.emit(ImString::new(error.to_string())), + } + }); + } +} + +pub fn expression_from_file() From e0863feb77b48a7dba676eb3b09ba04e657a8f31 Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Fri, 2 Jul 2021 15:28:05 +0200 Subject: [PATCH 04/25] Should files be visible? --- docs/CONTRIBUTING.md | 1 + package-lock.json | 31 +-------- src/rust/Cargo.lock | 18 ++++++ src/rust/Cargo.toml | 20 +++--- .../ensogl/lib/components/src/file_browser.rs | 6 +- .../ide/src/ide/integration/file_system.rs | 60 +++++++++-------- src/rust/ide/src/ide/integration/project.rs | 24 +++---- src/rust/ide/view/src/lib.rs | 1 + src/rust/ide/view/src/open_dialog.rs | 48 ++++++++++++++ src/rust/ide/view/src/project.rs | 64 ++++++++++++------- 10 files changed, 170 insertions(+), 103 deletions(-) create mode 100644 src/rust/ide/view/src/open_dialog.rs diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index c6e5ac4a71..bb041f3cc5 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -1,3 +1,4 @@ + --- layout: developer-doc title: Development & Contributing Guide diff --git a/package-lock.json b/package-lock.json index 00b65b4672..48e341a095 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,32 +1,3 @@ { - "name": "ide", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "devDependencies": { - "prettier": "2.2.1" - } - }, - "node_modules/prettier": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - } - }, - "dependencies": { - "prettier": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", - "dev": true - } - } + "lockfileVersion": 1 } diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 9698ab6915..eeaaa61cbd 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -572,6 +572,8 @@ dependencies = [ [[package]] name = "enso-automata" version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9b028792f442d36cdd2df02a29ef988c219a9ebce952015bb1c2bcb5942d261" dependencies = [ "enso-prelude", ] @@ -595,6 +597,8 @@ dependencies = [ [[package]] name = "enso-data" version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39dba144366e08671b102fd6feca76be1623e05816a3ba43ab05b2aaa45a625a" dependencies = [ "enso-prelude", "rustversion", @@ -623,6 +627,8 @@ dependencies = [ [[package]] name = "enso-generics" version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345a68488069ed550c31127513445628bcaff9da467aa8e833067149cf8bc445" dependencies = [ "nalgebra 0.21.1", "serde", @@ -631,6 +637,8 @@ dependencies = [ [[package]] name = "enso-logger" version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed27bf8ac2768a9224fd66863de4384b42bf16e079e02dd507798ce71dd4d2d" dependencies = [ "enso-prelude", "enso-shapely", @@ -642,6 +650,8 @@ dependencies = [ [[package]] name = "enso-macro-utils" version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e4c3aca9d82b782043ad1378929e03813ee00e444858caddd6ec32580eff08" dependencies = [ "proc-macro2 1.0.26", "quote 1.0.9", @@ -651,6 +661,8 @@ dependencies = [ [[package]] name = "enso-optics" version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4a34423408c57e6285d19ae88b53b9e0d254983bbcbf301d3f4a5c38f15802" dependencies = [ "enso-prelude", ] @@ -658,6 +670,8 @@ dependencies = [ [[package]] name = "enso-prelude" version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8a93f83e03fd9db4819f4258bc17d05dace04ec6ad2dd44aea9eb67936c601" dependencies = [ "anyhow", "backtrace", @@ -718,6 +732,8 @@ dependencies = [ [[package]] name = "enso-shapely" version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061a335e6068e8960a315f62813a7196c3cde2c650ebd0e744f26b479baf3cd8" dependencies = [ "derivative", "enso-shapely-macros", @@ -729,6 +745,8 @@ dependencies = [ [[package]] name = "enso-shapely-macros" version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3362771ca6e5a077479ae310c28e28abb56f4f62f2fe649719292227685dece0" dependencies = [ "Inflector", "boolinator", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 8f4e5384da..3b4cb81aa2 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -57,13 +57,13 @@ debug = true ## These patch versions exist to allow local development of these libraries alongside the IDE. It ## assumes you have `rust-lib` in the same directory as `ide`. See: ## https://github.com/enso-org/rust-lib/blob/main/docs/CONTRIBUTING.md#developing-in-conjunction-with-enso--ide -[patch.crates-io] -enso-automata = { path = '../../../rust-lib/src/automata' } -enso-data = { path = '../../../rust-lib/src/data' } -enso-generics = { path = '../../../rust-lib/src/generics' } -enso-logger = { path = '../../../rust-lib/src/logger' } -enso-macro-utils = { path = '../../../rust-lib/src/macro-utils' } -enso-optics = { path = '../../../rust-lib/src/optics' } -enso-prelude = { path = '../../../rust-lib/src/prelude' } -enso-shapely = { path = '../../../rust-lib/src/shapely/impl' } -enso-shapely-macros = { path = '../../../rust-lib/src/shapely/macros' } +#[patch.crates-io] +#enso-automata = { path = '../../../rust-lib/src/automata' } +#enso-data = { path = '../../../rust-lib/src/data' } +#enso-generics = { path = '../../../rust-lib/src/generics' } +#enso-logger = { path = '../../../rust-lib/src/logger' } +#enso-macro-utils = { path = '../../../rust-lib/src/macro-utils' } +#enso-optics = { path = '../../../rust-lib/src/optics' } +#enso-prelude = { path = '../../../rust-lib/src/prelude' } +#enso-shapely = { path = '../../../rust-lib/src/shapely/impl' } +#enso-shapely-macros = { path = '../../../rust-lib/src/shapely/macros' } diff --git a/src/rust/ensogl/lib/components/src/file_browser.rs b/src/rust/ensogl/lib/components/src/file_browser.rs index 49ce8251a5..2a18e0bb41 100644 --- a/src/rust/ensogl/lib/components/src/file_browser.rs +++ b/src/rust/ensogl/lib/components/src/file_browser.rs @@ -43,10 +43,10 @@ const CONTENT_OFFSET_Y : f32 = TOOLBAR_HEIGHT + TOOLBAR_BORDER_SIZE; const PADDING : f32 = 16.0; // TODO: Take this value from styles. (https://github.com/enso-org/ide/issues/1694) // Or make it configurable through FRP, or both. -const WIDTH : f32 = 814.0; +pub const WIDTH : f32 = 814.0; // TODO: Take this value from styles. (https://github.com/enso-org/ide/issues/1694) // Or make it configurable through FRP, or both. -const HEIGHT : f32 = 421.0; +pub const HEIGHT : f32 = 421.0; // TODO: Take this value from styles. (https://github.com/enso-org/ide/issues/1694) const CONTENT_HEIGHT : f32 = HEIGHT - CONTENT_OFFSET_Y; // TODO: Take this value from styles. (https://github.com/enso-org/ide/issues/1694) @@ -306,7 +306,7 @@ impl ModelWithFrp { /// A file browser component. It allows to browse the content of a folder and it's subfolders and /// emits an event when an entry is chosen. -#[derive(Debug)] +#[derive(Clone,CloneRef,Debug)] pub struct FileBrowser(Rc); impl Deref for FileBrowser { diff --git a/src/rust/ide/src/ide/integration/file_system.rs b/src/rust/ide/src/ide/integration/file_system.rs index bd2aacb89d..a9cfc696ef 100644 --- a/src/rust/ide/src/ide/integration/file_system.rs +++ b/src/rust/ide/src/ide/integration/file_system.rs @@ -1,9 +1,12 @@ use crate::prelude::*; use enso_protocol::language_server; -use ensogl_gui_components::file_browser::model::{Folder, FolderEntry, FolderEntryType, FileSystem, ContentRoot, ContentRootType}; use enso_frp as frp; -use enso_protocol::language_server::{FileSystemObject,}; +use enso_protocol::language_server::FileSystemObject; +use ensogl_gui_components::file_browser::model::FolderContent; +use ensogl_gui_components::file_browser::model::FolderType; +use ensogl_gui_components::file_browser::model::Entry; +use ensogl_gui_components::file_browser::model::EntryType; #[derive(Clone,Debug)] @@ -12,26 +15,30 @@ pub struct FileProvider { pub content_roots : Vec>, } -impl FileSystem for FileProvider { - fn request_content_roots(&self, entries_loaded: frp::Source>) { +impl FolderContent for FileProvider { + fn request_entries + (&self, entries_loaded:frp::Any>>, _error_occurred:frp::Any) { let entries = self.content_roots.iter().map(|root| { - ContentRoot { + let folder_type = match root.content_root_type { + language_server::ContentRootType::Project => FolderType::Project, + language_server::ContentRootType::Root => FolderType::Root, + language_server::ContentRootType::Home => FolderType::Home, + language_server::ContentRootType::Library => FolderType::Library, + language_server::ContentRootType::Custom => FolderType::Custom, + }; + Entry { name: root.name.clone(), path: root.id.to_string().into(), - type_: match root.content_root_type { - language_server::ContentRootType::Project => ContentRootType::Project, - language_server::ContentRootType::Root => ContentRootType::Root, - language_server::ContentRootType::Home => ContentRootType::Home, - language_server::ContentRootType::Library => ContentRootType::Library, - language_server::ContentRootType::Custom => ContentRootType::Custom, - }, - content: { - let connection = self.connection.clone_ref(); - DirectoryView::new_from_root(connection,root.clone_ref()).into() + type_: EntryType::Folder { + type_ : folder_type, + content: { + let connection = self.connection.clone_ref(); + DirectoryView::new_from_root(connection,root.clone_ref()).into() + } } } }); - entries_loaded.emit(entries.collect_vec()); + entries_loaded.emit(Rc::new(entries.collect_vec())); } } @@ -59,7 +66,7 @@ impl DirectoryView { } } - async fn get_entries_list(&self) -> FallibleResult> { + async fn get_entries_list(&self) -> FallibleResult> { let response = self.connection.file_list(&self.path).await?; let entries = response.paths.into_iter().map(|fs_obj| { match fs_obj { @@ -68,14 +75,17 @@ impl DirectoryView { FileSystemObject::SymlinkLoop {name,path,..} => { let path = path.to_string().into(); let sub = self.sub_view(&name); - let type_ = FolderEntryType::Folder(sub.into()); - FolderEntry {name,path,type_} + let type_ = EntryType::Folder { + type_ : FolderType::Standard, + content : sub.into() + }; + Entry {name,path,type_} } FileSystemObject::File {name,path} | FileSystemObject::Other {name,path} => { let path = path.to_string().into(); - let type_ = FolderEntryType::File; - FolderEntry{name,path,type_} + let type_ = EntryType::File; + Entry {name,path,type_} } } }); @@ -83,17 +93,15 @@ impl DirectoryView { } } -impl Folder for DirectoryView { +impl FolderContent for DirectoryView { fn request_entries - (&self, entries_loaded:frp::Source>, error_occurred:frp::Source) { + (&self, entries_loaded:frp::Any>>, error_occurred:frp::Any) { let this = self.clone_ref(); executor::global::spawn(async move { match this.get_entries_list().await { - Ok (entries) => entries_loaded.emit(entries), + Ok (entries) => entries_loaded.emit(Rc::new(entries)), Err(error) => error_occurred.emit(ImString::new(error.to_string())), } }); } } - -pub fn expression_from_file() diff --git a/src/rust/ide/src/ide/integration/project.rs b/src/rust/ide/src/ide/integration/project.rs index 0e78d2ec6f..db0dfd0b9f 100644 --- a/src/rust/ide/src/ide/integration/project.rs +++ b/src/rust/ide/src/ide/integration/project.rs @@ -13,6 +13,7 @@ use crate::controller::searcher::action::MatchInfo; use crate::controller::searcher::Actions; use crate::controller::upload; use crate::controller::upload::NodeFromDroppedFileHandler; +use crate::ide::integration::file_system::FileProvider; use crate::model::execution_context::ComputedValueInfo; use crate::model::execution_context::ExpressionId; use crate::model::execution_context::LocalCall; @@ -31,6 +32,7 @@ use ensogl::data::color; use ensogl::display::shape::StyleWatch; use ensogl::display::traits::*; use ensogl::display; +use ensogl_gui_components::file_browser::model::AnyFolderContent; use ensogl_gui_components::list_view; use ensogl_text as text; use ensogl_web::drop; @@ -45,6 +47,7 @@ use ide_view::graph_editor; use utils::iter::split_by_predicate; + // ============== // === Errors === // ============== @@ -299,7 +302,6 @@ impl Integration { let inv = &invalidate.trigger; let node_editing_in_ui = Model::node_editing_in_ui(Rc::downgrade(&model)); let searcher_opened_in_ui = Model::searcher_opened_in_ui(Rc::downgrade(&model)); - let searcher_opened_fop_in_ui = Model::searcher_opened_for_opening_project_in_ui(Rc::downgrade(&model)); let code_changed = Self::ui_action(&model,Model::code_changed_in_ui ,inv); let node_removed = Self::ui_action(&model,Model::node_removed_in_ui ,inv); let nodes_collapsed = Self::ui_action(&model,Model::nodes_collapsed_in_ui ,inv); @@ -309,7 +311,6 @@ impl Integration { let connection_removed = Self::ui_action(&model,Model::connection_removed_in_ui ,inv); let node_moved = Self::ui_action(&model,Model::node_moved_in_ui ,inv); let searcher_opened = Self::ui_action(&model,searcher_opened_in_ui ,inv); - let searcher_opened_fop = Self::ui_action(&model,searcher_opened_fop_in_ui ,inv); let node_editing = Self::ui_action(&model,node_editing_in_ui ,inv); let node_expression_set = Self::ui_action(&model,Model::node_expression_set_in_ui ,inv); let used_as_suggestion = Self::ui_action(&model,Model::used_as_suggestion_in_ui ,inv); @@ -349,7 +350,6 @@ impl Integration { _action <- editor_outs.node_position_set_batched.map2(&is_hold,node_moved); _action <- editor_outs.node_being_edited .map2(&is_hold,node_editing); _action <- project_frp.searcher_opened .map2(&is_hold,searcher_opened); - _action <- project_frp.searcher_opened_for_opening_project.map2(&is_hold,searcher_opened_fop); _action <- editor_outs.node_expression_set .map2(&is_hold,node_expression_set); _action <- searcher_frp.used_as_suggestion .map2(&is_hold,used_as_suggestion); _action <- project_frp.editing_committed .map2(&is_hold,node_editing_committed); @@ -1040,14 +1040,6 @@ impl Model { } } - fn searcher_opened_for_opening_project_in_ui(weak_self:Weak) - -> impl Fn(&Self,&graph_editor::NodeId) -> FallibleResult { - move |this,_displayed_id| { - let mode = controller::searcher::Mode::OpenProject; - this.setup_searcher_controller(&weak_self,mode) - } - } - fn node_editing_in_ui(weak_self:Weak) -> impl Fn(&Self,&Option) -> FallibleResult { move |this,displayed_id| { @@ -1279,6 +1271,16 @@ impl Model { Err(MissingMappingFor::DisplayedVisualization(node_id).into()) } } + + fn open_file_dialog_opened_in_ui(&self) { + debug!(self.logger, "Opened file dialog in ui. Providing content root list"); + let provider = FileProvider { + connection: self.project.json_rpc(), + content_roots: self.project.content_roots(), + }; + let provider:AnyFolderContent = provider.into(); + self.view.open_dialog().file_browser.set_content(provider); + } } diff --git a/src/rust/ide/view/src/lib.rs b/src/rust/ide/view/src/lib.rs index b9723384f3..9432b12ffd 100644 --- a/src/rust/ide/view/src/lib.rs +++ b/src/rust/ide/view/src/lib.rs @@ -30,6 +30,7 @@ pub mod code_editor; pub mod debug_scenes; pub mod documentation; +pub mod open_dialog; pub mod project; pub mod searcher; pub mod status_bar; diff --git a/src/rust/ide/view/src/open_dialog.rs b/src/rust/ide/view/src/open_dialog.rs new file mode 100644 index 0000000000..f1be7599e9 --- /dev/null +++ b/src/rust/ide/view/src/open_dialog.rs @@ -0,0 +1,48 @@ +use crate::prelude::*; + +use enso_frp as frp; +use ensogl::display; +use ensogl_gui_components::list_view; +use ensogl_gui_components::list_view::ListView; +use ensogl_gui_components::file_browser; +use ensogl_gui_components::file_browser::FileBrowser; +use ensogl::application::Application; + + + +const PROJECT_LIST_WIDTH:f32 = 202.0; +const WIDTH:f32 = file_browser::WIDTH + PROJECT_LIST_WIDTH; +const HEIGHT:f32 = file_browser::HEIGHT; + + +#[derive(Clone,CloneRef,Debug)] +pub struct OpenDialog { + logger : Logger, + pub project_list : ListView, + pub file_browser : FileBrowser, + display_object : display::object::Instance, +} + +impl OpenDialog { + pub fn new(app:&Application) -> Self { + let logger = Logger::new("OpenDialog"); + let project_list = app.new_view::(); + let file_browser = app.new_view::(); + let display_object = display::object::Instance::new(&logger); + + display_object.add_child(&project_list); + project_list.resize(Vector2(PROJECT_LIST_WIDTH,HEIGHT)); + project_list.set_position_y(-WIDTH / 2.0 + PROJECT_LIST_WIDTH / 2.0); + + display_object.add_child(&file_browser); + file_browser.set_position_y(WIDTH / 2.0 - file_browser::WIDTH / 2.0); + + app.display.scene().layers.panel.add_exclusive(&display_object); + + Self {logger,project_list,file_browser,display_object} + } +} + +impl display::Object for OpenDialog { + fn display_object(&self) -> &display::object::Instance { &self.display_object } +} diff --git a/src/rust/ide/view/src/project.rs b/src/rust/ide/view/src/project.rs index bcb1a1bcf5..8f69f06878 100644 --- a/src/rust/ide/view/src/project.rs +++ b/src/rust/ide/view/src/project.rs @@ -8,6 +8,7 @@ use crate::graph_editor::component::node::Expression; use crate::graph_editor::component::visualization; use crate::graph_editor::GraphEditor; use crate::graph_editor::NodeId; +use crate::open_dialog::OpenDialog; use crate::searcher; use crate::status_bar; @@ -34,11 +35,12 @@ ensogl::define_endpoints! { Input { /// Open the searcher. open_searcher(), - /// Open the searcher with Open Project mode, where the only suggestions will be projects to - /// open, and node creation is disabled. - open_searcher_for_opening_project(), + /// Open the Open File or Project Dialog. + show_open_dialog(), /// Close the searcher without taking any actions close_searcher(), + /// Close the Open File or Project Dialog without further action + close_open_dialog(), /// Simulates a style toggle press event. toggle_style(), /// Saves the currently opened module to file. @@ -55,14 +57,13 @@ ensogl::define_endpoints! { Output { searcher_opened (NodeId), - searcher_opened_for_opening_project (NodeId), adding_new_node (bool), searcher_input (Option), is_searcher_opened (bool), - opening_project (bool), old_expression_of_edited_node (Expression), editing_aborted (NodeId), editing_committed (NodeId, Option), + open_dialog_shown (bool), code_editor_shown (bool), style (Theme), fullscreen_visualization_shown (bool), @@ -101,6 +102,10 @@ mod prompt_background { // === Model === // ============= +struct SubComponents { + +} + #[derive(Clone,CloneRef,Debug)] struct Model { app : Application, @@ -108,13 +113,14 @@ struct Model { display_object : display::object::Instance, /// These buttons are present only in a cloud environment. window_control_buttons : Immutable>, - graph_editor : GraphEditor, + graph_editor : Rc, searcher : searcher::View, code_editor : code_editor::View, status_bar : status_bar::View, fullscreen_vis : Rc>>, prompt_background : prompt_background::View, prompt : ensogl_text::Area, + open_dialog : Rc, } impl Model { @@ -136,6 +142,7 @@ impl Model { window_control_buttons }); let window_control_buttons = Immutable(window_control_buttons); + let open_dialog = Rc::new(OpenDialog::new(app)); prompt_background.add_child(&prompt); prompt.set_content("Press the tab key to search for components."); scene.layers.panel.add_exclusive(&prompt_background); @@ -148,9 +155,10 @@ impl Model { display_object.add_child(&status_bar); display_object.add_child(&prompt_background); display_object.remove_child(&searcher); - let app = app.clone_ref(); + let app = app.clone_ref(); + let graph_editor = Rc::new(graph_editor); Self{app,logger,display_object,window_control_buttons,graph_editor,searcher,code_editor, - status_bar,fullscreen_vis,prompt_background,prompt} + status_bar,fullscreen_vis,prompt_background,prompt,open_dialog} } /// Sets style of IDE to the one defined by parameter `theme`. @@ -235,7 +243,7 @@ impl Model { let node = self.graph_editor.model.model.nodes.all.get_cloned_ref(&node_id); if let Some(node) = node { let visualization = node.view.model.visualization.fullscreen_visualization().clone_ref(); - self.display_object.remove_child(&self.graph_editor); + self.display_object.remove_child(&*self.graph_editor); self.display_object.add_child(&visualization); *self.fullscreen_vis.borrow_mut() = Some(visualization); } @@ -244,7 +252,7 @@ impl Model { fn hide_fullscreen_visualization(&self) { if let Some(visualization) = std::mem::take(&mut *self.fullscreen_vis.borrow_mut()) { self.display_object.remove_child(&visualization); - self.display_object.add_child(&self.graph_editor); + self.display_object.add_child(&*self.graph_editor); } } @@ -263,6 +271,14 @@ impl Model { fn on_fullscreen_clicked(&self) { js::fullscreen(); } + + fn show_open_dialog(&self) { + self.display_object.add_child(&*self.open_dialog); + } + + fn hide_open_dialog(&self) { + self.display_object.remove_child(&*self.open_dialog); + } } @@ -345,6 +361,8 @@ impl View { let frp = Frp::new(); let searcher = &model.searcher.frp; let graph = &model.graph_editor.frp; + let project_list = &model.open_dialog.project_list; + let file_browser = &model.open_dialog.file_browser; let network = &frp.network; let searcher_left_top_position = DEPRECATED_Animation::>::new(network); let prompt_visibility = Animation::new(network); @@ -417,7 +435,7 @@ impl View { editing_aborted <+ frp.close_searcher.constant(true); editing_commited_in_searcher <- searcher.editing_committed.constant(()); should_finish_editing_if_any <- any(frp.close_searcher,editing_commited_in_searcher - ,frp.open_searcher,frp.open_searcher_for_opening_project); + ,frp.open_searcher,frp.show_open_dialog); should_finish_editing <- should_finish_editing_if_any.gate(&graph.output.node_editing); eval should_finish_editing ((()) graph.input.stop_editing.emit(())); @@ -466,19 +484,15 @@ impl View { eval adding_aborted ((node) graph.remove_node(node)); - // === Opening Project === - - frp.source.opening_project <+ frp.open_searcher_for_opening_project.constant(true); + // === Opening Open File or Project Dialog === - frp.source.searcher_opened_for_opening_project <+ frp.open_searcher_for_opening_project - .map(f!((_) model.add_node_and_edit())); + eval_ frp.show_open_dialog (model.show_open_dialog()); + project_chosen <- project_list.chosen_entry.constant(()); + file_chosen <- file_browser.entry_chosen.constant(()); + should_be_closed <- any(frp.close_open_dialog,project_chosen,file_chosen); + eval_ should_be_closed (model.hide_open_dialog()); - opening_committed <- frp.editing_committed.gate(&frp.opening_project).map(|(id,_)| *id); - opening_aborted <- frp.editing_aborted.gate(&frp.opening_project); - opening_finished <- any(&opening_committed,&opening_aborted); - frp.source.opening_project <+ opening_finished.constant(false); - - eval opening_finished ((node) graph.remove_node(node)); + frp.source.open_dialog_shown <+ bool(&should_be_closed,&frp.show_open_dialog); // === Style toggle === @@ -566,6 +580,9 @@ impl View { /// Status Bar View. pub fn status_bar(&self) -> &status_bar::View { &self.model.status_bar } + + /// Open File or Project Dialog + pub fn open_dialog(&self) -> &OpenDialog { &self.model.open_dialog } } impl display::Object for View { @@ -588,8 +605,9 @@ impl application::View for View { fn default_shortcuts() -> Vec { use shortcut::ActionType::*; (&[ (Press , "!is_searcher_opened", "tab" , "open_searcher") - , (Press , "!is_searcher_opened", "cmd o" , "open_searcher_for_opening_project") + , (Press , "!is_searcher_opened", "cmd o" , "show_open_dialog") , (Press , "is_searcher_opened" , "escape" , "close_searcher") + , (Press , "open_dialog_shown" , "escape" , "close_open_dialog") , (Press , "" , "tab" , "hide_prompt") , (Press , "" , "cmd alt shift t" , "toggle_style") , (Press , "" , "cmd s" , "save_module") From 4062aaec35b0391845e3b6e32d48af17a456b879 Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Mon, 5 Jul 2021 09:48:48 +0200 Subject: [PATCH 05/25] Yes, they should! --- src/rust/ide/src/ide/integration/project.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/rust/ide/src/ide/integration/project.rs b/src/rust/ide/src/ide/integration/project.rs index db0dfd0b9f..f4ed95553c 100644 --- a/src/rust/ide/src/ide/integration/project.rs +++ b/src/rust/ide/src/ide/integration/project.rs @@ -46,6 +46,9 @@ use ide_view::graph_editor::component::visualization; use ide_view::graph_editor; use utils::iter::split_by_predicate; +pub type Logger = enso_logger::DefaultTraceLogger; + + // ============== @@ -275,6 +278,7 @@ impl Integration { }); } + // === Dropping Files === let file_dropped = model.view.graph().file_dropped.clone_ref(); @@ -297,6 +301,14 @@ impl Integration { } + // === Open File or Project Dialog === + + frp::extend! { network + dialog_is_shown <- project_frp.open_dialog_shown.filter(|v| *v); + eval_ dialog_is_shown (model.open_file_dialog_opened_in_ui()); + } + + // === UI Actions === let inv = &invalidate.trigger; From 2dab4be3a661265f002efd53aa7168a71e0ea184 Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Mon, 5 Jul 2021 13:25:31 +0200 Subject: [PATCH 06/25] Some work on paths --- .../ensogl/lib/components/src/file_browser.rs | 2 +- .../src/language_server/types.rs | 2 + .../ide/src/ide/integration/file_system.rs | 46 ++++++++++++++++--- src/rust/ide/view/src/project.rs | 2 +- 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/rust/ensogl/lib/components/src/file_browser.rs b/src/rust/ensogl/lib/components/src/file_browser.rs index 2a18e0bb41..ca332b934f 100644 --- a/src/rust/ensogl/lib/components/src/file_browser.rs +++ b/src/rust/ensogl/lib/components/src/file_browser.rs @@ -185,7 +185,7 @@ ensogl_core::define_endpoints! { paste_into_focused (), } - Output { + Output { [TRACE_ALL] entry_selected (PathBuf), entry_chosen (PathBuf), diff --git a/src/rust/ide/lib/enso-protocol/src/language_server/types.rs b/src/rust/ide/lib/enso-protocol/src/language_server/types.rs index 7344ee3587..1ce875b8d8 100644 --- a/src/rust/ide/lib/enso-protocol/src/language_server/types.rs +++ b/src/rust/ide/lib/enso-protocol/src/language_server/types.rs @@ -2,6 +2,8 @@ use super::*; +use std::iter::once; + // ============= diff --git a/src/rust/ide/src/ide/integration/file_system.rs b/src/rust/ide/src/ide/integration/file_system.rs index a9cfc696ef..bc94b29abc 100644 --- a/src/rust/ide/src/ide/integration/file_system.rs +++ b/src/rust/ide/src/ide/integration/file_system.rs @@ -7,6 +7,35 @@ use ensogl_gui_components::file_browser::model::FolderContent; use ensogl_gui_components::file_browser::model::FolderType; use ensogl_gui_components::file_browser::model::Entry; use ensogl_gui_components::file_browser::model::EntryType; +use std::iter::once; +use std::ffi::OsString; + + +#[derive(Clone,Debug,Fail)] +#[fail(display="Invalid path received from File Browser Component: {}",path)] +struct InvalidPath {path:String} + +fn to_file_browser_path(path:&language_server::Path) -> std::path::PathBuf { + use std::path::Component::*; + let root_id_str = path.root_id.to_string(); + let segments_str = path.segments.iter().map(AsRef::::as_ref); + once("/").chain(once(root_id_str.as_ref())).chain(segments_str).collect() +} + +fn from_file_browser_path(path:&std::path::Path) -> FallibleResult { + use std::path::Component::*; + let mut iter = path.components(); + match (iter.next(), iter.next()) { + (Some(RootDir), Some(Normal(root_id))) => { + let root_id = root_id.to_string_lossy().parse()?; + Ok(language_server::Path::new(root_id,iter.map(|s| s.as_os_str().to_string_lossy()))) + } + _ => { + let path = path.to_string_lossy().to_string(); + Err(InvalidPath{path}.into()) + } + } +} #[derive(Clone,Debug)] @@ -19,6 +48,7 @@ impl FolderContent for FileProvider { fn request_entries (&self, entries_loaded:frp::Any>>, _error_occurred:frp::Any) { let entries = self.content_roots.iter().map(|root| { + let ls_path = language_server::Path::new_root(root.id); let folder_type = match root.content_root_type { language_server::ContentRootType::Project => FolderType::Project, language_server::ContentRootType::Root => FolderType::Root, @@ -27,11 +57,11 @@ impl FolderContent for FileProvider { language_server::ContentRootType::Custom => FolderType::Custom, }; Entry { - name: root.name.clone(), - path: root.id.to_string().into(), - type_: EntryType::Folder { - type_ : folder_type, - content: { + name : root.name.clone(), + path : to_file_browser_path(&ls_path), + type_ : EntryType::Folder { + type_ : folder_type, + content : { let connection = self.connection.clone_ref(); DirectoryView::new_from_root(connection,root.clone_ref()).into() } @@ -73,7 +103,7 @@ impl DirectoryView { FileSystemObject::Directory {name,path} | FileSystemObject::DirectoryTruncated {name,path} | FileSystemObject::SymlinkLoop {name,path,..} => { - let path = path.to_string().into(); + let path = to_file_browser_path(&path); let sub = self.sub_view(&name); let type_ = EntryType::Folder { type_ : FolderType::Standard, @@ -105,3 +135,7 @@ impl FolderContent for DirectoryView { }); } } + +// fn create_node_from_file(project:&model::Project, graph:&controller::Graph, path:&std::path::Path) -> FallibleResult { +// +// } diff --git a/src/rust/ide/view/src/project.rs b/src/rust/ide/view/src/project.rs index 8f69f06878..ed9d6e0611 100644 --- a/src/rust/ide/view/src/project.rs +++ b/src/rust/ide/view/src/project.rs @@ -489,7 +489,7 @@ impl View { eval_ frp.show_open_dialog (model.show_open_dialog()); project_chosen <- project_list.chosen_entry.constant(()); file_chosen <- file_browser.entry_chosen.constant(()); - should_be_closed <- any(frp.close_open_dialog,project_chosen,file_chosen); + should_be_closed <- any(frp.close_open_dialog,project_chosen/*,file_chosen*/); eval_ should_be_closed (model.hide_open_dialog()); frp.source.open_dialog_shown <+ bool(&should_be_closed,&frp.show_open_dialog); From e1ef3d9829cc8cda55146c1a669fd7fb0613944f Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Mon, 5 Jul 2021 14:31:36 +0200 Subject: [PATCH 07/25] Update with the newest Engines API --- .../src/language_server/connection.rs | 10 +-- .../src/language_server/types.rs | 67 +++++++++++++------ src/rust/ide/src/controller/visualization.rs | 2 +- .../ide/src/ide/integration/file_system.rs | 39 ++++++----- src/rust/ide/src/model/project.rs | 2 +- .../ide/src/model/project/synchronized.rs | 6 +- 6 files changed, 73 insertions(+), 53 deletions(-) diff --git a/src/rust/ide/lib/enso-protocol/src/language_server/connection.rs b/src/rust/ide/lib/enso-protocol/src/language_server/connection.rs index 251d51de3b..0d98a6750f 100644 --- a/src/rust/ide/lib/enso-protocol/src/language_server/connection.rs +++ b/src/rust/ide/lib/enso-protocol/src/language_server/connection.rs @@ -5,7 +5,6 @@ use crate::prelude::*; use crate::language_server::API; use crate::language_server::MockClient; use crate::language_server::types::ContentRoot; -use crate::language_server::types::ContentRootType; use uuid::Uuid; use utils::fail::FallibleResult; @@ -59,8 +58,7 @@ impl Connection { } fn extract_project_root(content_roots:&mut Vec) -> FallibleResult { - use ContentRootType::*; - let opt_index = content_roots.iter().position(|cr| cr.content_root_type == Project); + let opt_index = content_roots.iter().position(|cr| matches!(cr, ContentRoot::Project {..})); let index = opt_index.ok_or(MissingContentRoots)?; Ok(content_roots.drain(index..=index).next().unwrap()) } @@ -70,11 +68,7 @@ impl Connection { Connection { client : Box::new(client), client_id : default(), - project_root : ContentRoot { - id : default(), - content_root_type : ContentRootType::Project, - name : "Project".to_owned() - }, + project_root : ContentRoot::Project {id:default()}, content_roots : default(), } } diff --git a/src/rust/ide/lib/enso-protocol/src/language_server/types.rs b/src/rust/ide/lib/enso-protocol/src/language_server/types.rs index 1ce875b8d8..4bf66d3a9d 100644 --- a/src/rust/ide/lib/enso-protocol/src/language_server/types.rs +++ b/src/rust/ide/lib/enso-protocol/src/language_server/types.rs @@ -403,32 +403,55 @@ impl FileSystemObject { // === Content Roots === // ===================== -/// The type of the annotated content root. -#[derive(Clone,Copy,Debug,Deserialize,Eq,Hash,PartialEq,Serialize)] -pub enum ContentRootType { - /// The project home. - Project, - /// System root `/` on unix systems, or drive root on Windows. In Windows’ case, there may be - /// multiple [`Root`] entries corresponding to the various drives. - Root, - /// The user’s home directory. - Home, - /// An Enso library location. - Library, - /// A content root that has been added by the IDE (unused for now). - Custom -} - /// A content root represents a location on a real file-system that has been virtualized for use in /// the Cloud. #[allow(missing_docs)] #[derive(Clone,Debug,Deserialize,Eq,Hash,PartialEq,Serialize)] -#[serde(rename_all="camelCase")] -pub struct ContentRoot { - pub id:Uuid, - #[serde(rename="type")] - pub content_root_type : ContentRootType, - pub name : String, +#[serde(tag="type")] +pub enum ContentRoot { + /// Points to the project home. + #[serde(rename_all="camelCase")] + Project { + id : Uuid, + }, + /// This content root points to the system root (`/`) on unix systems, or to a drive root on + /// Windows. In Windows' case, there may be multiple `Root` entries corresponding to the various + /// drives. + #[serde(rename_all="camelCase")] + FileSystemRoot { + id : Uuid, + path : String, + }, + /// The user's home directory + #[serde(rename_all="camelCase")] + Home { + id : Uuid, + }, + /// An Enso library location. + #[serde(rename_all="camelCase")] + Library { + id : Uuid, + namespace : String, + name : String, + version : String, + }, + /// A content root that has been added by the IDE. + #[serde(rename_all="camelCase")] + Custom { + id : Uuid, + } +} + +impl ContentRoot { + pub fn id(&self) -> Uuid { + match self { + ContentRoot::Project {id } => *id, + ContentRoot::FileSystemRoot {id,..} => *id, + ContentRoot::Home {id } => *id, + ContentRoot::Library {id,..} => *id, + ContentRoot::Custom {id } => *id, + } + } } diff --git a/src/rust/ide/src/controller/visualization.rs b/src/rust/ide/src/controller/visualization.rs index 57550acbc8..523275c60f 100644 --- a/src/rust/ide/src/controller/visualization.rs +++ b/src/rust/ide/src/controller/visualization.rs @@ -105,7 +105,7 @@ impl Handle { async fn list_project_specific_visualizations (&self) -> FallibleResult> { - let root_id = self.language_server_rpc.project_root().id; + let root_id = self.language_server_rpc.project_root().id(); let path = language_server::Path::new(root_id,&[VISUALIZATION_DIRECTORY]); let folder = self.language_server_rpc.file_exists(&path).await?; let file_list = if folder.exists { diff --git a/src/rust/ide/src/ide/integration/file_system.rs b/src/rust/ide/src/ide/integration/file_system.rs index bc94b29abc..6ab5cce0ef 100644 --- a/src/rust/ide/src/ide/integration/file_system.rs +++ b/src/rust/ide/src/ide/integration/file_system.rs @@ -48,25 +48,28 @@ impl FolderContent for FileProvider { fn request_entries (&self, entries_loaded:frp::Any>>, _error_occurred:frp::Any) { let entries = self.content_roots.iter().map(|root| { - let ls_path = language_server::Path::new_root(root.id); - let folder_type = match root.content_root_type { - language_server::ContentRootType::Project => FolderType::Project, - language_server::ContentRootType::Root => FolderType::Root, - language_server::ContentRootType::Home => FolderType::Home, - language_server::ContentRootType::Library => FolderType::Library, - language_server::ContentRootType::Custom => FolderType::Custom, + let ls_path = language_server::Path::new_root(root.id()); + let path = to_file_browser_path(&ls_path); + let (name,folder_type) = match &**root { + language_server::ContentRoot::Project {..} => + ("Project".to_owned(), FolderType::Project), + language_server::ContentRoot::FileSystemRoot{path,..} => + (path.clone(),FolderType::Root), + language_server::ContentRoot::Home {..} => + ("Home".to_owned(), FolderType::Home), + language_server::ContentRoot::Library{namespace,name,..} => + (format!("{}.{}",namespace,name), FolderType::Library), + language_server::ContentRoot::Custom{..} => + ("Other".to_owned(),FolderType::Custom), }; - Entry { - name : root.name.clone(), - path : to_file_browser_path(&ls_path), - type_ : EntryType::Folder { - type_ : folder_type, - content : { - let connection = self.connection.clone_ref(); - DirectoryView::new_from_root(connection,root.clone_ref()).into() - } + let type_ = EntryType::Folder { + type_ : folder_type, + content : { + let connection = self.connection.clone_ref(); + DirectoryView::new_from_root(connection,root.clone_ref()).into() } - } + }; + Entry {name,path,type_} }); entries_loaded.emit(Rc::new(entries.collect_vec())); } @@ -84,7 +87,7 @@ impl DirectoryView { ( connection : Rc , content_root : Rc ) -> Self { - let path = Rc::new(language_server::Path::new_root(content_root.id)); + let path = Rc::new(language_server::Path::new_root(content_root.id())); Self{connection,content_root,path} } diff --git a/src/rust/ide/src/model/project.rs b/src/rust/ide/src/model/project.rs index dc8fbe15e1..4dcd691791 100644 --- a/src/rust/ide/src/model/project.rs +++ b/src/rust/ide/src/model/project.rs @@ -74,7 +74,7 @@ pub trait API:Debug { /// Returns the primary content root id for this project. fn project_content_root_id(&self) -> Uuid { - self.json_rpc().project_root().id + self.json_rpc().project_root().id() } /// Generates full module's qualified name that includes the leading project name segment. diff --git a/src/rust/ide/src/model/project/synchronized.rs b/src/rust/ide/src/model/project/synchronized.rs index 62bda6dd80..c5295e9922 100644 --- a/src/rust/ide/src/model/project/synchronized.rs +++ b/src/rust/ide/src/model/project/synchronized.rs @@ -104,7 +104,7 @@ impl ContentRoots { pub fn new_from_connection (parent:impl AnyLogger, connection:&language_server::Connection) -> Self { let logger = Logger::sub(parent,"ContentRoots"); - let roots_vec = connection.content_roots().map(|r| (r.id,Rc::new(r.clone()))).collect(); + let roots_vec = connection.content_roots().map(|r| (r.id(),Rc::new(r.clone()))).collect(); let roots = RefCell::new(roots_vec); Self{logger,roots} } @@ -115,7 +115,7 @@ impl ContentRoots { pub fn add_content_root(&self, content_root:ContentRoot) { let content_root = Rc::new(content_root); - if let Some(existing) = self.roots.borrow_mut().insert(content_root.id,content_root) { + if let Some(existing) = self.roots.borrow_mut().insert(content_root.id(),content_root) { warning!(self.logger,"Adding content root: there is already content root with given \ id: {existing:?}"); } @@ -510,7 +510,7 @@ impl model::project::API for Project { } fn project_content_root_id(&self) -> Uuid { - self.language_server_rpc.project_root().id + self.language_server_rpc.project_root().id() } fn subscribe(&self) -> Subscriber { From 4eb2cec279193ebf9ae86c23dfaf0daf4bc4a418 Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Tue, 6 Jul 2021 11:58:40 +0200 Subject: [PATCH 08/25] WIP --- .../lib/components/src/list_view/entry.rs | 4 +- src/rust/ide/src/ide/integration/project.rs | 69 ++++++++++++++++++- src/rust/ide/view/src/project.rs | 2 +- 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/src/rust/ensogl/lib/components/src/list_view/entry.rs b/src/rust/ensogl/lib/components/src/list_view/entry.rs index 1f7db78202..0e4eb5c604 100644 --- a/src/rust/ensogl/lib/components/src/list_view/entry.rs +++ b/src/rust/ensogl/lib/components/src/list_view/entry.rs @@ -132,13 +132,13 @@ impl EntryProvider for EmptyProvider { // === StringEntry === #[derive(Debug)] -struct StringEntry { +pub struct StringEntry { display_object : display::object::Instance, label : text::Area, } impl StringEntry { - fn new(app:&Application, string:&str) -> Self { + pub fn new(app:&Application, string:&str) -> Self { let logger = Logger::new("StringEntry"); let display_object = display::object::Instance::new(logger); diff --git a/src/rust/ide/src/ide/integration/project.rs b/src/rust/ide/src/ide/integration/project.rs index f4ed95553c..57344d2d7c 100644 --- a/src/rust/ide/src/ide/integration/project.rs +++ b/src/rust/ide/src/ide/integration/project.rs @@ -9,6 +9,7 @@ use crate::prelude::*; use crate::controller::graph::Connections; use crate::controller::graph::NodeTrees; +use crate::controller::ide::ProjectMetadata; use crate::controller::searcher::action::MatchInfo; use crate::controller::searcher::Actions; use crate::controller::upload; @@ -34,6 +35,7 @@ use ensogl::display::traits::*; use ensogl::display; use ensogl_gui_components::file_browser::model::AnyFolderContent; use ensogl_gui_components::list_view; +use ensogl_gui_components::list_view::entry::AnyEntry; use ensogl_text as text; use ensogl_web::drop; use futures::future::LocalBoxFuture; @@ -44,6 +46,7 @@ use ide_view::graph_editor::SharedHashMap; use ide_view::graph_editor::component::node; use ide_view::graph_editor::component::visualization; use ide_view::graph_editor; +use ide_view::searcher::entry::AnyEntryProvider; use utils::iter::split_by_predicate; pub type Logger = enso_logger::DefaultTraceLogger; @@ -201,6 +204,7 @@ struct Model { visualizations : SharedHashMap, error_visualizations : SharedHashMap, prompt_was_shown : Cell, + displayed_project_list : CloneRefCell, } @@ -305,7 +309,8 @@ impl Integration { frp::extend! { network dialog_is_shown <- project_frp.open_dialog_shown.filter(|v| *v); - eval_ dialog_is_shown (model.open_file_dialog_opened_in_ui()); + eval_ dialog_is_shown (model.open_dialog_opened_in_ui()); + // eval model.view.open_dialog().project_list.entry_chosen } @@ -1284,14 +1289,43 @@ impl Model { } } - fn open_file_dialog_opened_in_ui(&self) { - debug!(self.logger, "Opened file dialog in ui. Providing content root list"); + fn open_dialog_opened_in_ui(self:&Rc) { + debug!(logger, "Opened file dialog in ui. Providing content root list"); let provider = FileProvider { connection: self.project.json_rpc(), content_roots: self.project.content_roots(), }; let provider:AnyFolderContent = provider.into(); self.view.open_dialog().file_browser.set_content(provider); + let model = Rc::downgrade(self); + + executor::global::spawn(async move { + if let Some(this) = model.upgrade() { + if let Ok(manage_projects) = this.ide.manage_projects() { + match manage_projects.list_projects().await { + Ok(projects) => { + let entries = ProjectsToOpen::new(projects).into(); + this.displayed_project_list.set(entries.clone_ref()); + let any_entries:AnyEntryProvider = entries.into(); + this.view.open_dialog().project_list.set_entries(any_entries) + }, + Err(error) => error!(logger,"Error when loading project's list: {error}"), + } + } + } + }); + } + + fn project_opened_in_ui(&self, entry_id:&list_view::entry::Id) -> FallibleResult { + if let Some(id) = self.displayed_project_list.get().get_project_id_by_index(entry_id) { + let ide = self.ide.clone_ref(); + executor::global::spawn(async move { + if let Ok(manage_projects) = ide.manage_projects() { + manage_projects.open_project(id) + } + }) + + } } } @@ -1600,3 +1634,32 @@ impl upload::DataProvider for drop::File { self.read_chunk().map(|f| f.map_err(|e| e.into())).boxed_local() } } + + + +// ======================== +// === Project Provider === +// ======================== + +#[derive(Clone,CloneRef,Debug,Default)] +struct ProjectsToOpen { + projects : Rc> +} + +impl ProjectsToOpen { + fn new(projects:Vec) -> Self { + Self {projects:Rc::new(projects)} + } + + fn get_project_id_by_index(&self, index:usize) -> Option { + self.projects.get(index).map(|md| md.id) + } +} + +impl list_view::entry::EntryProvider for ProjectsToOpen { + fn entry_count(&self) -> usize { self.projects.len() } + + fn get(&self, app: &Application, id: usize) -> Option { + Some(list_view::entry::StringEntry::new(app,self.projects.get(id)?.name.as_ref()).into()) + } +} diff --git a/src/rust/ide/view/src/project.rs b/src/rust/ide/view/src/project.rs index ed9d6e0611..8f69f06878 100644 --- a/src/rust/ide/view/src/project.rs +++ b/src/rust/ide/view/src/project.rs @@ -489,7 +489,7 @@ impl View { eval_ frp.show_open_dialog (model.show_open_dialog()); project_chosen <- project_list.chosen_entry.constant(()); file_chosen <- file_browser.entry_chosen.constant(()); - should_be_closed <- any(frp.close_open_dialog,project_chosen/*,file_chosen*/); + should_be_closed <- any(frp.close_open_dialog,project_chosen,file_chosen); eval_ should_be_closed (model.hide_open_dialog()); frp.source.open_dialog_shown <+ bool(&should_be_closed,&frp.show_open_dialog); From 2b91fe4aec54e3b6f5656cec0e8832e3009d4cbd Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Tue, 6 Jul 2021 16:41:38 +0200 Subject: [PATCH 09/25] Adding nodes from files --- src/js/lib/content/package-lock.json | 4882 +++++++++++++++++ src/js/lib/project-manager/src/build.ts | 2 +- src/rust/ide/src/controller/project.rs | 4 +- .../ide/src/ide/integration/file_system.rs | 36 +- src/rust/ide/src/ide/integration/project.rs | 35 +- src/rust/ide/src/model/project.rs | 2 + .../ide/src/model/project/synchronized.rs | 24 +- 7 files changed, 4955 insertions(+), 30 deletions(-) create mode 100644 src/js/lib/content/package-lock.json diff --git a/src/js/lib/content/package-lock.json b/src/js/lib/content/package-lock.json new file mode 100644 index 0000000000..db1258006d --- /dev/null +++ b/src/js/lib/content/package-lock.json @@ -0,0 +1,4882 @@ +{ + "name": "enso-studio-content", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "typescript": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", + "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", + "dev": true + }, + "webpack": { + "version": "4.46.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz", + "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.5.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "optional": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true, + "optional": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "optional": true + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dev": true, + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "dev": true, + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "dev": true, + "optional": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.3.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + }, + "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "optional": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "optional": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "optional": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "optional": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } + } + }, + "errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==", + "dev": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "optional": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "optional": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "optional": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "optional": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dev": true, + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dev": true, + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true, + "optional": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "picomatch": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", + "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", + "dev": true, + "optional": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "optional": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true, + "optional": true + }, + "repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "ssri": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", + "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true + }, + "terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "optional": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, + "watchpack": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", + "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "dev": true, + "requires": { + "chokidar": "^3.4.1", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.1" + } + }, + "watchpack-chokidar2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", + "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", + "dev": true, + "optional": true, + "requires": { + "chokidar": "^2.1.8" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "optional": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "optional": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "optional": true + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "optional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "optional": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "optional": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "optional": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "optional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + } + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "webpack-cli": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.12.tgz", + "integrity": "sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "cross-spawn": "^6.0.5", + "enhanced-resolve": "^4.1.1", + "findup-sync": "^3.0.0", + "global-modules": "^2.0.0", + "import-local": "^2.0.0", + "interpret": "^1.4.0", + "loader-utils": "^1.4.0", + "supports-color": "^6.1.0", + "v8-compile-cache": "^2.1.1", + "yargs": "^13.3.2" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + } + }, + "errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "requires": { + "global-prefix": "^3.0.0" + }, + "dependencies": { + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + } + } + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "dependencies": { + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + } + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + } + } +} diff --git a/src/js/lib/project-manager/src/build.ts b/src/js/lib/project-manager/src/build.ts index 351ec42b21..53d4fb7c0c 100644 --- a/src/js/lib/project-manager/src/build.ts +++ b/src/js/lib/project-manager/src/build.ts @@ -44,7 +44,7 @@ async function get_project_manager_url(): Promise { // This constant MUST be synchronized with `ENGINE` constant in src/js/lib/client/tasks/signArchives.js. // Also it is usually a good idea to synchronize it with `ENGINE_VERSION_FOR_NEW_PROJECTS` in // src/rust/ide/src/controller/project.rs. See also https://github.com/enso-org/ide/issues/1359 - const version = '0.2.12' + const version = '0.2.13-SNAPSHOT.2021-07-06' let base_url: string = 'https://github.com/enso-org/' base_url += 'enso/releases/download/' base_url += `enso-${version}/enso-project-manager-${version}` diff --git a/src/rust/ide/src/controller/project.rs b/src/rust/ide/src/controller/project.rs index ea1c633e5b..7f366e4782 100644 --- a/src/rust/ide/src/controller/project.rs +++ b/src/rust/ide/src/controller/project.rs @@ -23,12 +23,12 @@ pub const COMPILING_STDLIB_LABEL:&str = "Compiling standard library. It can take /// The requirements for Engine's version, in format understandable by /// [`semver::VersionReq::parse`]. -pub const ENGINE_VERSION_SUPPORTED : &str = "^0.2.12"; +pub const ENGINE_VERSION_SUPPORTED : &str = "^0.2.13-SNAPSHOT.2021-07-06"; /// The Engine version used in projects created in IDE. // Usually it is a good idea to synchronize this version with the bundled Engine version in // src/js/lib/project-manager/src/build.ts. See also https://github.com/enso-org/ide/issues/1359 -pub const ENGINE_VERSION_FOR_NEW_PROJECTS : &str = "0.2.12"; +pub const ENGINE_VERSION_FOR_NEW_PROJECTS : &str = "0.2.13-SNAPSHOT.2021-07-06"; /// The name of the module initially opened in the project view. /// diff --git a/src/rust/ide/src/ide/integration/file_system.rs b/src/rust/ide/src/ide/integration/file_system.rs index 6ab5cce0ef..3380576b94 100644 --- a/src/rust/ide/src/ide/integration/file_system.rs +++ b/src/rust/ide/src/ide/integration/file_system.rs @@ -2,19 +2,22 @@ use crate::prelude::*; use enso_protocol::language_server; use enso_frp as frp; -use enso_protocol::language_server::FileSystemObject; +use enso_protocol::language_server::{FileSystemObject, ContentRoot}; use ensogl_gui_components::file_browser::model::FolderContent; use ensogl_gui_components::file_browser::model::FolderType; use ensogl_gui_components::file_browser::model::Entry; use ensogl_gui_components::file_browser::model::EntryType; use std::iter::once; use std::ffi::OsString; +use crate::controller::graph::NewNodeInfo; #[derive(Clone,Debug,Fail)] #[fail(display="Invalid path received from File Browser Component: {}",path)] struct InvalidPath {path:String} + + fn to_file_browser_path(path:&language_server::Path) -> std::path::PathBuf { use std::path::Component::*; let root_id_str = path.root_id.to_string(); @@ -103,10 +106,10 @@ impl DirectoryView { let response = self.connection.file_list(&self.path).await?; let entries = response.paths.into_iter().map(|fs_obj| { match fs_obj { - FileSystemObject::Directory {name,path} | - FileSystemObject::DirectoryTruncated {name,path} | - FileSystemObject::SymlinkLoop {name,path,..} => { - let path = to_file_browser_path(&path); + FileSystemObject::Directory {name,path} | + FileSystemObject::DirectoryTruncated {name,path} | + FileSystemObject::SymlinkLoop {name,path,..} => { + let path = to_file_browser_path(&path).join(&name); let sub = self.sub_view(&name); let type_ = EntryType::Folder { type_ : FolderType::Standard, @@ -114,9 +117,9 @@ impl DirectoryView { }; Entry {name,path,type_} } - FileSystemObject::File {name,path} | + FileSystemObject::File {name,path} | FileSystemObject::Other {name,path} => { - let path = path.to_string().into(); + let path = to_file_browser_path(&path).join(&name); let type_ = EntryType::File; Entry {name,path,type_} } @@ -139,6 +142,19 @@ impl FolderContent for DirectoryView { } } -// fn create_node_from_file(project:&model::Project, graph:&controller::Graph, path:&std::path::Path) -> FallibleResult { -// -// } +pub fn create_node_from_file(project:&model::Project, graph:&controller::Graph, path:&std::path::Path) -> FallibleResult { + let ls_path = from_file_browser_path(path)?; + let path_segments = ls_path.segments.into_iter().join("/"); + let content_root = project.content_root_by_id(ls_path.root_id)?; + let path = match &*content_root { + ContentRoot::Project { .. } => format!("Enso_Project.root/\"{}\"", path_segments), + ContentRoot::FileSystemRoot { path,.. } => format!("\"{}/{}\"", path,path_segments), + ContentRoot::Home { .. } => format!("File.home/\"{}\"", path_segments), + ContentRoot::Library { namespace,name,.. } => format!("{}.{}.Enso_Project.root / \"{}\"",namespace,name,path_segments), + ContentRoot::Custom { .. } => todo!(), + }; + let expression = format!("File.read {}", path); + let node_info = NewNodeInfo::new_pushed_back(expression); + graph.add_node(node_info)?; + Ok(()) +} diff --git a/src/rust/ide/src/ide/integration/project.rs b/src/rust/ide/src/ide/integration/project.rs index 57344d2d7c..5da0b8d275 100644 --- a/src/rust/ide/src/ide/integration/project.rs +++ b/src/rust/ide/src/ide/integration/project.rs @@ -308,9 +308,13 @@ impl Integration { // === Open File or Project Dialog === frp::extend! { network - dialog_is_shown <- project_frp.open_dialog_shown.filter(|v| *v); + let chosen_project = model.view.open_dialog().project_list.chosen_entry.clone_ref(); + let file_chosen = model.view.open_dialog().file_browser.entry_chosen.clone_ref(); + project_chosen <- chosen_project.filter_map(|p| *p); + dialog_is_shown <- project_frp.open_dialog_shown.filter(|v| *v); eval_ dialog_is_shown (model.open_dialog_opened_in_ui()); - // eval model.view.open_dialog().project_list.entry_chosen + eval project_chosen ((id) model.project_opened_in_ui(id)); + eval file_chosen ((path) model.file_opened_in_ui(path)); } @@ -490,10 +494,11 @@ impl Model { let error_visualizations = default(); let searcher = default(); let prompt_was_shown = default(); + let displayed_project_list = default(); let this = Model {logger,view,graph,text,ide,searcher,project,node_views,node_view_by_expression ,expression_views,expression_types,connection_views,code_view,visualizations - ,error_visualizations,prompt_was_shown}; + ,error_visualizations,prompt_was_shown,displayed_project_list}; this.view.graph().frp.remove_all_nodes(); this.view.status_bar().clear_all(); @@ -1290,7 +1295,7 @@ impl Model { } fn open_dialog_opened_in_ui(self:&Rc) { - debug!(logger, "Opened file dialog in ui. Providing content root list"); + debug!(self.logger, "Opened file dialog in ui. Providing content root list"); let provider = FileProvider { connection: self.project.json_rpc(), content_roots: self.project.content_roots(), @@ -1304,27 +1309,35 @@ impl Model { if let Ok(manage_projects) = this.ide.manage_projects() { match manage_projects.list_projects().await { Ok(projects) => { - let entries = ProjectsToOpen::new(projects).into(); + let entries = ProjectsToOpen::new(projects); this.displayed_project_list.set(entries.clone_ref()); let any_entries:AnyEntryProvider = entries.into(); this.view.open_dialog().project_list.set_entries(any_entries) }, - Err(error) => error!(logger,"Error when loading project's list: {error}"), + Err(error) => error!(this.logger,"Error when loading project's list: {error}"), } } } }); } - fn project_opened_in_ui(&self, entry_id:&list_view::entry::Id) -> FallibleResult { - if let Some(id) = self.displayed_project_list.get().get_project_id_by_index(entry_id) { - let ide = self.ide.clone_ref(); + fn project_opened_in_ui(&self, entry_id:&list_view::entry::Id) { + if let Some(id) = self.displayed_project_list.get().get_project_id_by_index(*entry_id) { + let logger = self.logger.clone_ref(); + let ide = self.ide.clone_ref(); executor::global::spawn(async move { if let Ok(manage_projects) = ide.manage_projects() { - manage_projects.open_project(id) + if let Err(err) = manage_projects.open_project(id).await { + error!(logger, "Error while opening project: {err}"); + } } - }) + }); + } + } + fn file_opened_in_ui(&self, path:&std::path::Path) { + if let Err(err) = create_node_from_file(&self.project,&self.graph.graph(),path) { + error!(self.logger, "Error while creating node from file: {err}"); } } } diff --git a/src/rust/ide/src/model/project.rs b/src/rust/ide/src/model/project.rs index 4dcd691791..8a5adf6fd8 100644 --- a/src/rust/ide/src/model/project.rs +++ b/src/rust/ide/src/model/project.rs @@ -56,6 +56,8 @@ pub trait API:Debug { fn content_roots(&self) -> Vec>; + fn content_root_by_id(&self, id:Uuid) -> FallibleResult>; + /// Returns a model of module opened from file. #[allow(clippy::needless_lifetimes)] // Note: Needless lifetimes fn module<'a> diff --git a/src/rust/ide/src/model/project/synchronized.rs b/src/rust/ide/src/model/project/synchronized.rs index c5295e9922..79b5d9a5f4 100644 --- a/src/rust/ide/src/model/project/synchronized.rs +++ b/src/rust/ide/src/model/project/synchronized.rs @@ -94,6 +94,10 @@ impl ExecutionContextsRegistry { // === ContentRoots === // ==================== +#[derive(Clone,Debug,Fail)] +#[fail(display="Content root {} does not exist.",id)] +struct MissingContentRoot {id:Uuid} + #[derive(Clone,Debug)] pub struct ContentRoots { logger : Logger, @@ -109,11 +113,11 @@ impl ContentRoots { Self{logger,roots} } - pub fn all_content_roots(&self) -> Vec> { + pub fn all(&self) -> Vec> { self.roots.borrow().values().cloned().collect() } - pub fn add_content_root(&self, content_root:ContentRoot) { + pub fn add(&self, content_root:ContentRoot) { let content_root = Rc::new(content_root); if let Some(existing) = self.roots.borrow_mut().insert(content_root.id(),content_root) { warning!(self.logger,"Adding content root: there is already content root with given \ @@ -121,7 +125,11 @@ impl ContentRoots { } } - pub fn remove_content_root(&self, id:Uuid) { + pub fn get(&self, id:Uuid) -> FallibleResult> { + self.roots.borrow().get(&id).cloned().ok_or_else(|| MissingContentRoot{id}.into()) + } + + pub fn remove(&self, id:Uuid) { if self.roots.borrow_mut().remove(&id).is_none() { warning!(self.logger,"Removing content root: no content root with given id: {id}"); } @@ -394,12 +402,12 @@ impl Project { } Event::Notification(Notification::ContentRootAdded {root}) => { if let Some(content_roots) = weak_content_roots.upgrade() { - content_roots.add_content_root(root); + content_roots.add(root); } } Event::Notification(Notification::ContentRootRemoved {id}) => { if let Some(content_roots) = weak_content_roots.upgrade() { - content_roots.remove_content_root(id); + content_roots.remove(id); } } Event::Closed => { @@ -473,7 +481,11 @@ impl model::project::API for Project { } fn content_roots(&self) -> Vec> { - self.content_roots.all_content_roots() + self.content_roots.all() + } + + fn content_root_by_id(&self, id:Uuid) -> FallibleResult> { + self.content_roots.get(id) } fn module(&self, path: module::Path) -> BoxFuture> { From e6939705f44ce7ea92cd9a2044f68575abda5ec6 Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Thu, 8 Jul 2021 10:25:22 +0200 Subject: [PATCH 10/25] WIP --- src/rust/Cargo.toml | 2 +- .../ensogl/lib/components/src/file_browser.rs | 8 +- .../lib/components/src/list_view/entry.rs | 4 +- src/rust/ensogl/lib/theme/src/lib.rs | 10 ++ .../src/language_server/types.rs | 3 +- src/rust/ide/src/ide/integration/project.rs | 6 +- src/rust/ide/view/src/open_dialog.rs | 32 ++--- .../ide/view/src/open_dialog/project_list.rs | 133 ++++++++++++++++++ 8 files changed, 171 insertions(+), 27 deletions(-) create mode 100644 src/rust/ide/view/src/open_dialog/project_list.rs diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 3b4cb81aa2..620251d924 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -35,7 +35,7 @@ members = [ ] [profile.dev] -opt-level = 0 +opt-level = 2 lto = false debug = true diff --git a/src/rust/ensogl/lib/components/src/file_browser.rs b/src/rust/ensogl/lib/components/src/file_browser.rs index ca332b934f..2656f9d5c6 100644 --- a/src/rust/ensogl/lib/components/src/file_browser.rs +++ b/src/rust/ensogl/lib/components/src/file_browser.rs @@ -33,17 +33,21 @@ use ensogl_core::data::color; // === Constants === // ================= +/// The height of the File Browser's toolbar in pixels. // TODO: Take this value from styles. (https://github.com/enso-org/ide/issues/1694) -const TOOLBAR_HEIGHT : f32 = 45.0; +pub const TOOLBAR_HEIGHT : f32 = 45.0; +/// The size in pixels of the line between File Browser's toolbar and content. // TODO: Take this value from styles. (https://github.com/enso-org/ide/issues/1694) -const TOOLBAR_BORDER_SIZE : f32 = 1.0; +pub const TOOLBAR_BORDER_SIZE : f32 = 1.0; // TODO: Take this value from styles. (https://github.com/enso-org/ide/issues/1694) const CONTENT_OFFSET_Y : f32 = TOOLBAR_HEIGHT + TOOLBAR_BORDER_SIZE; // TODO: Take this value from styles. (https://github.com/enso-org/ide/issues/1694) const PADDING : f32 = 16.0; +/// The width of the File Browser in pixels. // TODO: Take this value from styles. (https://github.com/enso-org/ide/issues/1694) // Or make it configurable through FRP, or both. pub const WIDTH : f32 = 814.0; +/// The height of the File Browser in pixels. // TODO: Take this value from styles. (https://github.com/enso-org/ide/issues/1694) // Or make it configurable through FRP, or both. pub const HEIGHT : f32 = 421.0; diff --git a/src/rust/ensogl/lib/components/src/list_view/entry.rs b/src/rust/ensogl/lib/components/src/list_view/entry.rs index 0e4eb5c604..9c974de2dd 100644 --- a/src/rust/ensogl/lib/components/src/list_view/entry.rs +++ b/src/rust/ensogl/lib/components/src/list_view/entry.rs @@ -131,8 +131,8 @@ impl EntryProvider for EmptyProvider { // === StringEntry === -#[derive(Debug)] -pub struct StringEntry { +#[derive(Clone,CloneRef,Debug)] +struct StringEntry { display_object : display::object::Instance, label : text::Area, } diff --git a/src/rust/ensogl/lib/theme/src/lib.rs b/src/rust/ensogl/lib/theme/src/lib.rs index afe70c70f0..1cc1496f58 100644 --- a/src/rust/ensogl/lib/theme/src/lib.rs +++ b/src/rust/ensogl/lib/theme/src/lib.rs @@ -171,6 +171,16 @@ define_themes! { [light:0, dark:1] background = graph_editor::node::background , graph_editor::node::background; toolbar_border_color = Rgba(0.808,0.808,0.808,1.0) , Rgba(0.808,0.808,0.808,1.0); } + project_list { + width = 202.0 , 202.0; + padding = 16.0, 16.0; + height = 421.0, 421.0; + bar { + height = 45.0, 45.0; + border_size = 1.0, 1.0; + label_size = 12.0, 12.0; + } + } window_control_buttons { radius = 6.5, 6.5; diff --git a/src/rust/ide/lib/enso-protocol/src/language_server/types.rs b/src/rust/ide/lib/enso-protocol/src/language_server/types.rs index 4bf66d3a9d..75e800afc9 100644 --- a/src/rust/ide/lib/enso-protocol/src/language_server/types.rs +++ b/src/rust/ide/lib/enso-protocol/src/language_server/types.rs @@ -2,8 +2,6 @@ use super::*; -use std::iter::once; - // ============= @@ -443,6 +441,7 @@ pub enum ContentRoot { } impl ContentRoot { + /// Get the id of the content root. pub fn id(&self) -> Uuid { match self { ContentRoot::Project {id } => *id, diff --git a/src/rust/ide/src/ide/integration/project.rs b/src/rust/ide/src/ide/integration/project.rs index 5da0b8d275..7bca2311fb 100644 --- a/src/rust/ide/src/ide/integration/project.rs +++ b/src/rust/ide/src/ide/integration/project.rs @@ -15,6 +15,7 @@ use crate::controller::searcher::Actions; use crate::controller::upload; use crate::controller::upload::NodeFromDroppedFileHandler; use crate::ide::integration::file_system::FileProvider; +use crate::ide::integration::file_system::create_node_from_file; use crate::model::execution_context::ComputedValueInfo; use crate::model::execution_context::ExpressionId; use crate::model::execution_context::LocalCall; @@ -49,9 +50,6 @@ use ide_view::graph_editor; use ide_view::searcher::entry::AnyEntryProvider; use utils::iter::split_by_predicate; -pub type Logger = enso_logger::DefaultTraceLogger; - - // ============== @@ -1673,6 +1671,6 @@ impl list_view::entry::EntryProvider for ProjectsToOpen { fn entry_count(&self) -> usize { self.projects.len() } fn get(&self, app: &Application, id: usize) -> Option { - Some(list_view::entry::StringEntry::new(app,self.projects.get(id)?.name.as_ref()).into()) + Some(open_dialog::project_list::Entry::new(app, self.projects.get(id)?.name.as_str()).into()) } } diff --git a/src/rust/ide/view/src/open_dialog.rs b/src/rust/ide/view/src/open_dialog.rs index f1be7599e9..0671e5c14a 100644 --- a/src/rust/ide/view/src/open_dialog.rs +++ b/src/rust/ide/view/src/open_dialog.rs @@ -1,41 +1,41 @@ +pub mod project_list; + use crate::prelude::*; -use enso_frp as frp; use ensogl::display; -use ensogl_gui_components::list_view; -use ensogl_gui_components::list_view::ListView; use ensogl_gui_components::file_browser; use ensogl_gui_components::file_browser::FileBrowser; use ensogl::application::Application; +use ensogl::display::object::Instance; + +const WIDTH:f32 = file_browser::WIDTH + project_list::WIDTH + GAP; +const HEIGHT:f32 = file_browser::HEIGHT; +const GAP:f32 = 16.0; -const PROJECT_LIST_WIDTH:f32 = 202.0; -const WIDTH:f32 = file_browser::WIDTH + PROJECT_LIST_WIDTH; -const HEIGHT:f32 = file_browser::HEIGHT; #[derive(Clone,CloneRef,Debug)] pub struct OpenDialog { - logger : Logger, - pub project_list : ListView, - pub file_browser : FileBrowser, - display_object : display::object::Instance, + logger : Logger, + pub project_list : project_list::ProjectList, + pub file_browser : FileBrowser, + display_object : display::object::Instance, } impl OpenDialog { pub fn new(app:&Application) -> Self { - let logger = Logger::new("OpenDialog"); - let project_list = app.new_view::(); - let file_browser = app.new_view::(); + let logger = Logger::new("OpenDialog"); + let project_list = project_list::ProjectList::new(app); + let file_browser = app.new_view::(); let display_object = display::object::Instance::new(&logger); display_object.add_child(&project_list); - project_list.resize(Vector2(PROJECT_LIST_WIDTH,HEIGHT)); - project_list.set_position_y(-WIDTH / 2.0 + PROJECT_LIST_WIDTH / 2.0); + project_list.set_position_x(-WIDTH / 2.0 + project_list::WIDTH / 2.0); display_object.add_child(&file_browser); - file_browser.set_position_y(WIDTH / 2.0 - file_browser::WIDTH / 2.0); + file_browser.set_position_x(WIDTH / 2.0 - file_browser::WIDTH / 2.0); app.display.scene().layers.panel.add_exclusive(&display_object); diff --git a/src/rust/ide/view/src/open_dialog/project_list.rs b/src/rust/ide/view/src/open_dialog/project_list.rs new file mode 100644 index 0000000000..c8a0644c6a --- /dev/null +++ b/src/rust/ide/view/src/open_dialog/project_list.rs @@ -0,0 +1,133 @@ +use crate::prelude::*; + +use enso_frp as frp; +use ensogl_gui_components::list_view; +use ensogl::application::Application; +use ensogl::display; +use ensogl::display::shape::*; +use ensogl_text as text; +use ensogl_gui_components::file_browser; +use ensogl_gui_components::shadow; +use ensogl_theme as theme; +use ensogl::data::color; + + +pub const WIDTH:f32 = 202.0; +pub const PADDING:f32 = 16.0; +pub const HEIGHT:f32 = file_browser::HEIGHT; +pub const BAR_HEIGHT:f32 = file_browser::TOOLBAR_HEIGHT; +pub const BAR_BORDER_SIZE:f32 = file_browser::TOOLBAR_BORDER_SIZE; +pub const LABEL_SIZE:f32 = list_view::entry::LABEL_SIZE; + + +#[derive(Clone,CloneRef,Debug)] +pub struct Entry { + network : frp::Network, + style_watch : StyleWatchFrp, + label : ensogl_text::Area, +} + +impl Entry { + pub fn new(app:&Application, name:impl Str) -> Self { + let network = frp::Network::new("ProjectEntry"); + let label = app.new_view::(); + let style_watch = StyleWatchFrp::new(&app.display.scene().style_sheet); + let text_color = style_watch.get_color(ensogl_theme::widget::list_view::text); + label.set_default_color(text_color.value()); + label.set_position_xy(Vector2(6.0,6.0)); // TODO[ao] Hmmm... + label.set_content(name.as_ref()); + label.remove_from_scene_layer(&app.display.scene().layers.main); + label.add_to_scene_layer(&app.display.scene().layers.panel_text); + frp::extend! { network + eval text_color ((color) label.set_default_color(color)); + } + Self {network,style_watch,label} + } +} + +impl display::Object for Entry { + fn display_object(&self) -> &display::object::Instance { self.label.display_object() } +} + +impl list_view::entry::Entry for Entry { + fn set_focused(&self, _selected: bool) {} + + fn set_width(&self, _width: f32) {} +} + +mod background { + use super::*; + + pub const SHADOW_PX:f32 = 10.0; + pub const CORNER_RADIUS_PX:f32 = 16.0; + + ensogl::define_shape_system! { + (style:Style) { + let sprite_width : Var = "input_size.x".into(); + let sprite_height : Var = "input_size.y".into(); + let width = sprite_width - SHADOW_PX.px() * 2.0; + let height = sprite_height - SHADOW_PX.px() * 2.0; + let color = style.get_color(theme::application::file_browser::background); + let rect = Rect((&width,&height)).corners_radius(CORNER_RADIUS_PX.px()); + let shape = rect.fill(color); + + let shadow = shadow::from_shape(rect.into(),style); + + let toolbar_border = Rect((width, BAR_BORDER_SIZE.px())) + .translate_y(height / 2.0 - BAR_HEIGHT.px()) + .fill(style.get_color(theme::application::file_browser::toolbar_border_color)); + + (shadow + shape + toolbar_border).into() + } + } +} + + +#[derive(Clone,CloneRef,Debug)] +pub struct ProjectList { + logger : Logger, + display_object : display::object::Instance, + background : background::View, + caption : text::Area, + list : list_view::ListView, +} + +impl Deref for ProjectList { + type Target = list_view::Frp; + + fn deref(&self) -> &Self::Target { &self.list.frp } +} + +impl ProjectList { + pub fn new(app:&Application) -> Self { + let logger = Logger::new("ProjectList"); + let display_object = display::object::Instance::new(&logger); + let background = background::View::new(&logger); + let caption = app.new_view::(); + let list = app.new_view::(); + display_object.add_child(&background); + display_object.add_child(&caption); + display_object.add_child(&list); + app.display.scene().layers.panel.add_exclusive(&display_object); + + background.size.set(Vector2(WIDTH + background::SHADOW_PX * 2.0,HEIGHT + background::SHADOW_PX * 2.0)); + + list.resize(Vector2(WIDTH,HEIGHT-BAR_HEIGHT)); + list.set_position_y(-BAR_HEIGHT/2.0); + + caption.set_position_xy(Vector2(-WIDTH/2.0 + PADDING, HEIGHT/2.0 - PADDING)); + caption.set_default_color(color::Rgba(0.439,0.439,0.439,1.0)); + caption.set_default_text_size(text::Size(LABEL_SIZE)); + caption.set_content("Open Project"); + caption.remove_from_scene_layer(&app.display.scene().layers.main); + caption.add_to_scene_layer(&app.display.scene().layers.panel_text); + + //TODO[ao] update style. + + Self {logger,display_object,background,caption,list} + } +} + +impl display::Object for ProjectList { + fn display_object(&self) -> &display::object::Instance { &self.display_object } +} From fd460a5d7676772d74d56522f783134221a10cbe Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Fri, 9 Jul 2021 15:39:59 +0200 Subject: [PATCH 11/25] Cleanups --- CHANGELOG.md | 8 +++ src/js/lib/project-manager/src/build.ts | 2 +- src/rust/ensogl/lib/theme/src/lib.rs | 19 ++++-- src/rust/ide/src/controller/project.rs | 4 +- src/rust/ide/view/src/open_dialog.rs | 45 ++++++++----- .../ide/view/src/open_dialog/project_list.rs | 66 ++++++++++++------- src/rust/ide/view/src/project.rs | 5 -- 7 files changed, 94 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f52f4ae60..65612bb10e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,19 @@ # Next Release +
![New Features](/docs/assets/tags/new_features.svg) + +- [File or Project Open Dialog][xxxx]. ctrl/cmd+o will + display a new File or Project Open Dialog. Here you can open another project, + or pick a file from browser: the file will be inserted as a node to the + current graph. + # Enso 2.0.0-alpha.8 (2021-06-09)
![New Features](/docs/assets/tags/new_features.svg) #### Visual Environment +<<<<<<< HEAD - [File browser component][1677]. A basic file browser component has been implemented, but is not integrated into the user interface yet. diff --git a/src/js/lib/project-manager/src/build.ts b/src/js/lib/project-manager/src/build.ts index 53d4fb7c0c..c6c4553be8 100644 --- a/src/js/lib/project-manager/src/build.ts +++ b/src/js/lib/project-manager/src/build.ts @@ -44,7 +44,7 @@ async function get_project_manager_url(): Promise { // This constant MUST be synchronized with `ENGINE` constant in src/js/lib/client/tasks/signArchives.js. // Also it is usually a good idea to synchronize it with `ENGINE_VERSION_FOR_NEW_PROJECTS` in // src/rust/ide/src/controller/project.rs. See also https://github.com/enso-org/ide/issues/1359 - const version = '0.2.13-SNAPSHOT.2021-07-06' + const version = '0.2.13' let base_url: string = 'https://github.com/enso-org/' base_url += 'enso/releases/download/' base_url += `enso-${version}/enso-project-manager-${version}` diff --git a/src/rust/ensogl/lib/theme/src/lib.rs b/src/rust/ensogl/lib/theme/src/lib.rs index 1cc1496f58..7c6145545d 100644 --- a/src/rust/ensogl/lib/theme/src/lib.rs +++ b/src/rust/ensogl/lib/theme/src/lib.rs @@ -171,14 +171,23 @@ define_themes! { [light:0, dark:1] background = graph_editor::node::background , graph_editor::node::background; toolbar_border_color = Rgba(0.808,0.808,0.808,1.0) , Rgba(0.808,0.808,0.808,1.0); } + open_dialog { + gap_between_panels = 16.0, 16.0; + } project_list { - width = 202.0 , 202.0; - padding = 16.0, 16.0; - height = 421.0, 421.0; + width = 202.0 , 202.0; + padding = 16.0, 16.0; + height = 421.0, 421.0; + background = application::file_browser::background , application::file_browser::background; + text = widget::list_view::text, widget::list_view::text; bar { - height = 45.0, 45.0; + height = 45.0, 45.0; border_size = 1.0, 1.0; - label_size = 12.0, 12.0; + border_color = application::file_browser::toolbar_border_color, application::file_browser::toolbar_border_color; + label { + size = 12.0, 12.0; + color = Rgba(0.439,0.439,0.439,1.0), Rgba(0.439,0.439,0.439,1.0); + } } } diff --git a/src/rust/ide/src/controller/project.rs b/src/rust/ide/src/controller/project.rs index 7f366e4782..040a9235dd 100644 --- a/src/rust/ide/src/controller/project.rs +++ b/src/rust/ide/src/controller/project.rs @@ -23,12 +23,12 @@ pub const COMPILING_STDLIB_LABEL:&str = "Compiling standard library. It can take /// The requirements for Engine's version, in format understandable by /// [`semver::VersionReq::parse`]. -pub const ENGINE_VERSION_SUPPORTED : &str = "^0.2.13-SNAPSHOT.2021-07-06"; +pub const ENGINE_VERSION_SUPPORTED : &str = "^0.2.13"; /// The Engine version used in projects created in IDE. // Usually it is a good idea to synchronize this version with the bundled Engine version in // src/js/lib/project-manager/src/build.ts. See also https://github.com/enso-org/ide/issues/1359 -pub const ENGINE_VERSION_FOR_NEW_PROJECTS : &str = "0.2.13-SNAPSHOT.2021-07-06"; +pub const ENGINE_VERSION_FOR_NEW_PROJECTS : &str = "0.2.13"; /// The name of the module initially opened in the project view. /// diff --git a/src/rust/ide/view/src/open_dialog.rs b/src/rust/ide/view/src/open_dialog.rs index 0671e5c14a..8e9a7623d5 100644 --- a/src/rust/ide/view/src/open_dialog.rs +++ b/src/rust/ide/view/src/open_dialog.rs @@ -1,45 +1,56 @@ +//! A module with [`OpenDialog`] component. + pub mod project_list; use crate::prelude::*; +use enso_frp as frp; use ensogl::display; use ensogl_gui_components::file_browser; use ensogl_gui_components::file_browser::FileBrowser; use ensogl::application::Application; -use ensogl::display::object::Instance; - - - -const WIDTH:f32 = file_browser::WIDTH + project_list::WIDTH + GAP; -const HEIGHT:f32 = file_browser::HEIGHT; -const GAP:f32 = 16.0; - +use ensogl::display::shape::StyleWatchFrp; +use ensogl_theme as theme; #[derive(Clone,CloneRef,Debug)] pub struct OpenDialog { - logger : Logger, - pub project_list : project_list::ProjectList, - pub file_browser : FileBrowser, - display_object : display::object::Instance, + logger : Logger, + network : frp::Network, + pub project_list : project_list::ProjectList, + pub file_browser : FileBrowser, + display_object : display::object::Instance, + style_watch : StyleWatchFrp, } impl OpenDialog { pub fn new(app:&Application) -> Self { let logger = Logger::new("OpenDialog"); + let network = frp::Network::new("OpenDialog"); + let style_watch = StyleWatchFrp::new(&app.display.scene().style_sheet); let project_list = project_list::ProjectList::new(app); let file_browser = app.new_view::(); let display_object = display::object::Instance::new(&logger); display_object.add_child(&project_list); - project_list.set_position_x(-WIDTH / 2.0 + project_list::WIDTH / 2.0); - display_object.add_child(&file_browser); - file_browser.set_position_x(WIDTH / 2.0 - file_browser::WIDTH / 2.0); - app.display.scene().layers.panel.add_exclusive(&display_object); - Self {logger,project_list,file_browser,display_object} + let project_list_width = style_watch.get_number(theme::application::project_list::width); + let gap_between_panels = style_watch.get_number(theme::application::open_dialog::gap_between_panels); + frp::extend! { network + init <- source::<()>(); + width <- all_with3(&project_list_width,&gap_between_panels,&init, + |pw,g,()| *pw + *g + file_browser::WIDTH + ); + project_list_x <- all_with(&width,&project_list_width,|w,pw| *w / 2.0 + *pw / 2.0); + file_browser_x <- width.map(|w| w / 2.0 - file_browser::WIDTH / 2.0); + + eval project_list_x ((x) project_list.set_position_x(*x)); + eval file_browser_x ((x) file_browser.set_position_x(*x)); + } + + Self {logger,network,project_list,file_browser,display_object,style_watch} } } diff --git a/src/rust/ide/view/src/open_dialog/project_list.rs b/src/rust/ide/view/src/open_dialog/project_list.rs index c8a0644c6a..2e8d1c7cb2 100644 --- a/src/rust/ide/view/src/open_dialog/project_list.rs +++ b/src/rust/ide/view/src/open_dialog/project_list.rs @@ -6,18 +6,10 @@ use ensogl::application::Application; use ensogl::display; use ensogl::display::shape::*; use ensogl_text as text; -use ensogl_gui_components::file_browser; use ensogl_gui_components::shadow; -use ensogl_theme as theme; -use ensogl::data::color; +use ensogl_theme::application::project_list as theme; -pub const WIDTH:f32 = 202.0; -pub const PADDING:f32 = 16.0; -pub const HEIGHT:f32 = file_browser::HEIGHT; -pub const BAR_HEIGHT:f32 = file_browser::TOOLBAR_HEIGHT; -pub const BAR_BORDER_SIZE:f32 = file_browser::TOOLBAR_BORDER_SIZE; -pub const LABEL_SIZE:f32 = list_view::entry::LABEL_SIZE; #[derive(Clone,CloneRef,Debug)] @@ -32,7 +24,7 @@ impl Entry { let network = frp::Network::new("ProjectEntry"); let label = app.new_view::(); let style_watch = StyleWatchFrp::new(&app.display.scene().style_sheet); - let text_color = style_watch.get_color(ensogl_theme::widget::list_view::text); + let text_color = style_watch.get_color(theme::text); label.set_default_color(text_color.value()); label.set_position_xy(Vector2(6.0,6.0)); // TODO[ao] Hmmm... label.set_content(name.as_ref()); @@ -67,15 +59,17 @@ mod background { let sprite_height : Var = "input_size.y".into(); let width = sprite_width - SHADOW_PX.px() * 2.0; let height = sprite_height - SHADOW_PX.px() * 2.0; - let color = style.get_color(theme::application::file_browser::background); + let color = style.get_color(theme::background); + let border_size = style.get_number(theme::bar::border_size); + let bar_height = style.get_number(theme::bar::height); let rect = Rect((&width,&height)).corners_radius(CORNER_RADIUS_PX.px()); let shape = rect.fill(color); let shadow = shadow::from_shape(rect.into(),style); - let toolbar_border = Rect((width, BAR_BORDER_SIZE.px())) - .translate_y(height / 2.0 - BAR_HEIGHT.px()) - .fill(style.get_color(theme::application::file_browser::toolbar_border_color)); + let toolbar_border = Rect((width, border_size.px())) + .translate_y(height / 2.0 - bar_height.px()) + .fill(style.get_color(theme::bar::border_color)); (shadow + shape + toolbar_border).into() } @@ -86,10 +80,12 @@ mod background { #[derive(Clone,CloneRef,Debug)] pub struct ProjectList { logger : Logger, + network : frp::Network, display_object : display::object::Instance, background : background::View, caption : text::Area, list : list_view::ListView, + style_watch : StyleWatchFrp, } impl Deref for ProjectList { @@ -101,6 +97,7 @@ impl Deref for ProjectList { impl ProjectList { pub fn new(app:&Application) -> Self { let logger = Logger::new("ProjectList"); + let network = frp::Network::new("ProjectList"); let display_object = display::object::Instance::new(&logger); let background = background::View::new(&logger); let caption = app.new_view::(); @@ -109,22 +106,41 @@ impl ProjectList { display_object.add_child(&caption); display_object.add_child(&list); app.display.scene().layers.panel.add_exclusive(&display_object); - - background.size.set(Vector2(WIDTH + background::SHADOW_PX * 2.0,HEIGHT + background::SHADOW_PX * 2.0)); - - list.resize(Vector2(WIDTH,HEIGHT-BAR_HEIGHT)); - list.set_position_y(-BAR_HEIGHT/2.0); - - caption.set_position_xy(Vector2(-WIDTH/2.0 + PADDING, HEIGHT/2.0 - PADDING)); - caption.set_default_color(color::Rgba(0.439,0.439,0.439,1.0)); - caption.set_default_text_size(text::Size(LABEL_SIZE)); caption.set_content("Open Project"); caption.remove_from_scene_layer(&app.display.scene().layers.main); caption.add_to_scene_layer(&app.display.scene().layers.panel_text); - //TODO[ao] update style. + let style_watch = StyleWatchFrp::new(&app.display.scene().style_sheet); + let width = style_watch.get_number(theme::width); + let height = style_watch.get_number(theme::height); + let bar_height = style_watch.get_number(theme::bar::height); + let padding = style_watch.get_number(theme::padding); + let color = style_watch.get_color(theme::bar::label::color); + let label_size = style_watch.get_number(theme::bar::label::color); - Self {logger,display_object,background,caption,list} + frp::extend! { network + init <- source::<()>(); + size <- all_with3(&width,&height,&init,|w,h,()| + Vector2(w + background::SHADOW_PX * 2.0,h + background::SHADOW_PX * 2.0) + ); + list_size <- all_with4(&width,&height,&bar_height,&init,|w,h,bh,()| + Vector2(*w,*h - *bh)); + list_y <- bar_height.map(|bh| -*bh / 2.0); + caption_xy <- all_with4(&width,&height,&padding,&init, + |w,h,p,()| Vector2(-*w / 2.0 + *p, *h / 2.0 - p) + ); + color <- all(&color,&init)._0(); + label_size <- all(&label_size,&init)._0(); + + eval size ((size) background.size.set(*size)); + eval list_size ((size) list.resize(*size)); + eval list_y ((y) list.set_position_y(*y)); + eval caption_xy ((xy) caption.set_position_xy(*xy)); + eval color ((color) caption.set_default_color(color)); + eval label_size ((size) caption.set_default_text_size(text::Size(*size))); + }; + + Self {logger,network,display_object,background,caption,list,style_watch} } } diff --git a/src/rust/ide/view/src/project.rs b/src/rust/ide/view/src/project.rs index 8f69f06878..c3ef1b4d8a 100644 --- a/src/rust/ide/view/src/project.rs +++ b/src/rust/ide/view/src/project.rs @@ -97,15 +97,10 @@ mod prompt_background { -// ============= // ============= // === Model === // ============= -struct SubComponents { - -} - #[derive(Clone,CloneRef,Debug)] struct Model { app : Application, From e3054549a9b1bb0a2fc54edfb68149155391f667 Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Fri, 9 Jul 2021 16:52:58 +0200 Subject: [PATCH 12/25] Fix tests --- .../lib/components/src/selector/shape.rs | 1 - .../src/language_server/tests.rs | 7 +- .../ide/src/ide/integration/file_system.rs | 98 ++++++++++++++----- src/rust/ide/src/ide/integration/project.rs | 7 +- src/rust/ide/src/model/project.rs | 6 +- .../ide/src/model/project/synchronized.rs | 10 ++ src/rust/ide/tests/language_server.rs | 4 +- src/rust/ide/view/src/open_dialog.rs | 18 +++- .../ide/view/src/open_dialog/project_list.rs | 24 ++++- 9 files changed, 132 insertions(+), 43 deletions(-) diff --git a/src/rust/ensogl/lib/components/src/selector/shape.rs b/src/rust/ensogl/lib/components/src/selector/shape.rs index 2e28c0bab7..488e95ce91 100644 --- a/src/rust/ensogl/lib/components/src/selector/shape.rs +++ b/src/rust/ensogl/lib/components/src/selector/shape.rs @@ -246,7 +246,6 @@ mod tests { use enso_frp::io::mouse::Button; use enso_frp::stream::EventEmitter; use enso_frp::stream::ValueProvider; - use float_eq::assert_float_eq; #[test] fn test_shape_is_dragged() { diff --git a/src/rust/ide/lib/enso-protocol/src/language_server/tests.rs b/src/rust/ide/lib/enso-protocol/src/language_server/tests.rs index a4a21e15ca..c713246246 100644 --- a/src/rust/ide/lib/enso-protocol/src/language_server/tests.rs +++ b/src/rust/ide/lib/enso-protocol/src/language_server/tests.rs @@ -261,11 +261,7 @@ fn test_file_requests() { #[test] fn test_protocol_connection() { let init_protocol_connection_response = response::InitProtocolConnection { - content_roots: vec![ContentRoot { - id : default(), - content_root_type : ContentRootType::Project, - name : "Project".to_owned() - }] + content_roots: vec![ContentRoot::Project {id:default()}] }; test_request( |client| client.init_protocol_connection(&uuid::Uuid::default()), @@ -277,7 +273,6 @@ fn test_protocol_connection() { "contentRoots" : [{ "id" : "00000000-0000-0000-0000-000000000000", "type" : "Project", - "name" : "Project", }] }), init_protocol_connection_response diff --git a/src/rust/ide/src/ide/integration/file_system.rs b/src/rust/ide/src/ide/integration/file_system.rs index 3380576b94..5a5314f904 100644 --- a/src/rust/ide/src/ide/integration/file_system.rs +++ b/src/rust/ide/src/ide/integration/file_system.rs @@ -1,31 +1,50 @@ +//! The integration between EnsoGL File Browser and the Engine's file management API. + use crate::prelude::*; -use enso_protocol::language_server; +use crate::controller::graph::NewNodeInfo; + use enso_frp as frp; -use enso_protocol::language_server::{FileSystemObject, ContentRoot}; +use enso_protocol::language_server; +use enso_protocol::language_server::ContentRoot; +use enso_protocol::language_server::FileSystemObject; use ensogl_gui_components::file_browser::model::FolderContent; use ensogl_gui_components::file_browser::model::FolderType; use ensogl_gui_components::file_browser::model::Entry; use ensogl_gui_components::file_browser::model::EntryType; use std::iter::once; -use std::ffi::OsString; -use crate::controller::graph::NewNodeInfo; + +// ======================= +// === Path Conversion === +// ======================= + +// === Errors === + #[derive(Clone,Debug,Fail)] #[fail(display="Invalid path received from File Browser Component: {}",path)] struct InvalidPath {path:String} +// === Functions === -fn to_file_browser_path(path:&language_server::Path) -> std::path::PathBuf { - use std::path::Component::*; +/// Translate [`language_server::Path`] to path used by File Browser. +/// +/// The path will be absolute, starting with "/". The first segment will be the content root id. +pub fn to_file_browser_path(path:&language_server::Path) -> std::path::PathBuf { let root_id_str = path.root_id.to_string(); let segments_str = path.segments.iter().map(AsRef::::as_ref); once("/").chain(once(root_id_str.as_ref())).chain(segments_str).collect() } -fn from_file_browser_path(path:&std::path::Path) -> FallibleResult { +/// Translate [`std::path::Path`] received from File Browser to a language server path. +/// +/// The path should br absolute, starting with "/" and first segment should be a valid uuid of the +/// content root. The function returns `Err` if these conditions are not met. +/// +/// Translating back path generated by [`to_file_browser_path`] must not fail. +pub fn from_file_browser_path(path:&std::path::Path) -> FallibleResult { use std::path::Component::*; let mut iter = path.components(); match (iter.next(), iter.next()) { @@ -41,10 +60,32 @@ fn from_file_browser_path(path:&std::path::Path) -> FallibleResult, - pub content_roots : Vec>, + connection : Rc, + content_roots : Vec>, +} + +impl FileProvider { + /// Create provider of all content roots attached to given project. + pub fn new(project:&model::Project) -> Self { + Self { + connection : project.json_rpc(), + content_roots : project.content_roots(), + } + } } impl FolderContent for FileProvider { @@ -78,31 +119,36 @@ impl FolderContent for FileProvider { } } + +// === DirectoryView === + +/// A provider of the content of a specific directory. #[derive(Clone,CloneRef,Debug)] pub struct DirectoryView { connection : Rc, - content_root : Rc, + content_root : Rc, path : Rc, } impl DirectoryView { - fn new_from_root - ( connection : Rc - , content_root : Rc - ) -> Self { + /// Create a view of given Content Root content. + pub fn new_from_root + (connection:Rc, content_root:Rc) -> Self { let path = Rc::new(language_server::Path::new_root(content_root.id())); Self{connection,content_root,path} } - fn sub_view(&self, segment:impl Str) -> DirectoryView { + /// Returns a new view of the content of current's view subdirectory. + pub fn sub_view(&self, sub_dir:impl Str) -> DirectoryView { DirectoryView { connection : self.connection.clone_ref(), content_root : self.content_root.clone_ref(), - path : Rc::new(self.path.append_im(segment)) + path : Rc::new(self.path.append_im(sub_dir)) } } - async fn get_entries_list(&self) -> FallibleResult> { + /// Retrieves the directory content from the Engine. + pub async fn get_entries_list(&self) -> FallibleResult> { let response = self.connection.file_list(&self.path).await?; let entries = response.paths.into_iter().map(|fs_obj| { match fs_obj { @@ -142,16 +188,22 @@ impl FolderContent for DirectoryView { } } -pub fn create_node_from_file(project:&model::Project, graph:&controller::Graph, path:&std::path::Path) -> FallibleResult { +/// Create a node reading the given file. +/// +/// The `path` should be a path convertible to Path from Language Server Protocol - see +/// [`from_file_browser_path`], otherwise function will return `Err`. +pub fn create_node_from_file +(project:&model::Project, graph:&controller::Graph, path:&std::path::Path) -> FallibleResult { let ls_path = from_file_browser_path(path)?; let path_segments = ls_path.segments.into_iter().join("/"); let content_root = project.content_root_by_id(ls_path.root_id)?; let path = match &*content_root { - ContentRoot::Project { .. } => format!("Enso_Project.root/\"{}\"", path_segments), - ContentRoot::FileSystemRoot { path,.. } => format!("\"{}/{}\"", path,path_segments), - ContentRoot::Home { .. } => format!("File.home/\"{}\"", path_segments), - ContentRoot::Library { namespace,name,.. } => format!("{}.{}.Enso_Project.root / \"{}\"",namespace,name,path_segments), - ContentRoot::Custom { .. } => todo!(), + ContentRoot::Project {..} => format!("Enso_Project.root/\"{}\"", path_segments), + ContentRoot::FileSystemRoot {path,..} => format!("\"{}/{}\"", path,path_segments), + ContentRoot::Home {..} => format!("File.home/\"{}\"", path_segments), + ContentRoot::Library { namespace,name,.. } => + format!("{}.{}.Enso_Project.root / \"{}\"",namespace,name,path_segments), + ContentRoot::Custom { .. } => "Unsupported Content Root".to_owned(), }; let expression = format!("File.read {}", path); let node_info = NewNodeInfo::new_pushed_back(expression); diff --git a/src/rust/ide/src/ide/integration/project.rs b/src/rust/ide/src/ide/integration/project.rs index 7bca2311fb..b1aec87562 100644 --- a/src/rust/ide/src/ide/integration/project.rs +++ b/src/rust/ide/src/ide/integration/project.rs @@ -1294,10 +1294,7 @@ impl Model { fn open_dialog_opened_in_ui(self:&Rc) { debug!(self.logger, "Opened file dialog in ui. Providing content root list"); - let provider = FileProvider { - connection: self.project.json_rpc(), - content_roots: self.project.content_roots(), - }; + let provider = FileProvider::new(&self.project); let provider:AnyFolderContent = provider.into(); self.view.open_dialog().file_browser.set_content(provider); let model = Rc::downgrade(self); @@ -1670,7 +1667,7 @@ impl ProjectsToOpen { impl list_view::entry::EntryProvider for ProjectsToOpen { fn entry_count(&self) -> usize { self.projects.len() } - fn get(&self, app: &Application, id: usize) -> Option { + fn get(&self, app: &Application, id: usize) -> Option { Some(open_dialog::project_list::Entry::new(app, self.projects.get(id)?.name.as_str()).into()) } } diff --git a/src/rust/ide/src/model/project.rs b/src/rust/ide/src/model/project.rs index 8a5adf6fd8..6b65448ab5 100644 --- a/src/rust/ide/src/model/project.rs +++ b/src/rust/ide/src/model/project.rs @@ -54,8 +54,10 @@ pub trait API:Debug { /// Get the suggestions database. fn suggestion_db(&self) -> Rc; + /// Get the list of all content roots attached to the project. fn content_roots(&self) -> Vec>; + /// Get content root by id. fn content_root_by_id(&self, id:Uuid) -> FallibleResult>; /// Returns a model of module opened from file. @@ -183,9 +185,9 @@ pub mod test { .returning_st(move |_root_definition| ready(Ok(ctx2.clone_ref())).boxed_local()); } - /// Sets up root id expectation on the mock project, returning a given id. + /// Sets up project root id expectation on the mock project, returning a given id. pub fn expect_root_id(project:&mut MockAPI, root_id:Uuid) { - project.expect_content_root_id().return_const(root_id); + project.expect_project_content_root_id().return_const(root_id); } /// Sets up suggestion database expectation on the mock project, returning a given database. diff --git a/src/rust/ide/src/model/project/synchronized.rs b/src/rust/ide/src/model/project/synchronized.rs index 79b5d9a5f4..c76178db22 100644 --- a/src/rust/ide/src/model/project/synchronized.rs +++ b/src/rust/ide/src/model/project/synchronized.rs @@ -98,6 +98,7 @@ impl ExecutionContextsRegistry { #[fail(display="Content root {} does not exist.",id)] struct MissingContentRoot {id:Uuid} +/// A repository of content roots attached to a specific project. #[derive(Clone,Debug)] pub struct ContentRoots { logger : Logger, @@ -105,6 +106,7 @@ pub struct ContentRoots { } impl ContentRoots { + /// Create ContentRoots, initializing with the roots retrieved during connection initialization. pub fn new_from_connection (parent:impl AnyLogger, connection:&language_server::Connection) -> Self { let logger = Logger::sub(parent,"ContentRoots"); @@ -113,10 +115,14 @@ impl ContentRoots { Self{logger,roots} } + /// Return all content roots. pub fn all(&self) -> Vec> { self.roots.borrow().values().cloned().collect() } + /// Add a new content root. + /// + /// If there is already a root with given id, it will be replaced and warning will be printed. pub fn add(&self, content_root:ContentRoot) { let content_root = Rc::new(content_root); if let Some(existing) = self.roots.borrow_mut().insert(content_root.id(),content_root) { @@ -125,10 +131,14 @@ impl ContentRoots { } } + /// Get content root by id. pub fn get(&self, id:Uuid) -> FallibleResult> { self.roots.borrow().get(&id).cloned().ok_or_else(|| MissingContentRoot{id}.into()) } + /// Remove the content root with given id. + /// + /// If there is no content root with such id, a warning will be printed. pub fn remove(&self, id:Uuid) { if self.roots.borrow_mut().remove(&id).is_none() { warning!(self.logger,"Removing content root: no content root with given id: {id}"); diff --git a/src/rust/ide/tests/language_server.rs b/src/rust/ide/tests/language_server.rs index 91ffd3fbef..bd424cf24b 100644 --- a/src/rust/ide/tests/language_server.rs +++ b/src/rust/ide/tests/language_server.rs @@ -239,7 +239,7 @@ async fn file_events() { let client_id = uuid::Uuid::default(); let session = client.init_protocol_connection(&client_id).await; let session = session.expect("Couldn't initialize session."); - let root_id = session.content_roots[0].id; + let root_id = session.content_roots[0].id(); let path = Path{root_id,segments:vec!["test.txt".into()]}; let file = client.file_exists(&path).await; @@ -297,7 +297,7 @@ async fn file_operations_test() { let project = ide.current_project(); info!(logger,"Got project: {project:?}"); // Edit file using the text protocol - let path = Path::new(project.json_rpc().project_root().id, &["test_file.txt"]); + let path = Path::new(project.json_rpc().project_root().id(), &["test_file.txt"]); let contents = "Hello, 世界!".to_string(); let written = project.json_rpc().write_file(&path,&contents).await.unwrap(); info!(logger,"Written: {written:?}"); diff --git a/src/rust/ide/view/src/open_dialog.rs b/src/rust/ide/view/src/open_dialog.rs index 8e9a7623d5..9b6ce97c7c 100644 --- a/src/rust/ide/view/src/open_dialog.rs +++ b/src/rust/ide/view/src/open_dialog.rs @@ -1,5 +1,4 @@ //! A module with [`OpenDialog`] component. - pub mod project_list; use crate::prelude::*; @@ -13,6 +12,17 @@ use ensogl::display::shape::StyleWatchFrp; use ensogl_theme as theme; + +// ================== +// === OpenDialog === +// ================== + +/// An Open Dialog GUI component. +/// +/// This is component bounding together projects-to-open list and the file browser. It does not +/// provide frp endpoints by its own: you should just go directly to the `project_list` or +/// `file_browser` field. +#[allow(missing_docs)] #[derive(Clone,CloneRef,Debug)] pub struct OpenDialog { logger : Logger, @@ -24,6 +34,7 @@ pub struct OpenDialog { } impl OpenDialog { + /// Create Open Dialog component. pub fn new(app:&Application) -> Self { let logger = Logger::new("OpenDialog"); let network = frp::Network::new("OpenDialog"); @@ -36,8 +47,9 @@ impl OpenDialog { display_object.add_child(&file_browser); app.display.scene().layers.panel.add_exclusive(&display_object); - let project_list_width = style_watch.get_number(theme::application::project_list::width); - let gap_between_panels = style_watch.get_number(theme::application::open_dialog::gap_between_panels); + use theme::application as theme_app; + let project_list_width = style_watch.get_number(theme_app::project_list::width); + let gap_between_panels = style_watch.get_number(theme_app::open_dialog::gap_between_panels); frp::extend! { network init <- source::<()>(); width <- all_with3(&project_list_width,&gap_between_panels,&init, diff --git a/src/rust/ide/view/src/open_dialog/project_list.rs b/src/rust/ide/view/src/open_dialog/project_list.rs index 2e8d1c7cb2..bb94c8c1f7 100644 --- a/src/rust/ide/view/src/open_dialog/project_list.rs +++ b/src/rust/ide/view/src/open_dialog/project_list.rs @@ -1,3 +1,5 @@ +//! A module containing [`ProjectList`] component and all related structures. + use crate::prelude::*; use enso_frp as frp; @@ -11,7 +13,11 @@ use ensogl_theme::application::project_list as theme; +// ============= +// === Entry === +// ============= +/// The project entry widget for the [`list_view::ListView`] inside [`ProjectList`]. #[derive(Clone,CloneRef,Debug)] pub struct Entry { network : frp::Network, @@ -20,6 +26,7 @@ pub struct Entry { } impl Entry { + /// Create entry for a project with given name. pub fn new(app:&Application, name:impl Str) -> Self { let network = frp::Network::new("ProjectEntry"); let label = app.new_view::(); @@ -47,6 +54,12 @@ impl list_view::entry::Entry for Entry { fn set_width(&self, _width: f32) {} } + + +// ============== +// === Shapes === +// ============== + mod background { use super::*; @@ -77,12 +90,20 @@ mod background { } + +// =================== +// === ProjectList === +// =================== + +/// The Project List GUI Component. +/// +/// This is a list of projects in a nice frame with title. #[derive(Clone,CloneRef,Debug)] pub struct ProjectList { logger : Logger, network : frp::Network, display_object : display::object::Instance, - background : background::View, + background : background::View, //TODO[ao] use Card instead. caption : text::Area, list : list_view::ListView, style_watch : StyleWatchFrp, @@ -95,6 +116,7 @@ impl Deref for ProjectList { } impl ProjectList { + /// Create Project List Component. pub fn new(app:&Application) -> Self { let logger = Logger::new("ProjectList"); let network = frp::Network::new("ProjectList"); From 0da74a2d03e96f630f1df3e0c5b14618209e177d Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Mon, 12 Jul 2021 12:07:54 +0200 Subject: [PATCH 13/25] Support for cut/copy/paste --- src/rust/ide/src/controller/upload.rs | 37 ++++++++--- .../ide/src/ide/integration/file_system.rs | 62 +++++++++++++++++++ src/rust/ide/src/ide/integration/project.rs | 34 ++++++++-- 3 files changed, 118 insertions(+), 15 deletions(-) diff --git a/src/rust/ide/src/controller/upload.rs b/src/rust/ide/src/controller/upload.rs index 1bb2ce4de8..29aa83dd3a 100644 --- a/src/rust/ide/src/controller/upload.rs +++ b/src/rust/ide/src/controller/upload.rs @@ -267,16 +267,7 @@ impl NodeFromDroppedFileHandler { } async fn establish_remote_file_name(&self, original_name:&str) -> FallibleResult { - let list_response = self.project.json_rpc().client.file_list(&self.data_path()).await?; - let files_list = list_response.paths.into_iter().map(|f| f.take_name()); - let files_in_data_dir = files_list.collect::>(); - let extension_sep = original_name.rfind('.').filter(|i| *i > 0); - let name_stem = extension_sep.map_or(original_name, |i| &original_name[0..i]); - let name_ext = extension_sep.map_or("", |i| &original_name[i..]); - let first_candidate = std::iter::once(original_name.to_owned()); - let next_candidates = (1..).map(|num| iformat!("{name_stem}_{num}{name_ext}")); - let mut candidates = first_candidate.chain(next_candidates); - Ok(candidates.find(|name| !files_in_data_dir.contains(name)).unwrap()) + pick_non_colliding_name(&*self.project.json_rpc(),&self.data_path(),original_name).await } async fn ensure_data_directory_exists(&self) -> FallibleResult { @@ -321,6 +312,32 @@ impl undo_redo::Aware for NodeFromDroppedFileHandler { +// ====================================== +// === File Name Collisions Resolving === +// ====================================== + +/// Return the name derived from `original_name` which does not collide with any other file in +/// directory under `path`. +/// +/// The directory content is retrieve from the Engine. If there is no colliding file, this function +/// will return the orignal name. Otherwise it adds to its stem a first non-colliding numeric +/// prefix. +pub async fn pick_non_colliding_name +(json_rpc:&language_server::Connection, path:&Path, original_name:&str) -> FallibleResult { + let list_response = json_rpc.client.file_list(path).await?; + let files_list = list_response.paths.into_iter().map(|f| f.take_name()); + let files_in_data_dir = files_list.collect::>(); + let extension_sep = original_name.rfind('.').filter(|i| *i > 0); + let name_stem = extension_sep.map_or(original_name, |i| &original_name[0..i]); + let name_ext = extension_sep.map_or("", |i| &original_name[i..]); + let first_candidate = std::iter::once(original_name.to_owned()); + let next_candidates = (1..).map(|num| iformat!("{name_stem}_{num}{name_ext}")); + let mut candidates = first_candidate.chain(next_candidates); + Ok(candidates.find(|name| !files_in_data_dir.contains(name)).unwrap()) +} + + + // ============ // === Test === // ============ diff --git a/src/rust/ide/src/ide/integration/file_system.rs b/src/rust/ide/src/ide/integration/file_system.rs index 5a5314f904..e61a080427 100644 --- a/src/rust/ide/src/ide/integration/file_system.rs +++ b/src/rust/ide/src/ide/integration/file_system.rs @@ -3,6 +3,7 @@ use crate::prelude::*; use crate::controller::graph::NewNodeInfo; +use crate::controller::upload::pick_non_colliding_name; use enso_frp as frp; use enso_protocol::language_server; @@ -188,6 +189,22 @@ impl FolderContent for DirectoryView { } } + + +// ==================== +// === User Actions === +// ==================== + +// === Errors === + +#[derive(Clone,Debug,Fail)] +#[fail(display="Invalid source file for copy/move operation: {}", path)] +// the path is a String here, because there is no Display for path_buf. +struct InvalidSourceFile {path:String} + + +// === create_node_from_file === + /// Create a node reading the given file. /// /// The `path` should be a path convertible to Path from Language Server Protocol - see @@ -210,3 +227,48 @@ pub fn create_node_from_file graph.add_node(node_info)?; Ok(()) } + + +// === copy_or_move_file === + +/// A enum describing if we want to copy or move file. +#[allow(missing_docs)] +#[derive(Copy,Clone,Debug)] +pub enum FileOperation {Copy,Move} + +impl Default for FileOperation { fn default() -> Self {Self::Copy} } + +impl FileOperation { + /// Returns a verb describing the operation ("copy" or "move"), to be used in diagnostic + /// messages. + pub fn verb(&self) -> &'static str { + match self { + Self::Copy => "copy", + Self::Move => "move" + } + } +} + +/// Do copy or move file operation. The destination must be a directory. If the destination already +/// contains file with the same name as source's, the moved/copy file name will be altered +/// according to algorithm described in [`pick_non_colliding_name`] docs. +pub async fn do_file_operation +( project : &model::Project +, source : &std::path::Path +, dest_dir : &std::path::Path +, operation : FileOperation +) -> FallibleResult { + let json_rpc = project.json_rpc(); + let ls_source = from_file_browser_path(source)?; + let ls_dest = from_file_browser_path(dest_dir)?; + let src_name = ls_source.file_name().ok_or_else( + || InvalidSourceFile{path:source.to_string_lossy().to_string()} + )?; + let dest_name = pick_non_colliding_name(&*json_rpc,&ls_dest,&src_name).await?; + let dest_full = ls_dest.append_im(dest_name); + match operation { + FileOperation::Copy => json_rpc.copy_file(&ls_source, &dest_full).await?, + FileOperation::Move => json_rpc.move_file(&ls_source, &dest_full).await?, + } + Ok(()) +} \ No newline at end of file diff --git a/src/rust/ide/src/ide/integration/project.rs b/src/rust/ide/src/ide/integration/project.rs index b1aec87562..96f93859d9 100644 --- a/src/rust/ide/src/ide/integration/project.rs +++ b/src/rust/ide/src/ide/integration/project.rs @@ -16,6 +16,8 @@ use crate::controller::upload; use crate::controller::upload::NodeFromDroppedFileHandler; use crate::ide::integration::file_system::FileProvider; use crate::ide::integration::file_system::create_node_from_file; +use crate::ide::integration::file_system::FileOperation; +use crate::ide::integration::file_system::do_file_operation; use crate::model::execution_context::ComputedValueInfo; use crate::model::execution_context::ExpressionId; use crate::model::execution_context::LocalCall; @@ -305,14 +307,36 @@ impl Integration { // === Open File or Project Dialog === + let file_browser = &model.view.open_dialog().file_browser; + let project_list = &model.view.open_dialog().project_list; frp::extend! { network - let chosen_project = model.view.open_dialog().project_list.chosen_entry.clone_ref(); - let file_chosen = model.view.open_dialog().file_browser.entry_chosen.clone_ref(); + let chosen_project = project_list.chosen_entry.clone_ref(); + let file_chosen = file_browser.entry_chosen.clone_ref(); project_chosen <- chosen_project.filter_map(|p| *p); dialog_is_shown <- project_frp.open_dialog_shown.filter(|v| *v); - eval_ dialog_is_shown (model.open_dialog_opened_in_ui()); - eval project_chosen ((id) model.project_opened_in_ui(id)); - eval file_chosen ((path) model.file_opened_in_ui(path)); + eval_ dialog_is_shown ( model.open_dialog_opened_in_ui()); + eval project_chosen ((id) model.project_opened_in_ui(id)); + eval file_chosen ((path) model.file_opened_in_ui(path)); + + file_copied <- file_browser.copy.map(|p| (p.clone(),FileOperation::Copy)); + file_cut <- file_browser.cut .map(|p| (p.clone(),FileOperation::Move)); + source_operation <- any(file_copied,file_cut); + file_operation <- file_browser.paste_into.map2(&source_operation, + |dest,(src,op)| (src.clone(),dest.clone(),*op) + ); + eval file_operation ([model]((src,dest,op)) + let logger = model.logger.clone_ref(); + let project = model.project.clone_ref(); + let source = src.clone(); + let dest = dest.clone(); + let operation = *op; + executor::global::spawn(async move { + if let Err(err) = do_file_operation(&project,&source,&dest,operation).await { + error!(logger, "Failed to {operation.verb()} file: {err}"); + } + }) + + ); } From 759939ba4fe559c8e6d1af1c4bf5879b3cba2174 Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Mon, 12 Jul 2021 12:56:59 +0200 Subject: [PATCH 14/25] Fix imports after merge --- src/rust/ide/src/ide/integration/project.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/rust/ide/src/ide/integration/project.rs b/src/rust/ide/src/ide/integration/project.rs index 96f93859d9..02eafd25d3 100644 --- a/src/rust/ide/src/ide/integration/project.rs +++ b/src/rust/ide/src/ide/integration/project.rs @@ -50,6 +50,7 @@ use ide_view::graph_editor::component::node; use ide_view::graph_editor::component::visualization; use ide_view::graph_editor; use ide_view::searcher::entry::AnyEntryProvider; +use ide_view::open_dialog; use utils::iter::split_by_predicate; From 267c5a9379cfee35f364cb5d47e802143dd89923 Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Mon, 12 Jul 2021 13:35:32 +0200 Subject: [PATCH 15/25] Self-review --- CHANGELOG.md | 17 ++++++++++------- docs/CONTRIBUTING.md | 1 - src/rust/Cargo.toml | 2 +- .../ensogl/lib/components/src/file_browser.rs | 2 +- .../lib/components/src/list_view/entry.rs | 4 ++-- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65612bb10e..ca9ebba436 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,22 +1,25 @@ # Next Release +This update contains major performance improvements and exposes new privacy user +settings. We will work towards stabilizing it in the next weeks in order to make +these updates be shipped in a stable release before the end of the year. +
![New Features](/docs/assets/tags/new_features.svg) - [File or Project Open Dialog][xxxx]. ctrl/cmd+o will display a new File or Project Open Dialog. Here you can open another project, or pick a file from browser: the file will be inserted as a node to the current graph. +- [File browser component][1677]. A basic file browser component has been + implemented, but is not integrated into the user interface yet. + +[1640]: https://github.com/enso-org/ide/pull/1664 +[1700]: https://github.com/enso-org/ide/pull/1700 # Enso 2.0.0-alpha.8 (2021-06-09)
![New Features](/docs/assets/tags/new_features.svg) -#### Visual Environment - -<<<<<<< HEAD -- [File browser component][1677]. A basic file browser component has been - implemented, but is not integrated into the user interface yet. - #### Enso Compiler - [Updated Enso engine to version 0.2.12][1640]. If you're interested in the @@ -24,7 +27,7 @@ details in [the engine release notes](https://github.com/enso-org/enso/blob/main/RELEASES.md). -[1640]: https://github.com/enso-org/ide/pull/1664 +
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index bb041f3cc5..c6e5ac4a71 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -1,4 +1,3 @@ - --- layout: developer-doc title: Development & Contributing Guide diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 620251d924..3b4cb81aa2 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -35,7 +35,7 @@ members = [ ] [profile.dev] -opt-level = 2 +opt-level = 0 lto = false debug = true diff --git a/src/rust/ensogl/lib/components/src/file_browser.rs b/src/rust/ensogl/lib/components/src/file_browser.rs index 2656f9d5c6..b48aad161a 100644 --- a/src/rust/ensogl/lib/components/src/file_browser.rs +++ b/src/rust/ensogl/lib/components/src/file_browser.rs @@ -189,7 +189,7 @@ ensogl_core::define_endpoints! { paste_into_focused (), } - Output { [TRACE_ALL] + Output { entry_selected (PathBuf), entry_chosen (PathBuf), diff --git a/src/rust/ensogl/lib/components/src/list_view/entry.rs b/src/rust/ensogl/lib/components/src/list_view/entry.rs index 9c974de2dd..1f7db78202 100644 --- a/src/rust/ensogl/lib/components/src/list_view/entry.rs +++ b/src/rust/ensogl/lib/components/src/list_view/entry.rs @@ -131,14 +131,14 @@ impl EntryProvider for EmptyProvider { // === StringEntry === -#[derive(Clone,CloneRef,Debug)] +#[derive(Debug)] struct StringEntry { display_object : display::object::Instance, label : text::Area, } impl StringEntry { - pub fn new(app:&Application, string:&str) -> Self { + fn new(app:&Application, string:&str) -> Self { let logger = Logger::new("StringEntry"); let display_object = display::object::Instance::new(logger); From 508ffcca8fb5916036fcae832fc04afb6275a606 Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Mon, 12 Jul 2021 16:52:48 +0200 Subject: [PATCH 16/25] Fixes --- src/rust/ensogl/lib/theme/src/lib.rs | 6 ++- src/rust/ide/src/ide/integration/project.rs | 2 +- src/rust/ide/view/src/open_dialog.rs | 4 +- .../ide/view/src/open_dialog/project_list.rs | 45 +++++++++++++------ 4 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/rust/ensogl/lib/theme/src/lib.rs b/src/rust/ensogl/lib/theme/src/lib.rs index 7c6145545d..97aa89acdc 100644 --- a/src/rust/ensogl/lib/theme/src/lib.rs +++ b/src/rust/ensogl/lib/theme/src/lib.rs @@ -178,8 +178,12 @@ define_themes! { [light:0, dark:1] width = 202.0 , 202.0; padding = 16.0, 16.0; height = 421.0, 421.0; - background = application::file_browser::background , application::file_browser::background; + background = Rgba(0.992,0.996,1.0,1.0), Rgba(0.182,0.188,0.196,1.0); text = widget::list_view::text, widget::list_view::text; + text { + size = 12.0, 12.0; + padding = 6.0 , 6.0 ; + } bar { height = 45.0, 45.0; border_size = 1.0, 1.0; diff --git a/src/rust/ide/src/ide/integration/project.rs b/src/rust/ide/src/ide/integration/project.rs index 02eafd25d3..b399813ad3 100644 --- a/src/rust/ide/src/ide/integration/project.rs +++ b/src/rust/ide/src/ide/integration/project.rs @@ -310,7 +310,7 @@ impl Integration { let file_browser = &model.view.open_dialog().file_browser; let project_list = &model.view.open_dialog().project_list; - frp::extend! { network + frp::extend! { TRACE_ALL network let chosen_project = project_list.chosen_entry.clone_ref(); let file_chosen = file_browser.entry_chosen.clone_ref(); project_chosen <- chosen_project.filter_map(|p| *p); diff --git a/src/rust/ide/view/src/open_dialog.rs b/src/rust/ide/view/src/open_dialog.rs index 9b6ce97c7c..0c88490b76 100644 --- a/src/rust/ide/view/src/open_dialog.rs +++ b/src/rust/ide/view/src/open_dialog.rs @@ -55,13 +55,13 @@ impl OpenDialog { width <- all_with3(&project_list_width,&gap_between_panels,&init, |pw,g,()| *pw + *g + file_browser::WIDTH ); - project_list_x <- all_with(&width,&project_list_width,|w,pw| *w / 2.0 + *pw / 2.0); + project_list_x <- all_with(&width,&project_list_width,|w,pw| - *w / 2.0 + *pw / 2.0); file_browser_x <- width.map(|w| w / 2.0 - file_browser::WIDTH / 2.0); eval project_list_x ((x) project_list.set_position_x(*x)); eval file_browser_x ((x) file_browser.set_position_x(*x)); } - + init.emit(()); Self {logger,network,project_list,file_browser,display_object,style_watch} } } diff --git a/src/rust/ide/view/src/open_dialog/project_list.rs b/src/rust/ide/view/src/open_dialog/project_list.rs index bb94c8c1f7..f889adbe53 100644 --- a/src/rust/ide/view/src/open_dialog/project_list.rs +++ b/src/rust/ide/view/src/open_dialog/project_list.rs @@ -20,32 +20,41 @@ use ensogl_theme::application::project_list as theme; /// The project entry widget for the [`list_view::ListView`] inside [`ProjectList`]. #[derive(Clone,CloneRef,Debug)] pub struct Entry { - network : frp::Network, - style_watch : StyleWatchFrp, - label : ensogl_text::Area, + display_object : display::object::Instance, + network : frp::Network, + style_watch : StyleWatchFrp, + label : ensogl_text::Area, } impl Entry { /// Create entry for a project with given name. pub fn new(app:&Application, name:impl Str) -> Self { - let network = frp::Network::new("ProjectEntry"); - let label = app.new_view::(); - let style_watch = StyleWatchFrp::new(&app.display.scene().style_sheet); - let text_color = style_watch.get_color(theme::text); + let logger = Logger::new("project_list::Entry"); + let display_object = display::object::Instance::new(logger); + let network = frp::Network::new("project_list::Entry"); + let label = app.new_view::(); + let style_watch = StyleWatchFrp::new(&app.display.scene().style_sheet); + let text_color = style_watch.get_color(theme::text); + let text_size = style_watch.get_number(theme::text::size); + let text_padding = style_watch.get_number(theme::text::padding); + display_object.add_child(&label); label.set_default_color(text_color.value()); - label.set_position_xy(Vector2(6.0,6.0)); // TODO[ao] Hmmm... + label.set_default_text_size(text::Size(text_size.value())); + label.set_position_xy(Vector2(text_padding.value(), text_size.value() / 2.0)); label.set_content(name.as_ref()); label.remove_from_scene_layer(&app.display.scene().layers.main); label.add_to_scene_layer(&app.display.scene().layers.panel_text); frp::extend! { network - eval text_color ((color) label.set_default_color(color)); + eval text_color ((color) label.set_default_color(color)); + eval text_size ((size) label.set_default_text_size(text::Size(*size))); + eval text_padding ((padding) label.set_position_x(*padding)); } - Self {network,style_watch,label} + Self {display_object,network,style_watch,label} } } impl display::Object for Entry { - fn display_object(&self) -> &display::object::Instance { self.label.display_object() } + fn display_object(&self) -> &display::object::Instance { &self.display_object } } impl list_view::entry::Entry for Entry { @@ -132,22 +141,29 @@ impl ProjectList { caption.remove_from_scene_layer(&app.display.scene().layers.main); caption.add_to_scene_layer(&app.display.scene().layers.panel_text); + ensogl::shapes_order_dependencies! { + app.display.scene() => { + background -> list_view::io_rect; + background -> list_view::selection; + } + } + let style_watch = StyleWatchFrp::new(&app.display.scene().style_sheet); let width = style_watch.get_number(theme::width); let height = style_watch.get_number(theme::height); let bar_height = style_watch.get_number(theme::bar::height); let padding = style_watch.get_number(theme::padding); let color = style_watch.get_color(theme::bar::label::color); - let label_size = style_watch.get_number(theme::bar::label::color); + let label_size = style_watch.get_number(theme::bar::label::size); - frp::extend! { network + frp::extend! { TRACE_ALL network init <- source::<()>(); size <- all_with3(&width,&height,&init,|w,h,()| Vector2(w + background::SHADOW_PX * 2.0,h + background::SHADOW_PX * 2.0) ); list_size <- all_with4(&width,&height,&bar_height,&init,|w,h,bh,()| Vector2(*w,*h - *bh)); - list_y <- bar_height.map(|bh| -*bh / 2.0); + list_y <- all_with(&bar_height,&init, |bh,()| -*bh / 2.0); caption_xy <- all_with4(&width,&height,&padding,&init, |w,h,p,()| Vector2(-*w / 2.0 + *p, *h / 2.0 - p) ); @@ -161,6 +177,7 @@ impl ProjectList { eval color ((color) caption.set_default_color(color)); eval label_size ((size) caption.set_default_text_size(text::Size(*size))); }; + init.emit(()); Self {logger,network,display_object,background,caption,list,style_watch} } From afd8b3836e81d090a0f1e12c4865a6b30afb5932 Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Mon, 12 Jul 2021 18:00:39 +0200 Subject: [PATCH 17/25] Tried fix for screen_to_object_space --- CHANGELOG.md | 2 -- .../lib/core/src/display/object/class.rs | 19 ++++++++++++++++++- src/rust/ensogl/lib/core/src/display/scene.rs | 4 +++- src/rust/ide/src/ide/integration/project.rs | 15 ++++++++++----- src/rust/ide/view/src/project.rs | 2 ++ 5 files changed, 33 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca9ebba436..2171b472d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,8 +27,6 @@ these updates be shipped in a stable release before the end of the year. details in [the engine release notes](https://github.com/enso-org/enso/blob/main/RELEASES.md). - -
# Enso 2.0.0-alpha.7 (2021-06-06) diff --git a/src/rust/ensogl/lib/core/src/display/object/class.rs b/src/rust/ensogl/lib/core/src/display/object/class.rs index da5b24ceaf..22bcffcff4 100644 --- a/src/rust/ensogl/lib/core/src/display/object/class.rs +++ b/src/rust/ensogl/lib/core/src/display/object/class.rs @@ -196,6 +196,9 @@ pub struct Model { transform : RefCell , visible : Cell , logger : Logger, + /// The first layer on the layers this object actually belongs to. + //TODO[ao] this is a workaround for screen_to_object_pos method. + main_layer : Cell>, } impl Model { @@ -210,7 +213,9 @@ impl Model { let callbacks = default(); let host = default(); let scene_layers = default(); - Self {host,scene_layers,dirty,callbacks,parent_bind,children,transform,visible,logger} + let main_layer = default(); + Self {host,scene_layers,dirty,callbacks,parent_bind,children,transform,visible,logger + ,main_layer} } /// Checks whether the object is visible. @@ -295,6 +300,7 @@ impl Model { }; if scene_layers_changed { debug!(self.logger, "Scene layers changed.", || { + self.main_layer.set(scene_layers.first().copied()); self.callbacks.on_scene_layers_changed(host,scene_layers); }); } @@ -602,6 +608,10 @@ impl Instance { Id(Rc::downgrade(&self.rc).as_ptr() as *const() as usize) } + /// Get the first layer where this object is actually displayed. + //TODO[ao] this is workaround for `screen_to_object_space` method. + pub fn _main_layer(&self) -> Option { self.main_layer.get() } + /// Add this object to the provided scene layer and remove it from all other layers. Do not use /// this method explicitly. Use layers' methods instead. pub(crate) fn add_to_scene_layer(&self, layer:LayerId) { @@ -609,6 +619,7 @@ impl Instance { let mut scene_layers = self.scene_layers.borrow_mut(); if !scene_layers.contains(&layer) { scene_layers.push(layer); + self.main_layer.set(scene_layers.first().copied()); } } @@ -617,6 +628,7 @@ impl Instance { pub(crate) fn add_to_scene_layer_exclusive(&self, layer:LayerId) { self.dirty.scene_layer.set(); *self.scene_layers.borrow_mut() = vec![layer]; + self.main_layer.set(Some(layer)); } /// Remove this object from the provided scene layer. Do not use this method explicitly. Use @@ -624,6 +636,7 @@ impl Instance { pub(crate) fn remove_from_scene_layer(&self, layer:LayerId) { self.dirty.scene_layer.set(); self.scene_layers.borrow_mut().remove_item(&layer); + self.main_layer.set(self.scene_layers.borrow().first().copied()); } /// Adds a new `Object` as a child to the current one. @@ -809,6 +822,10 @@ pub trait ObjectOps : Object { self.display_object()._id() } + /// Get the first layer where this object is actually displayed. + //TODO[ao] this is workaround for `screen_to_object_space` method. + fn main_layer(&self) -> Option { self.display_object()._main_layer() } + /// Add another display object as a child to this display object. Children will inherit all /// transformations of their parents. fn add_child>(&self, child:&T) { diff --git a/src/rust/ensogl/lib/core/src/display/scene.rs b/src/rust/ensogl/lib/core/src/display/scene.rs index e24b283f2a..f26f428d69 100644 --- a/src/rust/ensogl/lib/core/src/display/scene.rs +++ b/src/rust/ensogl/lib/core/src/display/scene.rs @@ -911,7 +911,9 @@ impl SceneData { pub fn screen_to_object_space (&self, object:&impl display::Object, screen_pos:Vector2) -> Vector2 { let origin_world_space = Vector4(0.0,0.0,0.0,1.0); - let origin_clip_space = self.camera().view_projection_matrix() * origin_world_space; + let layer = object.main_layer().and_then(|id| self.layers.get(id)); + let camera = layer.map_or(self.camera(), |l| l.camera()); + let origin_clip_space = camera.view_projection_matrix() * origin_world_space; let inv_object_matrix = object.transform_matrix().try_inverse().unwrap(); let shape = self.frp.shape.value(); diff --git a/src/rust/ide/src/ide/integration/project.rs b/src/rust/ide/src/ide/integration/project.rs index b399813ad3..8f96a5a5c7 100644 --- a/src/rust/ide/src/ide/integration/project.rs +++ b/src/rust/ide/src/ide/integration/project.rs @@ -38,7 +38,6 @@ use ensogl::display::traits::*; use ensogl::display; use ensogl_gui_components::file_browser::model::AnyFolderContent; use ensogl_gui_components::list_view; -use ensogl_gui_components::list_view::entry::AnyEntry; use ensogl_text as text; use ensogl_web::drop; use futures::future::LocalBoxFuture; @@ -331,9 +330,12 @@ impl Integration { let source = src.clone(); let dest = dest.clone(); let operation = *op; + let model = model.clone_ref(); executor::global::spawn(async move { if let Err(err) = do_file_operation(&project,&source,&dest,operation).await { error!(logger, "Failed to {operation.verb()} file: {err}"); + } else { + model.reload_files_in_file_browser(); } }) @@ -1319,11 +1321,8 @@ impl Model { fn open_dialog_opened_in_ui(self:&Rc) { debug!(self.logger, "Opened file dialog in ui. Providing content root list"); - let provider = FileProvider::new(&self.project); - let provider:AnyFolderContent = provider.into(); - self.view.open_dialog().file_browser.set_content(provider); + self.reload_files_in_file_browser(); let model = Rc::downgrade(self); - executor::global::spawn(async move { if let Some(this) = model.upgrade() { if let Ok(manage_projects) = this.ide.manage_projects() { @@ -1341,6 +1340,12 @@ impl Model { }); } + fn reload_files_in_file_browser(&self) { + let provider = FileProvider::new(&self.project); + let provider:AnyFolderContent = provider.into(); + self.view.open_dialog().file_browser.set_content(provider); + } + fn project_opened_in_ui(&self, entry_id:&list_view::entry::Id) { if let Some(id) = self.displayed_project_list.get().get_project_id_by_index(*entry_id) { let logger = self.logger.clone_ref(); diff --git a/src/rust/ide/view/src/project.rs b/src/rust/ide/view/src/project.rs index c3ef1b4d8a..ba905aa04b 100644 --- a/src/rust/ide/view/src/project.rs +++ b/src/rust/ide/view/src/project.rs @@ -150,6 +150,7 @@ impl Model { display_object.add_child(&status_bar); display_object.add_child(&prompt_background); display_object.remove_child(&searcher); + let app = app.clone_ref(); let graph_editor = Rc::new(graph_editor); Self{app,logger,display_object,window_control_buttons,graph_editor,searcher,code_editor, @@ -604,6 +605,7 @@ impl application::View for View { , (Press , "is_searcher_opened" , "escape" , "close_searcher") , (Press , "open_dialog_shown" , "escape" , "close_open_dialog") , (Press , "" , "tab" , "hide_prompt") + , (Press , "" , "cmd o" , "hide_prompt") , (Press , "" , "cmd alt shift t" , "toggle_style") , (Press , "" , "cmd s" , "save_module") , (Press , "" , "cmd z" , "undo") From afdca90dfeca6b35e01a8aab7d14b63a433573d0 Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Mon, 19 Jul 2021 10:55:41 +0200 Subject: [PATCH 18/25] Fixes after merge --- src/rust/ide/src/ide/integration/project.rs | 5 ++--- src/rust/ide/src/model/project.rs | 5 +++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rust/ide/src/ide/integration/project.rs b/src/rust/ide/src/ide/integration/project.rs index 2f76139981..d765ba1a96 100644 --- a/src/rust/ide/src/ide/integration/project.rs +++ b/src/rust/ide/src/ide/integration/project.rs @@ -9,7 +9,6 @@ use crate::prelude::*; use crate::controller::graph::Connections; use crate::controller::graph::NodeTrees; -use crate::controller::ide::ProjectMetadata; use crate::controller::searcher::action::MatchInfo; use crate::controller::searcher::Actions; use crate::controller::upload; @@ -1983,11 +1982,11 @@ impl upload::DataProvider for drop::File { #[derive(Clone,CloneRef,Debug,Default)] struct ProjectsToOpen { - projects : Rc> + projects : Rc> } impl ProjectsToOpen { - fn new(projects:Vec) -> Self { + fn new(projects:Vec) -> Self { Self {projects:Rc::new(projects)} } diff --git a/src/rust/ide/src/model/project.rs b/src/rust/ide/src/model/project.rs index cca839eb75..d180487c3d 100644 --- a/src/rust/ide/src/model/project.rs +++ b/src/rust/ide/src/model/project.rs @@ -110,8 +110,9 @@ pub trait API:Debug { #[allow(clippy::needless_lifetimes)] // Note: Needless lifetimes fn main_module_model<'a>(&'a self) -> BoxFuture<'a, FallibleResult> { async move { - let main_name = self.main_module(); - let main_path = model::module::Path::from_id(self.content_root_id(), &main_name.id); + let main_name = self.main_module(); + let content_root_id = self.project_content_root_id(); + let main_path = model::module::Path::from_id(content_root_id,&main_name.id); self.module(main_path).await }.boxed_local() } From 33c634c8fbb8a6c2d37f33ed279919a9a40463ed Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Tue, 20 Jul 2021 09:52:00 +0200 Subject: [PATCH 19/25] Fix misplaced mouse --- .../lib/core/src/display/object/class.rs | 57 ++++++++++++++----- src/rust/ensogl/lib/core/src/display/scene.rs | 3 +- 2 files changed, 45 insertions(+), 15 deletions(-) diff --git a/src/rust/ensogl/lib/core/src/display/object/class.rs b/src/rust/ensogl/lib/core/src/display/object/class.rs index 22bcffcff4..c7dba4ded5 100644 --- a/src/rust/ensogl/lib/core/src/display/object/class.rs +++ b/src/rust/ensogl/lib/core/src/display/object/class.rs @@ -285,18 +285,16 @@ impl Model { ) { // === Scene Layers Update === - let this_scene_layers = self.scene_layers.borrow(); - let this_scene_layers_slice = this_scene_layers.as_slice(); - let self_scene_layers_changed = self.dirty.scene_layer.check(); - let scene_layers_might_changed = parent_scene_layers_changed || self_scene_layers_changed; - let (scene_layers_changed,scene_layers) = if scene_layers_might_changed { + let this_scene_layers = self.scene_layers.borrow(); + let this_scene_layers_slice = this_scene_layers.as_slice(); + let self_scene_layers_changed = self.dirty.scene_layer.check(); + let scene_layers_changed = parent_scene_layers_changed || self_scene_layers_changed; + let scene_layers = if scene_layers_changed { self.dirty.scene_layer.unset(); - let scene_layers = if this_scene_layers_slice.is_empty() { parent_scene_layers} - else { this_scene_layers_slice}; - let changed = scene_layers != this_scene_layers_slice; - (changed,scene_layers) + if this_scene_layers_slice.is_empty() { parent_scene_layers } + else { this_scene_layers_slice } } else { - (false,this_scene_layers_slice) + this_scene_layers_slice }; if scene_layers_changed { debug!(self.logger, "Scene layers changed.", || { @@ -310,14 +308,18 @@ impl Model { self.update_visibility(host,parent_scene_layers); let has_new_parent = self.dirty.parent.check(); - let is_origin_dirty = has_new_parent || parent_origin_changed; + let is_origin_dirty = has_new_parent || parent_origin_changed || scene_layers_changed; let new_parent_origin = is_origin_dirty.as_some(parent_origin); let parent_origin_label = if new_parent_origin.is_some() {"new"} else {"old"}; debug!(self.logger, "Update with {parent_origin_label} parent origin.", || { let origin_changed = self.transform.borrow_mut().update(new_parent_origin); let new_origin = self.transform.borrow().matrix; - if origin_changed { - info!(self.logger,"Self origin changed."); + if origin_changed || scene_layers_changed { + if origin_changed { + info!(self.logger,"Self origin changed."); + } else { + info!(self.logger, "Self origin did not change, but the layers changed"); + } self.callbacks.on_updated(self); if !self.children.borrow().is_empty() { debug!(self.logger, "Updating all children.", || { @@ -330,7 +332,7 @@ impl Model { }) } } else { - info!(self.logger,"Self origin did not change."); + info!(self.logger,"Self origin and layers did not change."); if self.dirty.children.check_all() { debug!(self.logger, "Updating dirty children.", || { self.dirty.children.take().iter().for_each(|ix| { @@ -1466,4 +1468,31 @@ mod tests { assert_eq!(node5.is_visible(),false); assert_eq!(node6.is_visible(),false); } + + #[test] + fn layers_test() { + let layer1 = LayerId::new(0); + let layer2 = LayerId::new(2); + let node1 = Instance::<()>::new(Logger::new("node1")); + let node2 = Instance::<()>::new(Logger::new("node2")); + let node3 = Instance::<()>::new(Logger::new("node3")); + node1.add_child(&node2); + node1.add_child(&node3); + node1.update(&()); + assert_eq!(node1.main_layer(), None); + assert_eq!(node2.main_layer(), None); + assert_eq!(node3.main_layer(), None); + + node1.add_to_scene_layer(layer1); + node1.update(&()); + assert_eq!(node1.main_layer(), Some(layer1)); + assert_eq!(node2.main_layer(), Some(layer1)); + assert_eq!(node3.main_layer(), Some(layer1)); + + node2.add_to_scene_layer_exclusive(layer2); + node1.update(&()); + assert_eq!(node1.main_layer(), Some(layer1)); + assert_eq!(node2.main_layer(), Some(layer2)); + assert_eq!(node3.main_layer(), Some(layer1)); + } } diff --git a/src/rust/ensogl/lib/core/src/display/scene.rs b/src/rust/ensogl/lib/core/src/display/scene.rs index f26f428d69..c89c5d35d9 100644 --- a/src/rust/ensogl/lib/core/src/display/scene.rs +++ b/src/rust/ensogl/lib/core/src/display/scene.rs @@ -912,6 +912,7 @@ impl SceneData { (&self, object:&impl display::Object, screen_pos:Vector2) -> Vector2 { let origin_world_space = Vector4(0.0,0.0,0.0,1.0); let layer = object.main_layer().and_then(|id| self.layers.get(id)); + let is_layer = layer.is_some(); let camera = layer.map_or(self.camera(), |l| l.camera()); let origin_clip_space = camera.view_projection_matrix() * origin_world_space; let inv_object_matrix = object.transform_matrix().try_inverse().unwrap(); @@ -921,7 +922,7 @@ impl SceneData { let clip_space_x = origin_clip_space.w * 2.0 * screen_pos.x / shape.width; let clip_space_y = origin_clip_space.w * 2.0 * screen_pos.y / shape.height; let clip_space = Vector4(clip_space_x,clip_space_y,clip_space_z,origin_clip_space.w); - let world_space = self.camera().inversed_view_projection_matrix() * clip_space; + let world_space = camera.inversed_view_projection_matrix() * clip_space; (inv_object_matrix * world_space).xy() } } From 5c794f11f5f83e5fc350a116ef60970893ffc79e Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Tue, 20 Jul 2021 12:28:52 +0200 Subject: [PATCH 20/25] Applying @s9ferech review --- .../lib/components/src/file_browser/model.rs | 38 +++++++++++++---- src/rust/ensogl/lib/core/src/display/scene.rs | 1 - .../ide/src/ide/integration/file_system.rs | 22 +++++----- src/rust/ide/view/src/project.rs | 41 ++++++++++++------- 4 files changed, 67 insertions(+), 35 deletions(-) diff --git a/src/rust/ensogl/lib/components/src/file_browser/model.rs b/src/rust/ensogl/lib/components/src/file_browser/model.rs index e5f38d92d0..aabad79c7e 100644 --- a/src/rust/ensogl/lib/components/src/file_browser/model.rs +++ b/src/rust/ensogl/lib/components/src/file_browser/model.rs @@ -5,7 +5,7 @@ use crate::prelude::*; use enso_frp as frp; use std::path::PathBuf; - +use std::cmp::Ordering; // ============= @@ -16,16 +16,16 @@ use std::path::PathBuf; /// The type of a folder. This is used to distinguish standard folders from the different kinds of /// content roots. -#[derive(Debug,Copy,Clone)] +#[derive(Debug,Copy,Clone,Eq,Ord,PartialEq,PartialOrd)] pub enum FolderType { /// A normal sufolder in the file system. Standard, /// The projects root. Project, - /// The operating system's global root folder. - Root, /// The users home folder. Home, + /// The operating system's global root folder. + Root, /// The root of a library. Library, /// A custom kind of content root. @@ -34,7 +34,7 @@ pub enum FolderType { /// The type of a file system entry. Distinguishes files from the different kind of folders. The /// `EntryType` of a folder also caries the folder's content. -#[derive(Debug,Clone)] +#[derive(Clone,Debug)] pub enum EntryType { /// A file. File, @@ -47,15 +47,37 @@ pub enum EntryType { }, } +impl Ord for EntryType { + fn cmp(&self, other:&Self) -> Ordering { + match (self,other) { + (Self::File,Self::File) => Ordering::Equal, + (Self::File,Self::Folder {..}) => Ordering::Greater, + (Self::Folder {..},Self::File) => Ordering::Less, + (Self::Folder {type_:type1,..},Self::Folder {type_:type2,..}) => type1.cmp(type2), + } + } +} + +impl PartialOrd for EntryType { + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } +} + +impl PartialEq for EntryType { + fn eq(&self, other: &Self) -> bool { self.cmp(other) == Ordering::Equal } +} + +impl Eq for EntryType {} + /// A file system entry. Either a file or a folder. -#[derive(Debug,Clone)] +#[derive(Debug,Clone,Eq,Ord,PartialEq,PartialOrd)] pub struct Entry { + /// The entry type. + pub type_ : EntryType, /// The entrie's name. pub name : String, /// The entrie's global path in the file system. pub path : PathBuf, - /// The entry type. - pub type_ : EntryType, + } diff --git a/src/rust/ensogl/lib/core/src/display/scene.rs b/src/rust/ensogl/lib/core/src/display/scene.rs index c89c5d35d9..dc19c9f663 100644 --- a/src/rust/ensogl/lib/core/src/display/scene.rs +++ b/src/rust/ensogl/lib/core/src/display/scene.rs @@ -912,7 +912,6 @@ impl SceneData { (&self, object:&impl display::Object, screen_pos:Vector2) -> Vector2 { let origin_world_space = Vector4(0.0,0.0,0.0,1.0); let layer = object.main_layer().and_then(|id| self.layers.get(id)); - let is_layer = layer.is_some(); let camera = layer.map_or(self.camera(), |l| l.camera()); let origin_clip_space = camera.view_projection_matrix() * origin_world_space; let inv_object_matrix = object.transform_matrix().try_inverse().unwrap(); diff --git a/src/rust/ide/src/ide/integration/file_system.rs b/src/rust/ide/src/ide/integration/file_system.rs index e61a080427..0ad83efa95 100644 --- a/src/rust/ide/src/ide/integration/file_system.rs +++ b/src/rust/ide/src/ide/integration/file_system.rs @@ -92,21 +92,21 @@ impl FileProvider { impl FolderContent for FileProvider { fn request_entries (&self, entries_loaded:frp::Any>>, _error_occurred:frp::Any) { - let entries = self.content_roots.iter().map(|root| { + let entries = self.content_roots.iter().filter_map(|root| { let ls_path = language_server::Path::new_root(root.id()); let path = to_file_browser_path(&ls_path); let (name,folder_type) = match &**root { language_server::ContentRoot::Project {..} => - ("Project".to_owned(), FolderType::Project), + Some(("Project".to_owned(), FolderType::Project)), language_server::ContentRoot::FileSystemRoot{path,..} => - (path.clone(),FolderType::Root), + Some((path.clone(),FolderType::Root)), language_server::ContentRoot::Home {..} => - ("Home".to_owned(), FolderType::Home), - language_server::ContentRoot::Library{namespace,name,..} => - (format!("{}.{}",namespace,name), FolderType::Library), + Some(("Home".to_owned(), FolderType::Home)), + language_server::ContentRoot::Library{..} => + None, // We skip libraries, as they cannot be easily inserted. language_server::ContentRoot::Custom{..} => - ("Other".to_owned(),FolderType::Custom), - }; + None, // Custom content roots are not used. + }?; let type_ = EntryType::Folder { type_ : folder_type, content : { @@ -114,9 +114,9 @@ impl FolderContent for FileProvider { DirectoryView::new_from_root(connection,root.clone_ref()).into() } }; - Entry {name,path,type_} + Some(Entry {name,path,type_}) }); - entries_loaded.emit(Rc::new(entries.collect_vec())); + entries_loaded.emit(Rc::new(entries.sorted().collect_vec())); } } @@ -172,7 +172,7 @@ impl DirectoryView { } } }); - Ok(entries.collect()) + Ok(entries.sorted().collect()) } } diff --git a/src/rust/ide/view/src/project.rs b/src/rust/ide/view/src/project.rs index ba905aa04b..8e62a87605 100644 --- a/src/rust/ide/view/src/project.rs +++ b/src/rust/ide/view/src/project.rs @@ -49,10 +49,10 @@ ensogl::define_endpoints! { undo(), /// Redo the last undone action. redo(), - /// Show the prompt informing about tab key. + /// Show the prompt informing about tab key if it is not disabled. show_prompt(), - /// Hide the prompt - hide_prompt(), + /// Disable the prompt. It will be hidden if currently visible. + disable_prompt(), } Output { @@ -353,6 +353,7 @@ impl View { display::style::javascript::expose_to_window(&app.themes); + let scene = app.display.scene().clone_ref(); let model = Model::new(app); let frp = Frp::new(); let searcher = &model.searcher.frp; @@ -370,7 +371,7 @@ impl View { // See: https://github.com/enso-org/ide/issues/795 app.themes.update(); - let style_sheet = &model.app.display.scene().style_sheet; + let style_sheet = &scene.style_sheet; let styles = StyleWatchFrp::new(style_sheet); let default_gap_between_nodes_path = ensogl_theme::project::default_gap_between_nodes; @@ -390,7 +391,7 @@ impl View { } } - let shape = app.display.scene().shape().clone_ref(); + let shape = scene.shape().clone_ref(); frp::extend!{ network eval shape ((shape) model.on_dom_shape_changed(shape)); @@ -411,10 +412,6 @@ impl View { } }); - // === Searcher Selection === - - eval searcher.is_selected ((is_selected) graph.set_navigator_disabled(is_selected)); - // === Editing === @@ -485,7 +482,9 @@ impl View { eval_ frp.show_open_dialog (model.show_open_dialog()); project_chosen <- project_list.chosen_entry.constant(()); file_chosen <- file_browser.entry_chosen.constant(()); - should_be_closed <- any(frp.close_open_dialog,project_chosen,file_chosen); + mouse_down <- scene.mouse.frp.down.constant(()); + clicked_on_bg <- mouse_down.filter(f_!(scene.mouse.target.get().is_background())); + should_be_closed <- any(frp.close_open_dialog,project_chosen,file_chosen,clicked_on_bg); eval_ should_be_closed (model.hide_open_dialog()); frp.source.open_dialog_shown <+ bool(&should_be_closed,&frp.show_open_dialog); @@ -524,6 +523,7 @@ impl View { // === Prompt === + init <- source::<()>(); let prompt_bg_color_path = ensogl_theme::graph_editor::prompt::background; let prompt_bg_padding_path = ensogl_theme::graph_editor::prompt::background::padding; @@ -538,9 +538,13 @@ impl View { let prompt_size = styles.get_number(prompt_size_path); prompt_size <- all(&prompt_size,&init)._0(); - prompt_visibility.target <+ frp.show_prompt.constant(1.0); - prompt_visibility.target <+ frp.hide_prompt.constant(0.0); - prompt_visibility.target <+ frp.is_searcher_opened.filter(|v| *v).constant(0.0); + disable_after_opening_searcher <- frp.is_searcher_opened.filter(|v| *v).constant(()); + disable <- any(frp.disable_prompt,disable_after_opening_searcher); + disabled <- disable.constant(true); + show_prompt <- frp.show_prompt.gate_not(&disabled); + + prompt_visibility.target <+ show_prompt.constant(1.0); + prompt_visibility.target <+ disable.constant(0.0); _eval <- all_with4(&prompt_visibility.value,&prompt_bg_color,&prompt_color,&prompt_size, f!([model](weight,bg_color,color,size) { let mut bg_color = *bg_color; @@ -558,6 +562,12 @@ impl View { model.prompt_background.size.set(Vector2(*width + padding, *size + padding)); }) ); + + + // === Disabling Navigation === + + disable_navigation <- searcher.is_selected || frp.open_dialog_shown; + graph.set_navigator_disabled <+ disable_navigation; } init.emit(()); std::mem::forget(prompt_visibility); @@ -604,8 +614,9 @@ impl application::View for View { , (Press , "!is_searcher_opened", "cmd o" , "show_open_dialog") , (Press , "is_searcher_opened" , "escape" , "close_searcher") , (Press , "open_dialog_shown" , "escape" , "close_open_dialog") - , (Press , "" , "tab" , "hide_prompt") - , (Press , "" , "cmd o" , "hide_prompt") + , (Press , "" , "tab" , "disable_prompt") + , (Press , "" , "cmd o" , "disable_prompt") + , (Press , "" , "space" , "disable_prompt") , (Press , "" , "cmd alt shift t" , "toggle_style") , (Press , "" , "cmd s" , "save_module") , (Press , "" , "cmd z" , "undo") From fa19849af0808c7fdf3a625b304d6104cc559140 Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Tue, 20 Jul 2021 14:47:10 +0200 Subject: [PATCH 21/25] Another review fixes --- CHANGELOG.md | 4 +--- src/rust/ide/src/ide/integration/file_system.rs | 9 +++++---- src/rust/ide/src/ide/integration/project.rs | 6 ++++-- src/rust/ide/view/src/project.rs | 6 ++++++ 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6b2d2455f..9d00653efd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,12 +13,10 @@ these updates be shipped in a stable release before the end of the year. - node selection; - enabling and disabling a visualization; - entering and leaving a node. -- [File or Project Open Dialog][xxxx]. ctrl/cmd+o will +- [File or Project Open Dialog][1700]. ctrl/cmd+o will display a new File or Project Open Dialog. Here you can open another project, or pick a file from browser: the file will be inserted as a node to the current graph. -- [File browser component][1677]. A basic file browser component has been - implemented, but is not integrated into the user interface yet. [1640]: https://github.com/enso-org/ide/pull/1664 [1677]: https://github.com/enso-org/ide/pull/1677 diff --git a/src/rust/ide/src/ide/integration/file_system.rs b/src/rust/ide/src/ide/integration/file_system.rs index 0ad83efa95..fa1ab8c267 100644 --- a/src/rust/ide/src/ide/integration/file_system.rs +++ b/src/rust/ide/src/ide/integration/file_system.rs @@ -14,7 +14,7 @@ use ensogl_gui_components::file_browser::model::FolderType; use ensogl_gui_components::file_browser::model::Entry; use ensogl_gui_components::file_browser::model::EntryType; use std::iter::once; - +use json_rpc::error::RpcError; // ======================= @@ -149,7 +149,7 @@ impl DirectoryView { } /// Retrieves the directory content from the Engine. - pub async fn get_entries_list(&self) -> FallibleResult> { + pub async fn get_entries_list(&self) -> Result,RpcError> { let response = self.connection.file_list(&self.path).await?; let entries = response.paths.into_iter().map(|fs_obj| { match fs_obj { @@ -182,8 +182,9 @@ impl FolderContent for DirectoryView { let this = self.clone_ref(); executor::global::spawn(async move { match this.get_entries_list().await { - Ok (entries) => entries_loaded.emit(Rc::new(entries)), - Err(error) => error_occurred.emit(ImString::new(error.to_string())), + Ok (entries) => entries_loaded.emit(Rc::new(entries)), + Err(RpcError::RemoteError(error)) => error_occurred.emit(ImString::new(error.message)), + Err(error) => error_occurred.emit(ImString::new(error.to_string())), } }); } diff --git a/src/rust/ide/src/ide/integration/project.rs b/src/rust/ide/src/ide/integration/project.rs index d765ba1a96..e4d6810d9b 100644 --- a/src/rust/ide/src/ide/integration/project.rs +++ b/src/rust/ide/src/ide/integration/project.rs @@ -296,9 +296,11 @@ impl Integration { // === Dropping Files === - let file_dropped = model.view.graph().file_dropped.clone_ref(); + let dropping_enabled = model.view.drop_files_enabled.clone_ref(); + let file_dropped = model.view.graph().file_dropped.clone_ref(); frp::extend! { network - eval file_dropped ([model]((file,position)) { + file_upload_requested <- file_dropped.gate(&dropping_enabled); + eval file_upload_requested ([model]((file,position)) { let project = model.project.clone_ref(); let graph = model.graph.graph(); let to_upload = upload::FileToUpload { diff --git a/src/rust/ide/view/src/project.rs b/src/rust/ide/view/src/project.rs index 8e62a87605..9a4ed2cc4c 100644 --- a/src/rust/ide/view/src/project.rs +++ b/src/rust/ide/view/src/project.rs @@ -68,6 +68,7 @@ ensogl::define_endpoints! { style (Theme), fullscreen_visualization_shown (bool), default_gap_between_nodes (f32), + drop_files_enabled (bool), } } @@ -568,6 +569,11 @@ impl View { disable_navigation <- searcher.is_selected || frp.open_dialog_shown; graph.set_navigator_disabled <+ disable_navigation; + + // === Disabling Dropping === + + frp.source.drop_files_enabled <+ init.constant(true); + frp.source.drop_files_enabled <+ frp.open_dialog_shown.map(|v| !v); } init.emit(()); std::mem::forget(prompt_visibility); From cd95cc2e3413fadfe501e15ce49009ab55141b98 Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Tue, 20 Jul 2021 15:38:53 +0200 Subject: [PATCH 22/25] Keep all "actual layers", not only the first one --- .../lib/core/src/display/object/class.rs | 74 +++++++++---------- src/rust/ensogl/lib/core/src/display/scene.rs | 2 +- 2 files changed, 37 insertions(+), 39 deletions(-) diff --git a/src/rust/ensogl/lib/core/src/display/object/class.rs b/src/rust/ensogl/lib/core/src/display/object/class.rs index c7dba4ded5..6f5b1dee98 100644 --- a/src/rust/ensogl/lib/core/src/display/object/class.rs +++ b/src/rust/ensogl/lib/core/src/display/object/class.rs @@ -187,8 +187,12 @@ fn on_dirty_callback(f:&Rc>>) -> OnDirtyCallback { #[derive(Derivative)] #[derivative(Debug(bound=""))] pub struct Model { - host : PhantomData , - scene_layers : Rc>>, + host:PhantomData , + /// Layers the object was explicitly assigned to. + assigned_layers:RefCell>, + /// Layers where the object is displayed. May be same as assigned layers, or inherited by + /// parent. + scene_layers : RefCell>, dirty : DirtyFlags , callbacks : Callbacks , parent_bind : RefCell >>, @@ -196,26 +200,23 @@ pub struct Model { transform : RefCell , visible : Cell , logger : Logger, - /// The first layer on the layers this object actually belongs to. - //TODO[ao] this is a workaround for screen_to_object_pos method. - main_layer : Cell>, } impl Model { /// Constructor. pub fn new(logger:impl AnyLogger) -> Self { - let logger = Logger::new_from(logger); - let parent_bind = default(); - let children = default(); - let transform = default(); - let dirty = DirtyFlags::new(&logger); - let visible = Cell::new(false); - let callbacks = default(); - let host = default(); - let scene_layers = default(); - let main_layer = default(); - Self {host,scene_layers,dirty,callbacks,parent_bind,children,transform,visible,logger - ,main_layer} + let logger = Logger::new_from(logger); + let parent_bind = default(); + let children = default(); + let transform = default(); + let dirty = DirtyFlags::new(&logger); + let visible = Cell::new(false); + let callbacks = default(); + let host = default(); + let assigned_layers = default(); + let scene_layers = default(); + Self {host,assigned_layers,scene_layers,dirty,callbacks,parent_bind,children,transform + ,visible,logger} } /// Checks whether the object is visible. @@ -285,20 +286,20 @@ impl Model { ) { // === Scene Layers Update === - let this_scene_layers = self.scene_layers.borrow(); - let this_scene_layers_slice = this_scene_layers.as_slice(); - let self_scene_layers_changed = self.dirty.scene_layer.check(); - let scene_layers_changed = parent_scene_layers_changed || self_scene_layers_changed; + let assigned_layers = self.assigned_layers.borrow(); + let assigned_layers_slice = assigned_layers.as_slice(); + let assigned_layers_changed = self.dirty.scene_layer.check(); + let scene_layers_changed = parent_scene_layers_changed || assigned_layers_changed; let scene_layers = if scene_layers_changed { self.dirty.scene_layer.unset(); - if this_scene_layers_slice.is_empty() { parent_scene_layers } - else { this_scene_layers_slice } + if assigned_layers_slice.is_empty() { parent_scene_layers } + else { assigned_layers_slice } } else { - this_scene_layers_slice + assigned_layers_slice }; if scene_layers_changed { debug!(self.logger, "Scene layers changed.", || { - self.main_layer.set(scene_layers.first().copied()); + *self.scene_layers.borrow_mut() = scene_layers.to_vec(); self.callbacks.on_scene_layers_changed(host,scene_layers); }); } @@ -392,7 +393,7 @@ impl Model { fn set_vis_true(&self, host:&Host, parent_scene_layers:&[LayerId]) { if !self.visible.get() { info!(self.logger,"Showing."); - let this_scene_layers = self.scene_layers.borrow(); + let this_scene_layers = self.assigned_layers.borrow(); let this_scene_layers_slice = this_scene_layers.as_slice(); let scene_layers = if this_scene_layers_slice.is_empty() { parent_scene_layers } else { this_scene_layers_slice }; @@ -610,18 +611,17 @@ impl Instance { Id(Rc::downgrade(&self.rc).as_ptr() as *const() as usize) } - /// Get the first layer where this object is actually displayed. - //TODO[ao] this is workaround for `screen_to_object_space` method. - pub fn _main_layer(&self) -> Option { self.main_layer.get() } + /// Get the layers where this object is displayed. May be equal to layers it was explicitly + /// assigned, or layers inherited from the parent. + pub fn _scene_layers(&self) -> Vec { self.scene_layers.borrow().clone() } /// Add this object to the provided scene layer and remove it from all other layers. Do not use /// this method explicitly. Use layers' methods instead. pub(crate) fn add_to_scene_layer(&self, layer:LayerId) { self.dirty.scene_layer.set(); - let mut scene_layers = self.scene_layers.borrow_mut(); + let mut scene_layers = self.assigned_layers.borrow_mut(); if !scene_layers.contains(&layer) { scene_layers.push(layer); - self.main_layer.set(scene_layers.first().copied()); } } @@ -629,16 +629,14 @@ impl Instance { /// this method explicitly. Use layers' methods instead. pub(crate) fn add_to_scene_layer_exclusive(&self, layer:LayerId) { self.dirty.scene_layer.set(); - *self.scene_layers.borrow_mut() = vec![layer]; - self.main_layer.set(Some(layer)); + *self.assigned_layers.borrow_mut() = vec![layer]; } /// Remove this object from the provided scene layer. Do not use this method explicitly. Use /// layers' methods instead. pub(crate) fn remove_from_scene_layer(&self, layer:LayerId) { self.dirty.scene_layer.set(); - self.scene_layers.borrow_mut().remove_item(&layer); - self.main_layer.set(self.scene_layers.borrow().first().copied()); + self.assigned_layers.borrow_mut().remove_item(&layer); } /// Adds a new `Object` as a child to the current one. @@ -824,9 +822,9 @@ pub trait ObjectOps : Object { self.display_object()._id() } - /// Get the first layer where this object is actually displayed. - //TODO[ao] this is workaround for `screen_to_object_space` method. - fn main_layer(&self) -> Option { self.display_object()._main_layer() } + /// Get the layers where this object is displayed. May be equal to layers it was explicitly + /// assigned, or layers inherited from the parent. + fn scene_layers(&self) -> Vec { self.display_object()._scene_layers() } /// Add another display object as a child to this display object. Children will inherit all /// transformations of their parents. diff --git a/src/rust/ensogl/lib/core/src/display/scene.rs b/src/rust/ensogl/lib/core/src/display/scene.rs index dc19c9f663..2319f24dc1 100644 --- a/src/rust/ensogl/lib/core/src/display/scene.rs +++ b/src/rust/ensogl/lib/core/src/display/scene.rs @@ -911,7 +911,7 @@ impl SceneData { pub fn screen_to_object_space (&self, object:&impl display::Object, screen_pos:Vector2) -> Vector2 { let origin_world_space = Vector4(0.0,0.0,0.0,1.0); - let layer = object.main_layer().and_then(|id| self.layers.get(id)); + let layer = object.scene_layers().first().and_then(|id| self.layers.get(*id)); let camera = layer.map_or(self.camera(), |l| l.camera()); let origin_clip_space = camera.view_projection_matrix() * origin_world_space; let inv_object_matrix = object.transform_matrix().try_inverse().unwrap(); From 1ea42255efa0c0672917f559b8c34bf031802afd Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Fri, 23 Jul 2021 13:23:09 +0200 Subject: [PATCH 23/25] Fixes after merge --- .../ensogl/lib/components/src/file_browser.rs | 29 +++++++--- .../ensogl/lib/components/src/list_view.rs | 26 +++++---- .../lib/core/src/display/object/class.rs | 18 +++--- src/rust/ensogl/lib/theme/src/lib.rs | 7 ++- src/rust/ide/src/controller/project.rs | 3 +- src/rust/ide/src/ide/integration/project.rs | 14 ++--- src/rust/ide/view/src/open_dialog.rs | 21 ++++--- .../ide/view/src/open_dialog/project_list.rs | 56 ++----------------- 8 files changed, 79 insertions(+), 95 deletions(-) diff --git a/src/rust/ensogl/lib/components/src/file_browser.rs b/src/rust/ensogl/lib/components/src/file_browser.rs index cbe0e38e26..0de9485536 100644 --- a/src/rust/ensogl/lib/components/src/file_browser.rs +++ b/src/rust/ensogl/lib/components/src/file_browser.rs @@ -9,11 +9,8 @@ use crate::file_browser::model::*; use ensogl_core::display::shape::*; use std::path::PathBuf; -use ensogl_core::display::object::ObjectOps; -use ensogl_theme as theme; -use ensogl_text as text; -use ensogl_core::data::color; - +use ensogl_core::display; +use ensogl_core::display::Scene; // =========== @@ -51,9 +48,27 @@ ensogl_core::define_endpoints! { /// A file browser component. It allows to browse the content of a folder and it's subfolders and /// emits an event when an entry is chosen. #[derive(Clone,CloneRef,Debug)] -pub struct FileBrowser(Rc); +pub struct FileBrowser { + logger : Logger, + frp : Frp, + display_object : display::object::Instance, +} + +impl FileBrowser { + /// Constructore + pub fn new() -> Self { + let logger = Logger::new("FileBrowser"); + let frp = Frp::new(); + let display_object = display::object::Instance::new(&logger); + Self {logger,frp,display_object} + } +} impl Deref for FileBrowser { type Target = Frp; - fn deref(&self) -> &Self::Target { &self.0 } + fn deref(&self) -> &Self::Target { &self.frp } +} + +impl display::Object for FileBrowser { + fn display_object(&self) -> &display::object::Instance {&self.display_object } } diff --git a/src/rust/ensogl/lib/components/src/list_view.rs b/src/rust/ensogl/lib/components/src/list_view.rs index 6893f66cf4..0266be4fe6 100644 --- a/src/rust/ensogl/lib/components/src/list_view.rs +++ b/src/rust/ensogl/lib/components/src/list_view.rs @@ -18,6 +18,8 @@ use ensogl_core::display::shape::*; use ensogl_core::DEPRECATED_Animation; use ensogl_theme as theme; +pub use entry::Entry; + // ========================== @@ -33,9 +35,11 @@ const SHAPE_PADDING:f32 = 5.0; // === Selection === -mod selection { +/// The selection rectangle shape. +pub mod selection { use super::*; + /// The corner radius in pixels. pub const CORNER_RADIUS_PX:f32 = 12.0; ensogl_core::define_shape_system! { @@ -57,9 +61,11 @@ mod selection { // === Background === -mod background { +/// The default list view background. +pub mod background { use super::*; + /// The corner radius in pixels. pub const CORNER_RADIUS_PX:f32 = selection::CORNER_RADIUS_PX; ensogl_core::define_shape_system! { @@ -95,7 +101,7 @@ struct View { /// The Model of Select Component. #[derive(Clone,CloneRef,Debug)] -struct Model { +struct Model { app : Application, entries : entry::List, selection : selection::View, @@ -104,7 +110,7 @@ struct Model { display_object : display::object::Instance, } -impl Model { +impl Model { fn new(app:&Application) -> Self { let app = app.clone_ref(); @@ -238,17 +244,17 @@ ensogl_core::define_endpoints! { /// "choosing" by clicking or pressing enter. The basic entry types are defined in [`entry`] module. #[allow(missing_docs)] #[derive(Clone,CloneRef,Debug)] -pub struct ListView { +pub struct ListView { model : Model, pub frp : Frp, } -impl Deref for ListView { +impl Deref for ListView { type Target = Frp; fn deref(&self) -> &Self::Target { &self.frp } } -impl ListView +impl ListView where E::Model : Default { /// Constructor. pub fn new(app:&Application) -> Self { @@ -423,15 +429,15 @@ where E::Model : Default { } } -impl display::Object for ListView { +impl display::Object for ListView { fn display_object(&self) -> &display::object::Instance { &self.model.display_object } } -impl application::command::FrpNetworkProvider for ListView { +impl application::command::FrpNetworkProvider for ListView { fn network(&self) -> &frp::Network { &self.frp.network } } -impl application::View for ListView { +impl application::View for ListView { fn label() -> &'static str { "ListView" } fn new(app:&Application) -> Self { ListView::new(app) } fn app(&self) -> &Application { &self.model.app } diff --git a/src/rust/ensogl/lib/core/src/display/object/class.rs b/src/rust/ensogl/lib/core/src/display/object/class.rs index 38b2f4c819..302d5632c8 100644 --- a/src/rust/ensogl/lib/core/src/display/object/class.rs +++ b/src/rust/ensogl/lib/core/src/display/object/class.rs @@ -1477,20 +1477,20 @@ mod tests { node1.add_child(&node2); node1.add_child(&node3); node1.update(&()); - assert_eq!(node1.main_layer(), None); - assert_eq!(node2.main_layer(), None); - assert_eq!(node3.main_layer(), None); + assert_eq!(node1.scene_layers(), vec![]); + assert_eq!(node2.scene_layers(), vec![]); + assert_eq!(node3.scene_layers(), vec![]); node1.add_to_scene_layer(layer1); node1.update(&()); - assert_eq!(node1.main_layer(), Some(layer1)); - assert_eq!(node2.main_layer(), Some(layer1)); - assert_eq!(node3.main_layer(), Some(layer1)); + assert_eq!(node1.scene_layers(), vec![layer1]); + assert_eq!(node2.scene_layers(), vec![layer1]); + assert_eq!(node3.scene_layers(), vec![layer1]); node2.add_to_scene_layer_exclusive(layer2); node1.update(&()); - assert_eq!(node1.main_layer(), Some(layer1)); - assert_eq!(node2.main_layer(), Some(layer2)); - assert_eq!(node3.main_layer(), Some(layer1)); + assert_eq!(node1.scene_layers(), vec![layer1]); + assert_eq!(node2.scene_layers(), vec![layer2]); + assert_eq!(node3.scene_layers(), vec![layer1]); } } diff --git a/src/rust/ensogl/lib/theme/src/lib.rs b/src/rust/ensogl/lib/theme/src/lib.rs index a92b3c4cb0..16fe96a9f1 100644 --- a/src/rust/ensogl/lib/theme/src/lib.rs +++ b/src/rust/ensogl/lib/theme/src/lib.rs @@ -174,8 +174,13 @@ define_themes! { [light:0, dark:1] } } } + file_browser { + width = 0.0, 0.0; // Should be updated when file browser will be implemented. + height = 421.0, 421.0; + } open_dialog { - gap_between_panels = 16.0, 16.0; + // Should be updated when file browser will be implemented. + gap_between_panels = 0.0, 0.0; } project_list { width = 202.0 , 202.0; diff --git a/src/rust/ide/src/controller/project.rs b/src/rust/ide/src/controller/project.rs index 3b67ad6ad4..38732f6d1e 100644 --- a/src/rust/ide/src/controller/project.rs +++ b/src/rust/ide/src/controller/project.rs @@ -5,9 +5,8 @@ use crate::prelude::*; use crate::controller::graph::executed::Notification as GraphNotification; use crate::controller::ide::StatusNotificationPublisher; use crate::double_representation::project; -use crate::model::traits::*; -use crate::double_representation::project; use crate::model::module::QualifiedName; +use crate::model::traits::*; use enso_frp::web::platform; use enso_frp::web::platform::Platform; diff --git a/src/rust/ide/src/ide/integration/project.rs b/src/rust/ide/src/ide/integration/project.rs index 22da3dc690..fae533eab7 100644 --- a/src/rust/ide/src/ide/integration/project.rs +++ b/src/rust/ide/src/ide/integration/project.rs @@ -33,7 +33,6 @@ use enso_data::text::TextChange; use enso_frp as frp; use enso_protocol::language_server::ExpressionUpdatePayload; use ensogl::display::traits::*; -use ensogl::display; use ensogl_gui_components::file_browser::model::AnyFolderContent; use ensogl_gui_components::list_view; use ensogl_web::drop; @@ -43,7 +42,7 @@ use ide_view::graph_editor::component::visualization; use ide_view::graph_editor::EdgeEndpoint; use ide_view::graph_editor::GraphEditor; use ide_view::graph_editor::SharedHashMap; -use ide_view::searcher::entry::AnyEntryProvider; +use ide_view::searcher::entry::AnyModelProvider; use ide_view::open_dialog; use utils::iter::split_by_predicate; use futures::future::LocalBoxFuture; @@ -1506,7 +1505,7 @@ impl Model { -> FallibleResult { use visualization::instance::ContextModule::*; match context { - ProjectMain => Ok(self.project.main_module()?), + ProjectMain => Ok(self.project.main_module()), Specific(module_name) => model::module::QualifiedName::from_text(module_name), } } @@ -1545,7 +1544,7 @@ impl Model { Ok(projects) => { let entries = ProjectsToOpen::new(projects); this.displayed_project_list.set(entries.clone_ref()); - let any_entries:AnyEntryProvider = entries.into(); + let any_entries = AnyModelProvider::new(entries); this.view.open_dialog().project_list.set_entries(any_entries) }, Err(error) => error!(this.logger,"Error when loading project's list: {error}"), @@ -1943,10 +1942,11 @@ impl ProjectsToOpen { } } -impl list_view::entry::EntryProvider for ProjectsToOpen { +impl list_view::entry::ModelProvider for ProjectsToOpen { fn entry_count(&self) -> usize { self.projects.len() } - fn get(&self, app: &Application, id: usize) -> Option { - Some(open_dialog::project_list::Entry::new(app, self.projects.get(id)?.name.as_str()).into()) + fn get(&self, id:list_view::entry::Id) + -> Option< ::Model> { + Some(<[controller::ide::ProjectMetadata]>::get(&self.projects,id)?.name.clone().into()) } } diff --git a/src/rust/ide/view/src/open_dialog.rs b/src/rust/ide/view/src/open_dialog.rs index 0c88490b76..8fd975f5ac 100644 --- a/src/rust/ide/view/src/open_dialog.rs +++ b/src/rust/ide/view/src/open_dialog.rs @@ -5,7 +5,6 @@ use crate::prelude::*; use enso_frp as frp; use ensogl::display; -use ensogl_gui_components::file_browser; use ensogl_gui_components::file_browser::FileBrowser; use ensogl::application::Application; use ensogl::display::shape::StyleWatchFrp; @@ -36,11 +35,14 @@ pub struct OpenDialog { impl OpenDialog { /// Create Open Dialog component. pub fn new(app:&Application) -> Self { - let logger = Logger::new("OpenDialog"); - let network = frp::Network::new("OpenDialog"); - let style_watch = StyleWatchFrp::new(&app.display.scene().style_sheet); - let project_list = project_list::ProjectList::new(app); - let file_browser = app.new_view::(); + let logger = Logger::new("OpenDialog"); + let network = frp::Network::new("OpenDialog"); + let style_watch = StyleWatchFrp::new(&app.display.scene().style_sheet); + let project_list = project_list::ProjectList::new(app); + let file_browser = FileBrowser::new(); + // Once FileBrowser will be implemented as component, it should be instantiated this way: + //let file_browser = app.new_view::(); + let display_object = display::object::Instance::new(&logger); display_object.add_child(&project_list); @@ -49,14 +51,15 @@ impl OpenDialog { use theme::application as theme_app; let project_list_width = style_watch.get_number(theme_app::project_list::width); + let file_browser_width = style_watch.get_number(theme_app::file_browser::width); let gap_between_panels = style_watch.get_number(theme_app::open_dialog::gap_between_panels); frp::extend! { network init <- source::<()>(); - width <- all_with3(&project_list_width,&gap_between_panels,&init, - |pw,g,()| *pw + *g + file_browser::WIDTH + width <- all_with4(&project_list_width,&file_browser_width,&gap_between_panels,&init, + |pw,fw,g,()| *pw + *g + *fw ); project_list_x <- all_with(&width,&project_list_width,|w,pw| - *w / 2.0 + *pw / 2.0); - file_browser_x <- width.map(|w| w / 2.0 - file_browser::WIDTH / 2.0); + file_browser_x <- all_with(&width,&file_browser_width, |w,fw| w / 2.0 - *fw / 2.0); eval project_list_x ((x) project_list.set_position_x(*x)); eval file_browser_x ((x) file_browser.set_position_x(*x)); diff --git a/src/rust/ide/view/src/open_dialog/project_list.rs b/src/rust/ide/view/src/open_dialog/project_list.rs index b61619095c..8487aef0bb 100644 --- a/src/rust/ide/view/src/open_dialog/project_list.rs +++ b/src/rust/ide/view/src/open_dialog/project_list.rs @@ -17,52 +17,8 @@ use ensogl_theme::application::project_list as theme; // === Entry === // ============= -/// The project entry widget for the [`list_view::ListView`] inside [`ProjectList`]. -#[derive(Clone,CloneRef,Debug)] -pub struct Entry { - display_object : display::object::Instance, - network : frp::Network, - style_watch : StyleWatchFrp, - label : ensogl_text::Area, -} - -impl Entry { - /// Create entry for a project with given name. - pub fn new(app:&Application, name:impl Str) -> Self { - let logger = Logger::new("project_list::Entry"); - let display_object = display::object::Instance::new(logger); - let network = frp::Network::new("project_list::Entry"); - let label = app.new_view::(); - let style_watch = StyleWatchFrp::new(&app.display.scene().style_sheet); - let text_color = style_watch.get_color(theme::text); - let text_size = style_watch.get_number(theme::text::size); - let text_padding = style_watch.get_number(theme::text::padding); - display_object.add_child(&label); - label.set_default_color(text_color.value()); - label.set_default_text_size(text::Size(text_size.value())); - label.set_position_xy(Vector2(text_padding.value(), text_size.value() / 2.0)); - label.set_content(name.as_ref()); - label.remove_from_scene_layer(&app.display.scene().layers.main); - label.add_to_scene_layer(&app.display.scene().layers.panel_text); - frp::extend! { network - eval text_color ((color) label.set_default_color(color)); - eval text_size ((size) label.set_default_text_size(text::Size(*size))); - eval text_padding ((padding) label.set_position_x(*padding)); - } - Self {display_object,network,style_watch,label} - } -} - -impl display::Object for Entry { - fn display_object(&self) -> &display::object::Instance { &self.display_object } -} - -impl list_view::entry::Entry for Entry { - fn set_focused(&self, _selected: bool) {} - - fn set_width(&self, _width: f32) {} -} - +/// The entry in project list. +pub type Entry = list_view::entry::Label; // ============== @@ -114,12 +70,12 @@ pub struct ProjectList { display_object : display::object::Instance, background : background::View, //TODO[ao] use Card instead. caption : text::Area, - list : list_view::ListView, + list : list_view::ListView, style_watch : StyleWatchFrp, } impl Deref for ProjectList { - type Target = list_view::Frp; + type Target = list_view::Frp; fn deref(&self) -> &Self::Target { &self.list.frp } } @@ -132,14 +88,14 @@ impl ProjectList { let display_object = display::object::Instance::new(&logger); let background = background::View::new(&logger); let caption = app.new_view::(); - let list = app.new_view::(); + let list = app.new_view::>(); display_object.add_child(&background); display_object.add_child(&caption); display_object.add_child(&list); app.display.scene().layers.panel.add_exclusive(&display_object); caption.set_content("Open Project"); - caption.remove_from_scene_layer(&app.display.scene().layers.main); caption.add_to_scene_layer(&app.display.scene().layers.panel_text); + list.set_label_layer(app.display.scene().layers.panel_text.id); ensogl::shapes_order_dependencies! { app.display.scene() => { From 8bf8b1590d7cf2f6efec75aae7f7311dda0d6795 Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Fri, 23 Jul 2021 13:26:17 +0200 Subject: [PATCH 24/25] Update changelog --- CHANGELOG.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index abe628a255..4ed3f22eda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,9 @@ these updates be shipped in a stable release before the end of the year. #### Visual Environment -- [File or Project Open Dialog][1700]. ctrl/cmd+o will - display a new File or Project Open Dialog. Here you can open another project, - or pick a file from browser: the file will be inserted as a node to the - current graph. - +- [New look of open project dialog.][1700]. Now it has "Open project" title on + the top. +
#### Enso Compiler @@ -22,6 +20,9 @@ these updates be shipped in a stable release before the end of the year. details in [the engine release notes](https://github.com/enso-org/enso/blob/main/RELEASES.md). +
+ +[1700]: https://github.com/enso-org/ide/pull/1700 [1710]: https://github.com/enso-org/ide/pull/1710 # Enso 2.0.0-alpha.9 (2021-07-16) @@ -38,7 +39,6 @@ these updates be shipped in a stable release before the end of the year. [1640]: https://github.com/enso-org/ide/pull/1653 - # Enso 2.0.0-alpha.8 (2021-06-09)
![New Features](/docs/assets/tags/new_features.svg) @@ -49,7 +49,7 @@ these updates be shipped in a stable release before the end of the year. enhancements and fixes made to the Enso compiler, you can find out more details in [the engine release notes](https://github.com/enso-org/enso/blob/main/RELEASES.md). - + [1640]: https://github.com/enso-org/ide/pull/1640
From b7a48988e1e25d81dd4c064ac54ea35b9378bdb4 Mon Sep 17 00:00:00 2001 From: Adam Obuchowicz Date: Fri, 23 Jul 2021 16:11:56 +0200 Subject: [PATCH 25/25] Fix linter warnings --- src/rust/ensogl/lib/components/src/file_browser.rs | 11 ++++++++--- src/rust/ide/src/ide/integration/file_system.rs | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/rust/ensogl/lib/components/src/file_browser.rs b/src/rust/ensogl/lib/components/src/file_browser.rs index 0de9485536..fe59090a24 100644 --- a/src/rust/ensogl/lib/components/src/file_browser.rs +++ b/src/rust/ensogl/lib/components/src/file_browser.rs @@ -54,6 +54,12 @@ pub struct FileBrowser { display_object : display::object::Instance, } +impl Deref for FileBrowser { + type Target = Frp; + fn deref(&self) -> &Self::Target { &self.frp } +} + + impl FileBrowser { /// Constructore pub fn new() -> Self { @@ -64,9 +70,8 @@ impl FileBrowser { } } -impl Deref for FileBrowser { - type Target = Frp; - fn deref(&self) -> &Self::Target { &self.frp } +impl Default for FileBrowser { + fn default() -> Self { Self::new() } } impl display::Object for FileBrowser { diff --git a/src/rust/ide/src/ide/integration/file_system.rs b/src/rust/ide/src/ide/integration/file_system.rs index fa1ab8c267..e86f3a5194 100644 --- a/src/rust/ide/src/ide/integration/file_system.rs +++ b/src/rust/ide/src/ide/integration/file_system.rs @@ -265,7 +265,7 @@ pub async fn do_file_operation let src_name = ls_source.file_name().ok_or_else( || InvalidSourceFile{path:source.to_string_lossy().to_string()} )?; - let dest_name = pick_non_colliding_name(&*json_rpc,&ls_dest,&src_name).await?; + let dest_name = pick_non_colliding_name(&*json_rpc,&ls_dest,src_name).await?; let dest_full = ls_dest.append_im(dest_name); match operation { FileOperation::Copy => json_rpc.copy_file(&ls_source, &dest_full).await?,