Infer class name (#210)

* infer service names

* Update project code and add support for StarterPlayer

* Store parent_class in InstigatingSource

* Update snapshots

Co-authored-by: Lucien Greathouse <me@lpghatguy.com>
This commit is contained in:
jeparlefrancais
2020-03-29 19:03:15 -04:00
committed by GitHub
parent 571ef3060a
commit 6a1fffd1ce
12 changed files with 134 additions and 11 deletions

View File

@@ -0,0 +1,28 @@
---
source: rojo-test/src/build_test.rs
expression: contents
---
<roblox version="4">
<Item class="DataModel" referent="0">
<Properties>
<string name="Name">infer-service-name</string>
</Properties>
<Item class="HttpService" referent="1">
<Properties>
<string name="Name">HttpService</string>
<bool name="HttpEnabled">true</bool>
</Properties>
</Item>
<Item class="ReplicatedStorage" referent="2">
<Properties>
<string name="Name">ReplicatedStorage</string>
</Properties>
<Item class="ModuleScript" referent="3">
<Properties>
<string name="Name">Main</string>
<string name="Source">-- hello, from main</string>
</Properties>
</Item>
</Item>
</Item>
</roblox>

View File

@@ -0,0 +1,26 @@
---
source: rojo-test/src/build_test.rs
expression: contents
---
<roblox version="4">
<Item class="DataModel" referent="0">
<Properties>
<string name="Name">infer-service-name</string>
</Properties>
<Item class="StarterPlayer" referent="1">
<Properties>
<string name="Name">StarterPlayer</string>
</Properties>
<Item class="StarterCharacterScripts" referent="2">
<Properties>
<string name="Name">StarterCharacterScripts</string>
</Properties>
</Item>
<Item class="StarterPlayerScripts" referent="3">
<Properties>
<string name="Name">StarterPlayerScripts</string>
</Properties>
</Item>
</Item>
</Item>
</roblox>

View File

@@ -0,0 +1,16 @@
{
"name": "infer-service-name",
"tree": {
"$className": "DataModel",
"ReplicatedStorage": {
"Main": {
"$path": "main.lua"
}
},
"HttpService": {
"$properties": {
"HttpEnabled": true
}
}
}
}

View File

@@ -0,0 +1 @@
-- hello, from main

View File

@@ -0,0 +1,11 @@
{
"name": "infer-service-name",
"tree": {
"$className": "DataModel",
"StarterPlayer": {
"StarterPlayerScripts": {},
"StarterCharacterScripts": {}
}
}
}

View File

@@ -0,0 +1 @@
-- hello, from main

View File

@@ -28,6 +28,8 @@ gen_build_tests! {
csv_in_folder, csv_in_folder,
deep_nesting, deep_nesting,
gitkeep, gitkeep,
infer_service_name,
infer_starter_player,
init_meta_class_name, init_meta_class_name,
init_meta_properties, init_meta_properties,
init_with_children, init_with_children,
@@ -38,10 +40,10 @@ gen_build_tests! {
module_init, module_init,
rbxm_in_folder, rbxm_in_folder,
rbxmx_in_folder, rbxmx_in_folder,
rbxmx_ref,
script_meta_disabled, script_meta_disabled,
server_in_folder, server_in_folder,
server_init, server_init,
rbxmx_ref,
txt, txt,
txt_in_folder, txt_in_folder,
} }

View File

@@ -178,7 +178,7 @@ impl JobThreadContext {
if let Some(instigating_source) = &instance.metadata().instigating_source { if let Some(instigating_source) = &instance.metadata().instigating_source {
match instigating_source { match instigating_source {
InstigatingSource::Path(path) => fs::remove_file(path).unwrap(), InstigatingSource::Path(path) => fs::remove_file(path).unwrap(),
InstigatingSource::ProjectNode(_, _, _) => { InstigatingSource::ProjectNode(_, _, _, _) => {
log::warn!( log::warn!(
"Cannot remove instance {}, it's from a project file", "Cannot remove instance {}, it's from a project file",
id id
@@ -226,7 +226,7 @@ impl JobThreadContext {
log::warn!("Cannot change Source to non-string value."); log::warn!("Cannot change Source to non-string value.");
} }
} }
InstigatingSource::ProjectNode(_, _, _) => { InstigatingSource::ProjectNode(_, _, _, _) => {
log::warn!( log::warn!(
"Cannot remove instance {}, it's from a project file", "Cannot remove instance {}, it's from a project file",
id id
@@ -318,7 +318,7 @@ fn compute_and_apply_changes(tree: &mut RojoTree, vfs: &Vfs, id: RbxId) -> Optio
} }
}, },
InstigatingSource::ProjectNode(project_path, instance_name, project_node) => { InstigatingSource::ProjectNode(project_path, instance_name, project_node, parent_class) => {
// This instance is the direct subject of a project node. Since // This instance is the direct subject of a project node. Since
// there might be information associated with our instance from // there might be information associated with our instance from
// the project file, we snapshot the entire project node again. // the project file, we snapshot the entire project node again.
@@ -329,6 +329,7 @@ fn compute_and_apply_changes(tree: &mut RojoTree, vfs: &Vfs, id: RbxId) -> Optio
instance_name, instance_name,
project_node, project_node,
&vfs, &vfs,
parent_class.as_ref().map(|name| name.as_str()),
); );
let snapshot = match snapshot_result { let snapshot = match snapshot_result {

View File

@@ -163,6 +163,7 @@ pub enum InstigatingSource {
#[serde(serialize_with = "path_serializer::serialize_absolute")] PathBuf, #[serde(serialize_with = "path_serializer::serialize_absolute")] PathBuf,
String, String,
ProjectNode, ProjectNode,
Option<String>,
), ),
} }
@@ -170,12 +171,13 @@ impl fmt::Debug for InstigatingSource {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
InstigatingSource::Path(path) => write!(formatter, "Path({})", path.display()), InstigatingSource::Path(path) => write!(formatter, "Path({})", path.display()),
InstigatingSource::ProjectNode(path, name, node) => write!( InstigatingSource::ProjectNode(path, name, node, parent_class) => write!(
formatter, formatter,
"ProjectNode({}: {:?}) from path {}", "ProjectNode({}: {:?}) from path {} and parent class {:?}",
name, name,
node, node,
path.display() path.display(),
parent_class,
), ),
} }
} }

View File

@@ -1,7 +1,7 @@
use std::{borrow::Cow, collections::HashMap, path::Path}; use std::{borrow::Cow, collections::HashMap, path::Path};
use memofs::{IoResultExt, Vfs}; use memofs::{IoResultExt, Vfs};
use rbx_reflection::try_resolve_value; use rbx_reflection::{get_class_descriptor, try_resolve_value};
use crate::{ use crate::{
project::{Project, ProjectNode}, project::{Project, ProjectNode},
@@ -62,6 +62,7 @@ impl SnapshotMiddleware for SnapshotProject {
&project.name, &project.name,
&project.tree, &project.tree,
vfs, vfs,
None,
)? )?
.unwrap(); .unwrap();
@@ -93,6 +94,7 @@ pub fn snapshot_project_node(
instance_name: &str, instance_name: &str,
node: &ProjectNode, node: &ProjectNode,
vfs: &Vfs, vfs: &Vfs,
parent_class: Option<&str>,
) -> SnapshotInstanceResult { ) -> SnapshotInstanceResult {
let name = Cow::Owned(instance_name.to_owned()); let name = Cow::Owned(instance_name.to_owned());
let mut class_name = node let mut class_name = node
@@ -158,13 +160,43 @@ pub fn snapshot_project_node(
} }
let class_name = class_name let class_name = class_name
.or_else(|| {
// If className wasn't defined from another source, we may be able
// to infer one.
let parent_class = parent_class?;
if parent_class == "DataModel" {
// Members of DataModel with names that match known services are
// probably supposed to be those services.
let descriptor = get_class_descriptor(&name)?;
if descriptor.is_service() {
return Some(name.clone());
}
} else if parent_class == "StarterPlayer" {
// StarterPlayer has two special members with their own classes.
if name == "StarterPlayerScripts" || name == "StarterCharacterScripts" {
return Some(name.clone());
}
}
None
})
// TODO: Turn this into an error object. // TODO: Turn this into an error object.
.expect("$className or $path must be specified"); .expect("$className or $path must be specified");
for (child_name, child_project_node) in &node.children { for (child_name, child_project_node) in &node.children {
if let Some(child) = if let Some(child) = snapshot_project_node(
snapshot_project_node(context, project_folder, child_name, child_project_node, vfs)? context,
{ project_folder,
child_name,
child_project_node,
vfs,
Some(&class_name),
)? {
children.push(child); children.push(child);
} }
} }
@@ -194,6 +226,7 @@ pub fn snapshot_project_node(
project_folder.to_path_buf(), project_folder.to_path_buf(),
instance_name.to_string(), instance_name.to_string(),
node.clone(), node.clone(),
parent_class.map(|name| name.to_owned()),
)); ));
Ok(Some(InstanceSnapshot { Ok(Some(InstanceSnapshot {

View File

@@ -22,6 +22,7 @@ children:
- /foo - /foo
- Child - Child
- $className: Model - $className: Model
- Folder
relevant_paths: [] relevant_paths: []
context: {} context: {}
name: Child name: Child

View File

@@ -23,6 +23,7 @@ children:
- /foo - /foo
- SomeChild - SomeChild
- $className: Model - $className: Model
- Folder
relevant_paths: [] relevant_paths: []
context: {} context: {}
name: SomeChild name: SomeChild