Repository: GraphiteEditor/Graphite
File: editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs (Rust)

Code before:
			)])
		}),
	);
	map
}

pub fn resolve_document_node_type(identifier: &str) -> Option<&DocumentNodeDefinition> {
	DOCUMENT_NODE_TYPES.iter().find(|definition| definition.identifier == identifier)
}

pub fn collect_node_types() -> Vec<FrontendNodeType> {
	DOCUMENT_NODE_TYPES
		.iter()
		.filter(|definition| !definition.category.is_empty())
		.map(|definition| {
			let input_types = definition
				.node_template
				.document_node
				.inputs
				.iter()
				.filter_map(|node_input| {
					if let Some(node_value) = node_input.as_value() {
						Some(node_value.ty().nested_type().to_string())
					} else {
						None
					}
				})
				.collect::<Vec<String>>();

			FrontendNodeType::with_input_types(definition.identifier, definition.category, input_types)
		})
		.collect()
}

pub fn collect_node_descriptions() -> Vec<(String, String)> {
	DOCUMENT_NODE_TYPES
		.iter()
		.map(|definition| (definition.identifier.to_string(), definition.description.to_string()))
		.collect()
}

impl DocumentNodeDefinition {
	/// Converts the [DocumentNodeDefinition] type to a [NodeTemplate], using the provided `input_override` and falling back to the default inputs.
	/// `input_override` does not have to be the correct length.
	pub fn node_template_input_override(&self, input_override: impl IntoIterator<Item = Option<NodeInput>>) -> NodeTemplate {
		let mut template = self.node_template.clone();
		input_override.into_iter().enumerate().for_each(|(index, input_override)| {
			if let Some(input_override) = input_override {
				// Only value inputs can be overridden, since node inputs change graph structure and must be handled by the network interface
				// assert!(matches!(input_override, NodeInput::Value { .. }), "Only value inputs are supported for input overrides");
				template.document_node.inputs[index] = input_override;

Review comment (suggestion):
This ignores nodes that are compatible with multiple types. For example the transform node works on `Instances<Image<Colour>>` (if you paste a raster image into the document). However system will filter out the transform node for raster data.

Code after:
				]);
			}

			Ok(vec![LayoutGroup::Row { widgets }])
		}),
	);
	map.insert(
		"text_area".to_string(),
		Box::new(|node_id, index, context| {
			let (document_node, input_name) = node_properties::query_node_and_input_name(node_id, index, context)?;
			Ok(vec![LayoutGroup::Row {
				widgets: node_properties::text_area_widget(document_node, node_id, index, input_name, true),
			}])
		}),
	);
	map.insert(
		"text_font".to_string(),
		Box::new(|node_id, index, context| {
			let (document_node, input_name) = node_properties::query_node_and_input_name(node_id, index, context)?;
			let (font, style) = node_properties::font_inputs(document_node, node_id, index, input_name, true);
			let mut result = vec![LayoutGroup::Row { widgets: font }];
			if let Some(style) = style {
				result.push(LayoutGroup::Row { widgets: style });
			}
			Ok(result)
		}),
	);
	map.insert(
		"artboard_background".to_string(),
		Box::new(|node_id, index, context| {
			let (document_node, input_name) = node_properties::query_node_and_input_name(node_id, index, context)?;
			Ok(vec![node_properties::color_widget(
				document_node,
				node_id,
				index,
				input_name,
				ColorInput::default().allow_none(false),
				true,
			)])
		}),
	);
	map
}

pub fn resolve_document_node_type(identifier: &str) -> Option<&DocumentNodeDefinition> {
	DOCUMENT_NODE_TYPES.iter().find(|definition| definition.identifier == identifier)
}

pub fn collect_node_types() -> Vec<FrontendNodeType> {
	// Create a mapping from registry ID to document node identifier
	let id_to_identifier_map: HashMap<String, &'static str> = DOCUMENT_NODE_TYPES