com.wallstop-studios.unity-helpers 2.0.4 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Docs/DATA_STRUCTURES.md +7 -7
- package/Docs/EFFECTS_SYSTEM.md +836 -8
- package/Docs/EFFECTS_SYSTEM_TUTORIAL.md +77 -18
- package/Docs/HULLS.md +2 -2
- package/Docs/RANDOM_PERFORMANCE.md +1 -1
- package/Docs/REFLECTION_HELPERS.md +1 -1
- package/Docs/RELATIONAL_COMPONENTS.md +51 -6
- package/Docs/SERIALIZATION.md +1 -1
- package/Docs/SINGLETONS.md +2 -2
- package/Docs/SPATIAL_TREES_2D_GUIDE.md +3 -3
- package/Docs/SPATIAL_TREES_3D_GUIDE.md +3 -3
- package/Docs/SPATIAL_TREE_SEMANTICS.md +7 -7
- package/Editor/CustomDrawers/WShowIfPropertyDrawer.cs +131 -41
- package/Editor/Utils/ScriptableObjectSingletonCreator.cs +175 -18
- package/README.md +17 -3
- package/Runtime/Tags/Attribute.cs +144 -24
- package/Runtime/Tags/AttributeEffect.cs +119 -16
- package/Runtime/Tags/AttributeModification.cs +59 -29
- package/Runtime/Tags/AttributesComponent.cs +20 -0
- package/Runtime/Tags/EffectBehavior.cs +171 -0
- package/Runtime/Tags/EffectBehavior.cs.meta +4 -0
- package/Runtime/Tags/EffectHandle.cs +5 -0
- package/Runtime/Tags/EffectHandler.cs +385 -39
- package/Runtime/Tags/EffectStackKey.cs +79 -0
- package/Runtime/Tags/EffectStackKey.cs.meta +4 -0
- package/Runtime/Tags/PeriodicEffectDefinition.cs +102 -0
- package/Runtime/Tags/PeriodicEffectDefinition.cs.meta +4 -0
- package/Runtime/Tags/PeriodicEffectRuntimeState.cs +40 -0
- package/Runtime/Tags/PeriodicEffectRuntimeState.cs.meta +4 -0
- package/Samples~/DI - Zenject/README.md +0 -2
- package/Tests/Editor/Attributes/WShowIfPropertyDrawerTests.cs +285 -0
- package/Tests/Editor/Attributes/WShowIfPropertyDrawerTests.cs.meta +11 -0
- package/Tests/Editor/Core/Attributes/RelationalComponentAssignerTests.cs +2 -2
- package/Tests/Editor/Utils/ScriptableObjectSingletonTests.cs +41 -0
- package/Tests/Runtime/Serialization/JsonSerializationTest.cs +4 -3
- package/Tests/Runtime/Tags/AttributeEffectTests.cs +135 -0
- package/Tests/Runtime/Tags/AttributeEffectTests.cs.meta +3 -0
- package/Tests/Runtime/Tags/AttributeModificationTests.cs +137 -0
- package/Tests/Runtime/Tags/AttributeTests.cs +192 -0
- package/Tests/Runtime/Tags/AttributeTests.cs.meta +3 -0
- package/Tests/Runtime/Tags/EffectBehaviorTests.cs +184 -0
- package/Tests/Runtime/Tags/EffectBehaviorTests.cs.meta +3 -0
- package/Tests/Runtime/Tags/EffectHandlerTests.cs +618 -0
- package/Tests/Runtime/Tags/Helpers/RecordingEffectBehavior.cs +89 -0
- package/Tests/Runtime/Tags/Helpers/RecordingEffectBehavior.cs.meta +4 -0
- package/Tests/Runtime/Tags/PeriodicEffectDefinitionSerializationTests.cs +92 -0
- package/Tests/Runtime/Tags/PeriodicEffectDefinitionSerializationTests.cs.meta +3 -0
- package/package.json +1 -1
- package/scripts/lint-doc-links.ps1 +156 -11
- package/Tests/Runtime/Tags/AttributeDataTests.cs +0 -312
- package/node_modules.meta +0 -8
- /package/Tests/Runtime/Tags/{AttributeDataTests.cs.meta → AttributeModificationTests.cs.meta} +0 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
namespace WallstopStudios.UnityHelpers.Tests.Tags.Helpers
|
|
2
|
+
{
|
|
3
|
+
using System.Collections.Generic;
|
|
4
|
+
using WallstopStudios.UnityHelpers.Tags;
|
|
5
|
+
|
|
6
|
+
public sealed class RecordingEffectBehavior : EffectBehavior
|
|
7
|
+
{
|
|
8
|
+
private static readonly HashSet<int> InstanceIds = new();
|
|
9
|
+
|
|
10
|
+
public static List<EffectBehaviorContext> ApplyContexts { get; } = new();
|
|
11
|
+
|
|
12
|
+
public static List<EffectBehaviorContext> TickContexts { get; } = new();
|
|
13
|
+
|
|
14
|
+
public static List<PeriodicInvocation> PeriodicInvocations { get; } = new();
|
|
15
|
+
|
|
16
|
+
public static List<EffectBehaviorContext> RemoveContexts { get; } = new();
|
|
17
|
+
|
|
18
|
+
public static int ApplyCount { get; private set; }
|
|
19
|
+
|
|
20
|
+
public static int TickCount { get; private set; }
|
|
21
|
+
|
|
22
|
+
public static int PeriodicTickCount { get; private set; }
|
|
23
|
+
|
|
24
|
+
public static int RemoveCount { get; private set; }
|
|
25
|
+
|
|
26
|
+
public static int InstanceCount => InstanceIds.Count;
|
|
27
|
+
|
|
28
|
+
public static void Reset()
|
|
29
|
+
{
|
|
30
|
+
ApplyCount = 0;
|
|
31
|
+
TickCount = 0;
|
|
32
|
+
PeriodicTickCount = 0;
|
|
33
|
+
RemoveCount = 0;
|
|
34
|
+
InstanceIds.Clear();
|
|
35
|
+
ApplyContexts.Clear();
|
|
36
|
+
TickContexts.Clear();
|
|
37
|
+
PeriodicInvocations.Clear();
|
|
38
|
+
RemoveContexts.Clear();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private void OnEnable()
|
|
42
|
+
{
|
|
43
|
+
_ = InstanceIds.Add(GetInstanceID());
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public override void OnApply(EffectBehaviorContext context)
|
|
47
|
+
{
|
|
48
|
+
++ApplyCount;
|
|
49
|
+
ApplyContexts.Add(context);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public override void OnTick(EffectBehaviorContext context)
|
|
53
|
+
{
|
|
54
|
+
++TickCount;
|
|
55
|
+
TickContexts.Add(context);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public override void OnPeriodicTick(
|
|
59
|
+
EffectBehaviorContext context,
|
|
60
|
+
PeriodicEffectTickContext tickContext
|
|
61
|
+
)
|
|
62
|
+
{
|
|
63
|
+
++PeriodicTickCount;
|
|
64
|
+
PeriodicInvocations.Add(new PeriodicInvocation(context, tickContext));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public override void OnRemove(EffectBehaviorContext context)
|
|
68
|
+
{
|
|
69
|
+
++RemoveCount;
|
|
70
|
+
RemoveContexts.Add(context);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public readonly struct PeriodicInvocation
|
|
74
|
+
{
|
|
75
|
+
public PeriodicInvocation(
|
|
76
|
+
EffectBehaviorContext context,
|
|
77
|
+
PeriodicEffectTickContext tickContext
|
|
78
|
+
)
|
|
79
|
+
{
|
|
80
|
+
Context = context;
|
|
81
|
+
TickContext = tickContext;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public EffectBehaviorContext Context { get; }
|
|
85
|
+
|
|
86
|
+
public PeriodicEffectTickContext TickContext { get; }
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
namespace WallstopStudios.UnityHelpers.Tests.Tags
|
|
2
|
+
{
|
|
3
|
+
using System.Collections.Generic;
|
|
4
|
+
using NUnit.Framework;
|
|
5
|
+
using WallstopStudios.UnityHelpers.Tags;
|
|
6
|
+
using Serializer = WallstopStudios.UnityHelpers.Core.Serialization.Serializer;
|
|
7
|
+
|
|
8
|
+
[TestFixture]
|
|
9
|
+
public sealed class PeriodicEffectDefinitionSerializationTests
|
|
10
|
+
{
|
|
11
|
+
[Test]
|
|
12
|
+
public void JsonRoundtripPreservesFieldValues()
|
|
13
|
+
{
|
|
14
|
+
PeriodicEffectDefinition definition = CreateDefinition();
|
|
15
|
+
|
|
16
|
+
string json = Serializer.JsonStringify(definition);
|
|
17
|
+
PeriodicEffectDefinition deserialized =
|
|
18
|
+
Serializer.JsonDeserialize<PeriodicEffectDefinition>(json);
|
|
19
|
+
|
|
20
|
+
AssertEquivalent(definition, deserialized);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
[Test]
|
|
24
|
+
public void ProtoRoundtripPreservesFieldValues()
|
|
25
|
+
{
|
|
26
|
+
PeriodicEffectDefinition definition = CreateDefinition();
|
|
27
|
+
|
|
28
|
+
byte[] serialized = Serializer.ProtoSerialize(definition);
|
|
29
|
+
Assert.IsNotNull(serialized);
|
|
30
|
+
Assert.Greater(serialized.Length, 0);
|
|
31
|
+
|
|
32
|
+
PeriodicEffectDefinition deserialized =
|
|
33
|
+
Serializer.ProtoDeserialize<PeriodicEffectDefinition>(serialized);
|
|
34
|
+
|
|
35
|
+
AssertEquivalent(definition, deserialized);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private static PeriodicEffectDefinition CreateDefinition()
|
|
39
|
+
{
|
|
40
|
+
PeriodicEffectDefinition definition = new()
|
|
41
|
+
{
|
|
42
|
+
name = "Damage Pulse",
|
|
43
|
+
initialDelay = 0.35f,
|
|
44
|
+
interval = 0.8f,
|
|
45
|
+
maxTicks = 6,
|
|
46
|
+
modifications = new List<AttributeModification>
|
|
47
|
+
{
|
|
48
|
+
new AttributeModification
|
|
49
|
+
{
|
|
50
|
+
attribute = "health",
|
|
51
|
+
action = ModificationAction.Addition,
|
|
52
|
+
value = -7.5f,
|
|
53
|
+
},
|
|
54
|
+
new AttributeModification
|
|
55
|
+
{
|
|
56
|
+
attribute = "armor",
|
|
57
|
+
action = ModificationAction.Multiplication,
|
|
58
|
+
value = 0.85f,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
return definition;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private static void AssertEquivalent(
|
|
67
|
+
PeriodicEffectDefinition expected,
|
|
68
|
+
PeriodicEffectDefinition actual
|
|
69
|
+
)
|
|
70
|
+
{
|
|
71
|
+
Assert.IsNotNull(actual);
|
|
72
|
+
Assert.AreNotSame(expected, actual);
|
|
73
|
+
Assert.AreEqual(expected.name, actual.name);
|
|
74
|
+
Assert.AreEqual(expected.initialDelay, actual.initialDelay);
|
|
75
|
+
Assert.AreEqual(expected.interval, actual.interval);
|
|
76
|
+
Assert.AreEqual(expected.maxTicks, actual.maxTicks);
|
|
77
|
+
|
|
78
|
+
Assert.IsNotNull(actual.modifications);
|
|
79
|
+
Assert.AreNotSame(expected.modifications, actual.modifications);
|
|
80
|
+
Assert.AreEqual(expected.modifications.Count, actual.modifications.Count);
|
|
81
|
+
|
|
82
|
+
for (int i = 0; i < expected.modifications.Count; ++i)
|
|
83
|
+
{
|
|
84
|
+
AttributeModification expectedModification = expected.modifications[i];
|
|
85
|
+
AttributeModification actualModification = actual.modifications[i];
|
|
86
|
+
Assert.AreEqual(expectedModification.attribute, actualModification.attribute);
|
|
87
|
+
Assert.AreEqual(expectedModification.action, actualModification.action);
|
|
88
|
+
Assert.AreEqual(expectedModification.value, actualModification.value);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
package/package.json
CHANGED
|
@@ -3,6 +3,7 @@ Param(
|
|
|
3
3
|
)
|
|
4
4
|
|
|
5
5
|
$ErrorActionPreference = 'Stop'
|
|
6
|
+
$repoRoot = (Resolve-Path -LiteralPath '.').Path
|
|
6
7
|
|
|
7
8
|
function Write-Violation {
|
|
8
9
|
param(
|
|
@@ -19,11 +20,110 @@ function Write-Violation {
|
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
$schemePattern = [regex]'^[a-zA-Z][a-zA-Z0-9+\.-]*:'
|
|
24
|
+
|
|
25
|
+
function Get-MarkdownLinkTarget {
|
|
26
|
+
param([string]$RawTarget)
|
|
27
|
+
|
|
28
|
+
if ([string]::IsNullOrWhiteSpace($RawTarget)) {
|
|
29
|
+
return $null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
$trimmed = $RawTarget.Trim()
|
|
33
|
+
|
|
34
|
+
if ($trimmed.StartsWith('<') -and $trimmed.Contains('>')) {
|
|
35
|
+
$closingIndex = $trimmed.IndexOf('>')
|
|
36
|
+
if ($closingIndex -gt 1) {
|
|
37
|
+
$trimmed = $trimmed.Substring(1, $closingIndex - 1)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
$spaceIndex = $trimmed.IndexOfAny(@(' ', "`t"))
|
|
42
|
+
if ($spaceIndex -ge 0) {
|
|
43
|
+
$trimmed = $trimmed.Substring(0, $spaceIndex)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if ([string]::IsNullOrWhiteSpace($trimmed)) {
|
|
47
|
+
return $null
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return $trimmed
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function Is-LocalImageTarget {
|
|
54
|
+
param([string]$Target)
|
|
55
|
+
|
|
56
|
+
if ([string]::IsNullOrWhiteSpace($Target)) {
|
|
57
|
+
return $false
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
$trimmed = $Target.Trim()
|
|
61
|
+
if ($schemePattern.IsMatch($trimmed)) {
|
|
62
|
+
return $false
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if ($trimmed.StartsWith('#') -or $trimmed.StartsWith('//')) {
|
|
66
|
+
return $false
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return $true
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function Resolve-ImagePath {
|
|
73
|
+
param(
|
|
74
|
+
[string]$SourceFile,
|
|
75
|
+
[string]$Target,
|
|
76
|
+
[string]$RepoRoot
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
if ([string]::IsNullOrWhiteSpace($Target)) {
|
|
80
|
+
return $null
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
$normalized = $Target.Trim() -replace '\\', '/'
|
|
84
|
+
$cutIndex = $normalized.IndexOfAny(@('#', '?'))
|
|
85
|
+
if ($cutIndex -ge 0) {
|
|
86
|
+
$normalized = $normalized.Substring(0, $cutIndex)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
while ($normalized.StartsWith('./')) {
|
|
90
|
+
$normalized = $normalized.Substring(2)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
$normalized = $normalized.Trim()
|
|
94
|
+
if ([string]::IsNullOrWhiteSpace($normalized)) {
|
|
95
|
+
return $null
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
$separator = [System.IO.Path]::DirectorySeparatorChar
|
|
99
|
+
$normalized = $normalized.Replace('/', $separator).Replace('\', $separator)
|
|
100
|
+
|
|
101
|
+
$sourceDirectory = Split-Path -Path $SourceFile -Parent
|
|
102
|
+
$candidate = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($sourceDirectory, $normalized))
|
|
103
|
+
|
|
104
|
+
if (Test-Path -LiteralPath $candidate) {
|
|
105
|
+
return $candidate
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if ($normalized.Length -gt 0 -and $normalized[0] -ne '.') {
|
|
109
|
+
$rootRelative = $normalized.TrimStart($separator)
|
|
110
|
+
$candidateFromRoot = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($RepoRoot, $rootRelative))
|
|
111
|
+
if (Test-Path -LiteralPath $candidateFromRoot) {
|
|
112
|
+
return $candidateFromRoot
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return $null
|
|
117
|
+
}
|
|
118
|
+
|
|
22
119
|
$mdPattern = [regex]'[A-Za-z0-9._/\-]+\.md(?:#[A-Za-z0-9_\-]+)?'
|
|
23
120
|
$linkPattern = [regex]'\[[^\]]+\]\([^)]+\)'
|
|
24
121
|
$anglePattern = [regex]'<[^>]+>'
|
|
25
122
|
$filenameTextLinkPattern = [regex]'\[(?<text>[^\]]+?\.md(?:#[^\]]+)?)\]\((?<target>[^)]+?\.md(?:#[^)]+)?)\)'
|
|
26
123
|
$inlineCodeMdPattern = [regex]'`[^`\n]*?\.md[^`\n]*?`'
|
|
124
|
+
$imagePattern = [regex]'!\[[^\]]*\]\((?<target>[^)]+)\)'
|
|
125
|
+
$imageReferencePattern = [regex]'!\[[^\]]*\]\[(?<label>[^\]]+)\]'
|
|
126
|
+
$definitionPattern = [regex]'^\s*\[(?<label>[^\]]+)\]:\s*(?<rest>.+)$'
|
|
27
127
|
|
|
28
128
|
$violationCount = 0
|
|
29
129
|
|
|
@@ -31,44 +131,88 @@ Get-ChildItem -Path . -Recurse -Include *.md -File |
|
|
|
31
131
|
Where-Object { $_.FullName -notmatch '(?i)[\\/](node_modules)[\\/]' } |
|
|
32
132
|
ForEach-Object {
|
|
33
133
|
$file = $_.FullName
|
|
134
|
+
$lines = Get-Content -LiteralPath $file
|
|
135
|
+
$lineCount = $lines.Length
|
|
136
|
+
$linkDefinitions = New-Object 'System.Collections.Generic.Dictionary[string,string]' ([System.StringComparer]::OrdinalIgnoreCase)
|
|
137
|
+
$inFence = $false
|
|
138
|
+
|
|
139
|
+
for ($index = 0; $index -lt $lineCount; $index++) {
|
|
140
|
+
$line = $lines[$index]
|
|
141
|
+
if ($line -match '^\s*```' -or $line -match '^\s*~~~') {
|
|
142
|
+
$inFence = -not $inFence
|
|
143
|
+
continue
|
|
144
|
+
}
|
|
145
|
+
if ($inFence) { continue }
|
|
146
|
+
|
|
147
|
+
$definitionMatch = $definitionPattern.Match($line)
|
|
148
|
+
if ($definitionMatch.Success) {
|
|
149
|
+
$label = $definitionMatch.Groups['label'].Value.Trim()
|
|
150
|
+
$rest = $definitionMatch.Groups['rest'].Value
|
|
151
|
+
$target = Get-MarkdownLinkTarget $rest
|
|
152
|
+
if ($label -and $target) {
|
|
153
|
+
$linkDefinitions[$label] = $target
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
34
158
|
$inFence = $false
|
|
35
|
-
$
|
|
36
|
-
|
|
37
|
-
$
|
|
38
|
-
$lineNo++
|
|
159
|
+
for ($index = 0; $index -lt $lineCount; $index++) {
|
|
160
|
+
$line = $lines[$index]
|
|
161
|
+
$lineNo = $index + 1
|
|
39
162
|
|
|
40
|
-
# Track fenced code blocks (``` or ~~~)
|
|
41
163
|
if ($line -match '^\s*```' -or $line -match '^\s*~~~') {
|
|
42
164
|
$inFence = -not $inFence
|
|
165
|
+
continue
|
|
43
166
|
}
|
|
44
|
-
if ($inFence) {
|
|
167
|
+
if ($inFence) { continue }
|
|
45
168
|
|
|
46
|
-
# 1) Flag inline code mentions of .md
|
|
47
169
|
if ($inlineCodeMdPattern.IsMatch($line)) {
|
|
48
170
|
$violationCount++
|
|
49
171
|
Write-Violation -File $file -LineNumber $lineNo -Message "Inline code mentions .md; use a human-readable link instead" -Line $line
|
|
50
172
|
}
|
|
51
173
|
|
|
52
|
-
# Strip markdown links and angle-bracket autolinks before scanning for bare mentions
|
|
53
174
|
$stripped = $linkPattern.Replace($line, '')
|
|
54
175
|
$stripped = $anglePattern.Replace($stripped, '')
|
|
55
176
|
|
|
56
|
-
# 2) Bare .md mention outside links
|
|
57
177
|
if ($mdPattern.IsMatch($stripped)) {
|
|
58
178
|
$violationCount++
|
|
59
179
|
Write-Violation -File $file -LineNumber $lineNo -Message "Bare .md mention; convert to [Readable Text](file.md)" -Line $line
|
|
60
180
|
}
|
|
61
181
|
|
|
62
|
-
# 3) Links whose visible text is still a filename
|
|
63
182
|
foreach ($m in $filenameTextLinkPattern.Matches($line)) {
|
|
64
183
|
$text = $m.Groups['text'].Value
|
|
65
184
|
$target = $m.Groups['target'].Value
|
|
66
|
-
# Ignore if the text already contains spaces (unlikely for filename.md); otherwise flag
|
|
67
185
|
if ($text -match '\.md') {
|
|
68
186
|
$violationCount++
|
|
69
187
|
Write-Violation -File $file -LineNumber $lineNo -Message "Link text is a filename; use human-readable text for $target" -Line $line
|
|
70
188
|
}
|
|
71
189
|
}
|
|
190
|
+
|
|
191
|
+
foreach ($match in $imagePattern.Matches($line)) {
|
|
192
|
+
$rawTarget = $match.Groups['target'].Value
|
|
193
|
+
$resolvedTarget = Get-MarkdownLinkTarget $rawTarget
|
|
194
|
+
if ($resolvedTarget -and (Is-LocalImageTarget $resolvedTarget)) {
|
|
195
|
+
$imagePath = Resolve-ImagePath -SourceFile $file -Target $resolvedTarget -RepoRoot $repoRoot
|
|
196
|
+
if (-not $imagePath) {
|
|
197
|
+
$violationCount++
|
|
198
|
+
Write-Violation -File $file -LineNumber $lineNo -Message "Image target '$resolvedTarget' does not resolve to a file" -Line $line
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
foreach ($match in $imageReferencePattern.Matches($line)) {
|
|
204
|
+
$label = $match.Groups['label'].Value.Trim()
|
|
205
|
+
if ($linkDefinitions.ContainsKey($label)) {
|
|
206
|
+
$resolvedTarget = $linkDefinitions[$label]
|
|
207
|
+
if ($resolvedTarget -and (Is-LocalImageTarget $resolvedTarget)) {
|
|
208
|
+
$imagePath = Resolve-ImagePath -SourceFile $file -Target $resolvedTarget -RepoRoot $repoRoot
|
|
209
|
+
if (-not $imagePath) {
|
|
210
|
+
$violationCount++
|
|
211
|
+
Write-Violation -File $file -LineNumber $lineNo -Message "Image reference '$label' points to '$resolvedTarget' which does not resolve" -Line $line
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
72
216
|
}
|
|
73
217
|
}
|
|
74
218
|
|
|
@@ -78,3 +222,4 @@ if ($violationCount -gt 0) {
|
|
|
78
222
|
} else {
|
|
79
223
|
Write-Host "Markdown link lint passed: no issues found." -ForegroundColor Green
|
|
80
224
|
}
|
|
225
|
+
|