Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ semver Intersection would incorrectly pass if an exact version is compared again
no overlap.
- #1077: Fixed error handling of dependency resolution to correctly report what the offending
modules are.
- #1187: Remove extra path entries in output of %IPM.Storage.ResourceReference:ResolveChildren() that broke unguarded downstream callers.

## [0.10.7] - 2026-05-29

Expand Down
3 changes: 1 addition & 2 deletions src/cls/IPM/ResourceProcessor/Test.cls
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,7 @@ Method OnResolveChildren(ByRef pResourceArray) As %Status
set tResourceInfo("UnitTest") = 1
set tResource = $case(..Package '= "", 1: ..Package, : ..Class)_..Extension
// GetChildren has Output semantics — it kills its output array before populating it.
// Using tClassArray (not pResourceArray directly) preserves any existing entries
// in pResourceArray (e.g., the "/tests/" path entry added before this call).
// Use tClassArray as the intermediate to avoid killing any existing entries in pResourceArray.
kill tClassArray
$$$ThrowOnError(##class(%IPM.Storage.ResourceReference).GetChildren(tResource,tModuleName,1,.tResourceInfo,.tClassArray))
$$$ThrowOnError(..EmbeddedProcessor.OnResolveChildren(.tClassArray))
Expand Down
5 changes: 5 additions & 0 deletions src/cls/IPM/Storage/Module.cls
Original file line number Diff line number Diff line change
Expand Up @@ -1371,6 +1371,11 @@ Method GetResolvedReferences(
kill tempArray("Scope")
if ..HasScope(pPhases, resourceScope) && ..HasScope(pPhases, attrScope) {
merge pReferenceArray(..Name) = tempArray
// ResolveChildren does not emit path entries for document enumeration. Re-add here
// because ExportSingleModule needs the path entry to trigger its directory-copy branch.
if $extract(tResource.Name) = "/" {
set pReferenceArray(..Name, tResource.Name) = ..Name
}
}
if $$$ISERR(tSC) {
quit
Expand Down
2 changes: 1 addition & 1 deletion src/cls/IPM/Storage/ResourceReference.cls
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ ClassMethod GetChildren(
quit
}
} else {
if pResourceName '= "" {
if (pResourceName '= "") && ($extract(pResourceName) '= "/") {
merge pResourceArray(pResourceName) = pResourceInfoArray
}

Expand Down
35 changes: 35 additions & 0 deletions tests/integration_tests/Test/PM/Integration/IncludeTests.cls
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,39 @@ Method TestIncludeTestsModuleXml()
}
}

// Regression test: ResolveChildren must not return path entries (names starting with /)
// as top-level keys. Path resources have no Studio document representation; returning them
// as document names can crash callers.
Method TestResolveChildrenNoPathEntries()
{
set status = $$$OK
try {
set testRoot = ##class(%File).NormalizeDirectory($get(^UnitTestRoot))
set moduleDir = ##class(%File).NormalizeDirectory(##class(%File).GetDirectory(testRoot)_"/_data/test-output-format/")
set status = ##class(%IPM.Main).Shell("load "_moduleDir)
do $$$AssertStatusOK(status,"Loaded test-output-format module successfully.")

set module = ##class(%IPM.Storage.Module).NameOpen("test-output-format",,.status)
do $$$AssertStatusOK(status,"Opened test-output-format module.")

set key = ""
for {
set tResource = module.Resources.GetNext(.key)
quit:(key = "")
kill tChildren
do $$$AssertStatusOK(tResource.ResolveChildren(.tChildren),"ResolveChildren succeeded for "_tResource.Name)
set childKey = ""
for {
set childKey = $order(tChildren(childKey))
quit:(childKey = "")
if $extract(childKey) = "/" {
do $$$AssertTrue(0,"Path entry '"_childKey_"' found in ResolveChildren output for "_tResource.Name)
}
}
}
} catch e {
do $$$AssertStatusOK(e.AsStatus(),"An exception occurred.")
}
}

}
Loading