forked from rojo-rbx/rojo
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:
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "infer-service-name",
|
||||||
|
"tree": {
|
||||||
|
"$className": "DataModel",
|
||||||
|
"ReplicatedStorage": {
|
||||||
|
"Main": {
|
||||||
|
"$path": "main.lua"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"HttpService": {
|
||||||
|
"$properties": {
|
||||||
|
"HttpEnabled": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
rojo-test/build-tests/infer_service_name/main.lua
Normal file
1
rojo-test/build-tests/infer_service_name/main.lua
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-- hello, from main
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "infer-service-name",
|
||||||
|
"tree": {
|
||||||
|
"$className": "DataModel",
|
||||||
|
|
||||||
|
"StarterPlayer": {
|
||||||
|
"StarterPlayerScripts": {},
|
||||||
|
"StarterCharacterScripts": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
rojo-test/build-tests/infer_starter_player/main.lua
Normal file
1
rojo-test/build-tests/infer_starter_player/main.lua
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-- hello, from main
|
||||||
@@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ children:
|
|||||||
- /foo
|
- /foo
|
||||||
- Child
|
- Child
|
||||||
- $className: Model
|
- $className: Model
|
||||||
|
- Folder
|
||||||
relevant_paths: []
|
relevant_paths: []
|
||||||
context: {}
|
context: {}
|
||||||
name: Child
|
name: Child
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ children:
|
|||||||
- /foo
|
- /foo
|
||||||
- SomeChild
|
- SomeChild
|
||||||
- $className: Model
|
- $className: Model
|
||||||
|
- Folder
|
||||||
relevant_paths: []
|
relevant_paths: []
|
||||||
context: {}
|
context: {}
|
||||||
name: SomeChild
|
name: SomeChild
|
||||||
|
|||||||
Reference in New Issue
Block a user