8
8
isAlias ,
9
9
isCollection ,
10
10
isPair ,
11
+ isScalar ,
11
12
Node ,
12
13
NodeBase ,
13
14
Range
@@ -24,6 +25,8 @@ export declare namespace Alias {
24
25
}
25
26
}
26
27
28
+ const RESOLVE = Symbol ( '_resolve' )
29
+
27
30
export class Alias extends NodeBase {
28
31
source : string
29
32
@@ -39,46 +42,72 @@ export class Alias extends NodeBase {
39
42
} )
40
43
}
41
44
42
- /**
43
- * Resolve the value of this alias within `doc`, finding the last
44
- * instance of the `source` anchor before this node.
45
- */
46
- resolve ( doc : Document ) : Scalar | YAMLMap | YAMLSeq | undefined {
45
+ [ RESOLVE ] ( doc : Document ) {
47
46
let found : Scalar | YAMLMap | YAMLSeq | undefined = undefined
47
+ // @ts -expect-error - TS doesn't notice the assignment in the visitor
48
+ let root : Node & { anchor : string } = undefined
49
+ const pathLike = this . source . includes ( '/' )
48
50
visit ( doc , {
49
51
Node : ( _key : unknown , node : Node ) => {
50
52
if ( node === this ) return visit . BREAK
51
- if ( node . anchor === this . source ) found = node
53
+ const { anchor } = node
54
+ if ( anchor === this . source ) {
55
+ found = node
56
+ } else if (
57
+ doc . directives ?. yaml . version === 'next' &&
58
+ anchor &&
59
+ pathLike &&
60
+ this . source . startsWith ( anchor + '/' ) &&
61
+ ( ! root || root . anchor . length <= anchor . length )
62
+ ) {
63
+ root = node as Node & { anchor : string }
64
+ }
52
65
}
53
66
} )
54
- return found
67
+ if ( found ) return { node : found , root : found }
68
+
69
+ if ( isCollection ( root ) ) {
70
+ const parts = this . source . substring ( root . anchor . length + 1 ) . split ( '/' )
71
+ const node = root . getIn ( parts , true )
72
+ if ( isCollection ( node ) || isScalar ( node ) ) return { node, root }
73
+ }
74
+
75
+ return { node : undefined , root }
76
+ }
77
+
78
+ /**
79
+ * Resolve the value of this alias within `doc`, finding the last
80
+ * instance of the `source` anchor before this node.
81
+ */
82
+ resolve ( doc : Document ) : Scalar | YAMLMap | YAMLSeq | undefined {
83
+ return this [ RESOLVE ] ( doc ) . node
55
84
}
56
85
57
86
toJSON ( _arg ?: unknown , ctx ?: ToJSContext ) {
58
87
if ( ! ctx ) return { source : this . source }
59
- const { anchors, doc, maxAliasCount } = ctx
60
- const source = this . resolve ( doc )
61
- if ( ! source ) {
88
+ const { anchors, doc, maxAliasCount, resolved } = ctx
89
+ const { node , root } = this [ RESOLVE ] ( doc )
90
+ if ( ! node ) {
62
91
const msg = `Unresolved alias (the anchor must be set before the alias): ${ this . source } `
63
92
throw new ReferenceError ( msg )
64
93
}
65
- const data = anchors . get ( source )
66
- /* istanbul ignore if */
67
- if ( ! data || data . res === undefined ) {
68
- const msg = 'This should not happen: Alias anchor was not resolved?'
69
- throw new ReferenceError ( msg )
70
- }
94
+
71
95
if ( maxAliasCount >= 0 ) {
96
+ const data = anchors . get ( root )
97
+ if ( ! data ) {
98
+ const msg = 'This should not happen: Alias anchor was not resolved?'
99
+ throw new ReferenceError ( msg )
100
+ }
72
101
data . count += 1
73
- if ( data . aliasCount === 0 )
74
- data . aliasCount = getAliasCount ( doc , source , anchors )
102
+ data . aliasCount ||= getAliasCount ( doc , root , anchors )
75
103
if ( data . count * data . aliasCount > maxAliasCount ) {
76
104
const msg =
77
105
'Excessive alias count indicates a resource exhaustion attack'
78
106
throw new ReferenceError ( msg )
79
107
}
80
108
}
81
- return data . res
109
+
110
+ return resolved . get ( node )
82
111
}
83
112
84
113
toString (
@@ -105,8 +134,8 @@ function getAliasCount(
105
134
anchors : ToJSContext [ 'anchors' ]
106
135
) : number {
107
136
if ( isAlias ( node ) ) {
108
- const source = node . resolve ( doc )
109
- const anchor = anchors && source && anchors . get ( source )
137
+ const { root } = node [ RESOLVE ] ( doc )
138
+ const anchor = root && anchors ? .get ( root )
110
139
return anchor ? anchor . count * anchor . aliasCount : 0
111
140
} else if ( isCollection ( node ) ) {
112
141
let count = 0
0 commit comments