Skip to content

Commit 4d5fbf3

Browse files
kalunkuojohnpiersonCopilot
authored
DYN-10119: Add IValueSchemaProvider and typeIds to DefineData (#17040)
Co-authored-by: john pierson <sixtysecondrevit@gmail.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent 3d92ce3 commit 4d5fbf3

6 files changed

Lines changed: 166 additions & 39 deletions

File tree

doc/distrib/xml/en-US/DSCoreNodes.xml

Lines changed: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
namespace Dynamo.Graph.Nodes
2+
{
3+
/// <summary>
4+
/// Implemented by NodeModels that can describe their value type
5+
/// for external consumers (DynamoPlayer, MCP, etc.).
6+
/// Returns a canonical Forge Data Schema type identifier and list context.
7+
/// </summary>
8+
public interface IValueSchemaProvider
9+
{
10+
/// <summary>
11+
/// Type identifier matching the Player ValueSchema.TypeId wire format.
12+
/// For geometry/complex types: Forge Data Schema URN (e.g. "autodesk.math:point3d-1.0.0").
13+
/// For primitives: ForgeDataSchemaType values (e.g. "Float64", "String", "Bool", "Int64").
14+
/// Returns a non-null type identifier. If the type is not yet determined,
15+
/// implementations should return their existing non-null fallback value.
16+
/// </summary>
17+
string ValueTypeId { get; }
18+
19+
/// <summary>
20+
/// Whether the value is a list (array) of the declared type.
21+
/// </summary>
22+
bool IsListValue { get; }
23+
}
24+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
Dynamo.Graph.Nodes.IValueSchemaProvider
2+
Dynamo.Graph.Nodes.IValueSchemaProvider.IsListValue.get -> bool
3+
Dynamo.Graph.Nodes.IValueSchemaProvider.ValueTypeId.get -> string
14
Dynamo.Models.DynamoModel.DefaultStartConfiguration.EnableUnTrustedLocationsNotifications.get -> bool
25
Dynamo.Models.DynamoModel.DefaultStartConfiguration.EnableUnTrustedLocationsNotifications.set -> void
36
Dynamo.Models.DynamoModel.IStartConfiguration.EnableUnTrustedLocationsNotifications.get -> bool

src/Libraries/CoreNodeModels/DefineData.cs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,25 @@ namespace CoreNodeModels
2525
[OutPortDescriptions(typeof(Properties.Resources), nameof(Properties.Resources.DefineDataOutputTooltip))]
2626
[IsDesignScriptCompatible]
2727
[AlsoKnownAs("Data.DefineData")]
28-
public class DefineData : DSDropDownBase
28+
public class DefineData : DSDropDownBase, IValueSchemaProvider
2929
{
30+
/// <inheritdoc/>
31+
[JsonIgnore]
32+
public string ValueTypeId
33+
{
34+
get
35+
{
36+
if (SelectedIndex < 0 || SelectedIndex >= Items.Count)
37+
return SelectedString;
38+
39+
return (Items[SelectedIndex].Item as Data.DataNodeDynamoType)?.TypeId ?? SelectedString;
40+
}
41+
}
42+
43+
/// <inheritdoc/>
44+
[JsonIgnore]
45+
public bool IsListValue => IsList;
46+
3047
private bool isAutoMode = true; // default start with auto-detect 'on'
3148
private bool isList;
3249
private string displayValue = Properties.Resources.DefineDataDisplayValueMessage;

src/Libraries/CoreNodes/Data.cs

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,7 @@ public static Dictionary<string, object> Remember([ArbitraryDimensionArrayImport
534534
/// <summary>
535535
/// A class representing a DataType supported by Dynamo
536536
/// </summary>
537-
internal class DataNodeDynamoType(Type type, string name = null)
537+
internal class DataNodeDynamoType(Type type, string name = null, string typeId = null)
538538
{
539539
/// <summary>
540540
/// The underlying Type
@@ -545,6 +545,11 @@ internal class DataNodeDynamoType(Type type, string name = null)
545545
/// </summary>
546546
public string Name { get; private set; } = name ?? type.Name;
547547
/// <summary>
548+
/// Wire-format $typeid (e.g. "autodesk.math:point3d-1.0.0").
549+
/// Null for primitive types that don't use $typeid serialization.
550+
/// </summary>
551+
public string TypeId { get; private set; } = typeId;
552+
/// <summary>
548553
/// The hierarchical level to be displayed in the UI
549554
/// </summary>
550555
public int Level { get; private set; } = 0;
@@ -557,8 +562,8 @@ internal class DataNodeDynamoType(Type type, string name = null)
557562
/// </summary>
558563
public DataNodeDynamoType Parent { get; private set; }
559564

560-
public DataNodeDynamoType(Type type, int level, bool isLastChild = false, string name = null, DataNodeDynamoType parent = null)
561-
: this(type, name)
565+
public DataNodeDynamoType(Type type, int level, bool isLastChild = false, string name = null, DataNodeDynamoType parent = null, string typeId = null)
566+
: this(type, name, typeId)
562567
{
563568
Level = level;
564569
IsLastChild = isLastChild;
@@ -577,53 +582,55 @@ public DataNodeDynamoType(Type type, int level, bool isLastChild = false, string
577582
/// </summary>
578583
static Data()
579584
{
580-
var curve = new DataNodeDynamoType(typeof(Curve), 0, false, null, null);
581-
var polyCurve = new DataNodeDynamoType(typeof(PolyCurve), 1, false, null, curve);
582-
var polygon = new DataNodeDynamoType(typeof(Polygon), 2, false, null, polyCurve); // polygon is subtype of polyCurve
583-
var rectangle = new DataNodeDynamoType(typeof(Autodesk.DesignScript.Geometry.Rectangle), 3, true, null, polyCurve); // rectangle is subtype of polygon
584-
var solid = new DataNodeDynamoType(typeof(Solid), 0, false, null, null);
585-
var cone = new DataNodeDynamoType(typeof(Cone), 1, false, null, solid); // cone is subtype of solid
586-
var cylinder = new DataNodeDynamoType(typeof(Cylinder), 2, false, null, cone); // cylinder is subtype of cone
587-
var cuboid = new DataNodeDynamoType(typeof(Cuboid), 1, false, null, solid); // cuboid is subtype of solid
588-
var sphere = new DataNodeDynamoType(typeof(Sphere), 1, true, null, solid); // sphere is subtype of solid
589-
590-
var surface = new DataNodeDynamoType(typeof(Surface), 0, false, null, null);
585+
var curve = new DataNodeDynamoType(typeof(Curve), 0, false, null, null, "dynamo.geometry:sab-1.0.0");
586+
var polyCurve = new DataNodeDynamoType(typeof(PolyCurve), 1, false, null, curve, "autodesk.geometry.curve:compositecurve-1.0.0");
587+
var polygon = new DataNodeDynamoType(typeof(Polygon), 2, false, null, polyCurve, "autodesk.geometry.curve:polyline-1.0.0");
588+
var rectangle = new DataNodeDynamoType(typeof(Autodesk.DesignScript.Geometry.Rectangle), 3, true, null, polyCurve, "dynamo.geometry:rectangle-1.0.0");
589+
var solid = new DataNodeDynamoType(typeof(Solid), 0, false, null, null, "dynamo.geometry:sab-1.0.0");
590+
var cone = new DataNodeDynamoType(typeof(Cone), 1, false, null, solid, "dynamo.geometry:cone-1.0.0");
591+
var cylinder = new DataNodeDynamoType(typeof(Cylinder), 2, false, null, cone, "autodesk.geometry.surface:cylinder-2.0.0");
592+
var cuboid = new DataNodeDynamoType(typeof(Cuboid), 1, false, null, solid, "dynamo.geometry:cuboid-1.0.0");
593+
var sphere = new DataNodeDynamoType(typeof(Sphere), 1, true, null, solid, "autodesk.geometry.surface:sphere-1.0.0");
594+
595+
var surface = new DataNodeDynamoType(typeof(Surface), 0, false, null, null, "dynamo.geometry:sab-1.0.0");
591596

592597
var typeList = new List<DataNodeDynamoType>
593598
{
594-
new(typeof(bool)),
595-
new(typeof(BoundingBox)),
596-
new(typeof(CoordinateSystem)),
599+
new(typeof(bool), typeId: "Bool"),
600+
new(typeof(BoundingBox), typeId: "autodesk.geometry:boundingbox3d-1.0.0"),
601+
new(typeof(CoordinateSystem), typeId: "autodesk.math:matrix44d-1.0.0"),
602+
new(typeof(DSCore.Color), typeId: "dynamo.graphics:color-1.0.0"),
597603
curve,
598-
new(typeof(Arc), 1, false, null, curve),
599-
new(typeof(Circle), 1, false, null, curve),
600-
new(typeof(Ellipse), 1, false, null, curve),
601-
new(typeof(EllipseArc), 1, false, null, curve),
602-
new(typeof(Helix), 1, false, null, curve),
603-
new(typeof(Line), 1, false, null, curve),
604-
new(typeof(NurbsCurve), 1, false, null, curve),
604+
new(typeof(Arc), 1, false, null, curve, "autodesk.geometry.curve:circle-1.0.0"),
605+
new(typeof(Circle), 1, false, null, curve, "autodesk.geometry.curve:circle-1.0.0"),
606+
new(typeof(Ellipse), 1, false, null, curve, "autodesk.geometry.curve:ellipse-1.0.0"),
607+
new(typeof(EllipseArc), 1, false, null, curve, "autodesk.geometry.curve:ellipse-1.0.0"),
608+
new(typeof(Helix), 1, false, null, curve, "dynamo.geometry:sab-1.0.0"),
609+
new(typeof(System.Drawing.Bitmap), "Image", typeId: "dynamo.graphics:png-1.0.0"),
610+
new(typeof(Line), 1, false, null, curve, "autodesk.geometry.curve:line-1.0.0"),
611+
new(typeof(NurbsCurve), 1, false, null, curve, "autodesk.geometry.curve:bcurve-1.0.0"),
605612
polyCurve,
606613
polygon,
607614
rectangle,
608-
new(typeof(System.DateTime)),
609-
new(typeof(double), "Number"),
610-
new(typeof(long), "Integer"),
611-
new(typeof(Location)),
612-
new(typeof(Mesh)),
613-
new(typeof(Plane)),
614-
new(typeof(Autodesk.DesignScript.Geometry.Point)),
615+
new(typeof(System.DateTime), typeId: "DateTime"),
616+
new(typeof(double), "Number", typeId: "Float64"),
617+
new(typeof(long), "Integer", typeId: "Int64"),
618+
new(typeof(Location), typeId: "dynamo.data:location-1.0.0"),
619+
new(typeof(Mesh), typeId: "dynamo.geometry:mesh-1.0.0"),
620+
new(typeof(Plane), typeId: "autodesk.geometry.surface:plane-1.0.0"),
621+
new(typeof(Autodesk.DesignScript.Geometry.Point), typeId: "autodesk.math:point3d-1.0.0"),
615622
solid,
616623
cone,
617624
cylinder,
618625
cuboid,
619626
sphere,
620-
new(typeof(string)),
627+
new(typeof(string), typeId: "String"),
621628
surface,
622-
new(typeof(NurbsSurface), 1, false, null, surface),
623-
new(typeof(PolySurface), 1, true, null, surface),
624-
new(typeof(System.TimeSpan)),
625-
new(typeof(UV)),
626-
new(typeof(Vector))
629+
new(typeof(NurbsSurface), 1, false, null, surface, "autodesk.geometry.curve:bsurface-1.0.0"),
630+
new(typeof(PolySurface), 1, true, null, surface, "dynamo.geometry:sab-1.0.0"),
631+
new(typeof(System.TimeSpan), typeId: "TimeSpan"),
632+
new(typeof(UV), typeId: "autodesk.math:uv-1.0.0"),
633+
new(typeof(Vector), typeId: "autodesk.math:vector3d-1.0.0")
627634
};
628635

629636
DataNodeDynamoTypeList = new ReadOnlyCollection<DataNodeDynamoType>(typeList);
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using CoreNodeModels;
4+
using NUnit.Framework;
5+
6+
namespace Dynamo.Tests.Nodes
7+
{
8+
[TestFixture]
9+
internal class DefineDataTests : DynamoModelTestBase
10+
{
11+
protected override void GetLibrariesToPreload(List<string> libraries)
12+
{
13+
libraries.Add("DSCoreNodes.dll");
14+
base.GetLibrariesToPreload(libraries);
15+
}
16+
17+
[Test]
18+
[Category("UnitTests")]
19+
public void ValueSchemaProviderReturnsTypeId()
20+
{
21+
var node = new DefineData();
22+
CurrentDynamoModel.CurrentWorkspace.AddAndRegisterNode(node, false);
23+
24+
// Find a type with a non-null TypeId for testing
25+
var pointType = DSCore.Data.DataNodeDynamoTypeList.First(t => t.Type == typeof(Autodesk.DesignScript.Geometry.Point));
26+
Assert.IsNotNull(pointType.TypeId, "Point type should have a valid TypeId");
27+
28+
// Set the node to Point type
29+
node.SelectedIndex = DSCore.Data.DataNodeDynamoTypeList.IndexOf(pointType);
30+
31+
Assert.AreEqual(pointType.TypeId, node.ValueTypeId);
32+
Assert.IsFalse(node.IsListValue);
33+
}
34+
35+
[Test]
36+
[Category("UnitTests")]
37+
public void ValueTypeIdSafeWhenNoSelection()
38+
{
39+
var node = new DefineData();
40+
Assert.DoesNotThrow(() => { var _ = node.ValueTypeId; });
41+
Assert.AreEqual(node.SelectedString, node.ValueTypeId);
42+
}
43+
44+
[Test]
45+
[Category("UnitTests")]
46+
public void ValueTypeIdReturnsPrimitiveTypeId()
47+
{
48+
var node = new DefineData();
49+
CurrentDynamoModel.CurrentWorkspace.AddAndRegisterNode(node, false);
50+
51+
var boolType = DSCore.Data.DataNodeDynamoTypeList.First(t => t.Type == typeof(bool));
52+
node.SelectedIndex = DSCore.Data.DataNodeDynamoTypeList.IndexOf(boolType);
53+
54+
Assert.AreEqual("Bool", node.ValueTypeId);
55+
}
56+
57+
[Test]
58+
[Category("UnitTests")]
59+
public void ValueTypeIdReturnsFloat64ForNumber()
60+
{
61+
var node = new DefineData();
62+
CurrentDynamoModel.CurrentWorkspace.AddAndRegisterNode(node, false);
63+
64+
var numberType = DSCore.Data.DataNodeDynamoTypeList.First(t => t.Type == typeof(double));
65+
node.SelectedIndex = DSCore.Data.DataNodeDynamoTypeList.IndexOf(numberType);
66+
67+
Assert.AreEqual("Float64", node.ValueTypeId);
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)