• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rjrodger / aontu / 9178837021

21 May 2024 05:28PM UTC coverage: 82.627%. Remained the same
9178837021

push

github

rjrodger
v0.21.1

429 of 550 branches covered (78.0%)

Branch coverage included in aggregate %.

741 of 866 relevant lines covered (85.57%)

1873.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.69
/lib/val/RefVal.ts
1
/* Copyright (c) 2021-2023 Richard Rodger, MIT License */
5,094✔
2

3

4
/* TODO
5
   Rename ot PathVal
6
   
7
   $SELF.a - path starting at self
8
   $PARENT.b === .b - sibling
9

10
   implement $ as a prefix operator
11
   this allows "$AString" to be used for literal part names
12
*/
13

14

15

16
import type {
17
  Val,
18
  ValSpec,
19
} from '../type'
20

21
import {
22
  DONE,
23
} from '../type'
54✔
24

25
import {
26
  descErr
27
} from '../err'
54✔
28

29
import {
30
  Context,
31
} from '../unify'
32

33
import {
34
  unite
35
} from '../op/op'
54✔
36

37
import {
38
  TOP,
39
  StringVal,
40
} from '../val'
54✔
41

42

43
import { ConjunctVal } from '../val/ConjunctVal'
54✔
44
// import { DisjunctVal } from '../val/DisjunctVal'
45
// import { ListVal } from '../val/ListVal'
46
import { MapVal } from '../val/MapVal'
54✔
47
import { Nil } from '../val/Nil'
54✔
48
import { VarVal } from '../val/VarVal'
54✔
49
import { ValBase } from '../val/ValBase'
54✔
50

51

52

53

54

55
class RefVal extends ValBase {
56
  isRefVal = true
2,196✔
57

58
  absolute: boolean = false
2,196✔
59
  prefix: boolean = false
2,196✔
60

61
  constructor(
62
    spec: {
63
      peg: any[],
64
      absolute?: boolean,
65
      prefix?: boolean
66
    },
67
    ctx?: Context
68
  ) {
69
    super(spec, ctx)
2,196✔
70
    this.peg = []
2,196✔
71

72
    this.absolute = true === this.absolute ? true : // absolute sticks
2,196!
73
      true === spec.absolute ? true : false
2,196✔
74

75
    this.prefix = true === spec.prefix
2,196✔
76

77
    for (let pI = 0; pI < spec.peg.length; pI++) {
2,196✔
78
      this.append(spec.peg[pI])
2,790✔
79
    }
80
  }
81

82

83
  append(part: any) {
84
    // console.log('APPEND', part, this)
85
    let partval
86

87
    if ('string' === typeof part) {
2,814✔
88
      partval = part
522✔
89
      this.peg.push(partval)
522✔
90
    }
2,292✔
91

92
    else if (part instanceof StringVal) {
93
      partval = part.peg
1,152✔
94
      this.peg.push(partval)
1,152✔
95
    }
1,140✔
96

97
    else if (part instanceof VarVal) {
98
      partval = part
144✔
99
      this.peg.push(partval)
144✔
100
    }
996✔
101

102
    else if (part instanceof RefVal) {
103
      if (part.absolute) {
996✔
104
        this.absolute = true
132✔
105
      }
106

107
      if (this.prefix) {
996✔
108
        if (part.prefix) {
534✔
109
          this.peg.push('.')
450✔
110
        }
111
      }
112
      else {
113
        if (part.prefix) {
462✔
114
          if (0 === this.peg.length) {
402✔
115
            this.prefix = true
366✔
116
          }
36✔
117

118
          else if (0 < this.peg.length) {
119
            this.peg.push('.')
36✔
120
          }
121
        }
122
      }
123

124
      this.peg.push(...part.peg)
996✔
125
    }
126
  }
127

128

129
  unify(peer: Val, ctx: Context): Val {
130
    let out: Val = this
1,500✔
131
    // let why = 'id'
132

133
    if (this.id !== peer.id) {
1,500✔
134

135
      // TODO: not resolved when all Vals in path are done is an error
136
      // as path cannot be found
137
      // let resolved: Val | undefined = null == ctx ? this : ctx.find(this)
138
      let resolved: Val | undefined = null == ctx ? this : this.find(ctx)
1,500!
139

140
      // console.log('UR', this.peg, resolved)
141

142
      resolved = resolved || this
1,500✔
143

144
      if (null == resolved && this.canon === peer.canon) {
1,500!
145
        out = this
×
146
      }
1,500✔
147
      else if (resolved instanceof RefVal) {
148
        if (TOP === peer) {
906✔
149
          out = this
840✔
150
          // why = 'pt'
151
        }
66!
152
        else if (peer instanceof Nil) {
153
          out = Nil.make(ctx, 'ref[' + this.peg + ']', this, peer)
×
154
          // why = 'pn'
155
        }
66✔
156

157
        // same path
158
        // else if (this.peg === peer.peg) {
159
        else if (this.canon === peer.canon) {
160
          out = this
48✔
161
          // why = 'pp'
162
        }
163

164
        else {
165
          // Ensure RefVal done is incremented
166
          this.done = DONE === this.done ? DONE : this.done + 1
18!
167
          out = new ConjunctVal({ peg: [this, peer] }, ctx)
18✔
168
          // why = 'cj'
169
        }
170
      }
171
      else {
172
        out = unite(ctx, resolved, peer, 'ref')
594✔
173
        // why = 'u'
174
      }
175

176
      out.done = DONE === out.done ? DONE : this.done + 1
1,500✔
177
    }
178

179
    // console.log('RV', why, this.id, this.canon, '&', peer.canon, '->', out.canon)
180

181
    return out
1,500✔
182
  }
183

184

185
  find(ctx: Context) {
186
    // TODO: relative paths
187
    // if (this.root instanceof MapVal && ref.absolute) {
188

189
    // NOTE: path *to* the ref, not the ref itself!
190
    let fullpath = this.path
1,500✔
191

192
    let parts: string[] = []
1,500✔
193

194
    let modes: string[] = []
1,500✔
195

196
    // console.log('PARTS', this.peg)
197

198
    for (let pI = 0; pI < this.peg.length; pI++) {
1,500✔
199
      let part = this.peg[pI]
2,082✔
200
      if (part instanceof VarVal) {
2,082✔
201
        let strval = (part as VarVal).peg
240✔
202
        let name = strval ? '' + strval.peg : ''
240!
203

204
        if ('KEY' === name) {
240✔
205
          if (pI === this.peg.length - 1) {
240!
206
            modes.push(name)
240✔
207
          }
208
          else {
209
            // TODO: return a Nil explaining error
210
            return
×
211
          }
212
        }
213

214
        if ('SELF' === name) {
240!
215
          if (pI === 0) {
×
216
            modes.push(name)
×
217
          }
218
          else {
219
            // TODO: return a Nil explaining error
220
            return
×
221
          }
222
        }
240!
223
        else if ('PARENT' === name) {
224
          if (pI === 0) {
×
225
            modes.push(name)
×
226
          }
227
          else {
228
            // TODO: return a Nil explaining error
229
            return
×
230
          }
231
        }
240!
232
        else if (0 === modes.length) {
233
          part = (part as VarVal).unify(TOP, ctx)
×
234
          if (part instanceof Nil) {
×
235
            // TODO: var not found, so can't find path
236
            return
×
237
          }
238
          else {
239
            part = '' + part.peg
×
240
          }
241
        }
242
      }
243
      else {
244
        parts.push(part)
1,842✔
245
      }
246
    }
247

248
    // console.log('modes', modes)
249

250

251
    if (this.absolute) {
1,500✔
252
      fullpath = parts
822✔
253
    }
254
    else {
255
      fullpath = fullpath.slice(
678✔
256
        0,
257
        (
258
          modes.includes('SELF') ? 0 :
678!
259
            modes.includes('PARENT') ? -1 :
678!
260
              -1 // siblings
261
        )
262
      ).concat(parts)
263
    }
264

265
    let sep = '.'
1,500✔
266
    fullpath = fullpath
1,500✔
267
      .reduce(((a: string[], p: string) =>
268
        (p === sep ? a.length = a.length - 1 : a.push(p), a)), [])
2,400✔
269

270
    let node = ctx.root
1,500✔
271
    let pI = 0
1,500✔
272
    for (; pI < fullpath.length; pI++) {
1,500✔
273
      // console.log('RefVal DESCEND', pI, node)
274
      let part = fullpath[pI]
2,148✔
275

276
      if (node instanceof MapVal) {
2,148✔
277
        node = node.peg[part]
1,530✔
278
      }
279
      else {
280
        break;
618✔
281
      }
282
    }
283

284
    // console.log('RefVal KEY', modes, pI, fullpath)
285

286
    if (pI === fullpath.length) {
1,500✔
287
      // if (this.attr && 'KEY' === this.attr.kind) {
288
      if (modes.includes('KEY')) {
882✔
289
        // let key = fullpath[fullpath.length - ('' === this.attr.part ? 1 : 2)]
290
        let key = fullpath[fullpath.length - 1]
96✔
291
        let sv = new StringVal({ peg: null == key ? '' : key }, ctx)
96!
292

293
        // TODO: other props?
294
        sv.done = DONE
96✔
295
        sv.path = this.path
96✔
296

297
        return sv
96✔
298
      }
299
      else {
300
        return node
786✔
301
      }
302
    }
303
  }
304

305

306
  same(peer: Val): boolean {
307
    return null == peer ? false : this.peg === peer.peg
×
308
  }
309

310

311
  clone(spec?: ValSpec, ctx?: Context): Val {
312
    let out = (super.clone({
300✔
313
      peg: this.peg,
314
      absolute: this.absolute,
315
      ...(spec || {})
600✔
316
    }, ctx) as RefVal)
317
    return out
300✔
318
  }
319

320

321
  get canon() {
322
    let str =
660✔
323
      (this.absolute ? '$' : '') +
660✔
324
      (0 < this.peg.length ? '.' : '') +
660✔
325
      // this.peg.join(this.sep)
326
      this.peg.map((p: any) => '.' === p ? '' :
1,608✔
327
        (p.isVal ? p.canon : '' + p))
1,140✔
328
        .join('.')
329
    return str
660✔
330
  }
331

332

333
  gen(ctx?: Context) {
334
    // Unresolved ref cannot be generated, so always an error.
335
    let nil = Nil.make(
24✔
336
      ctx,
337
      'ref',
338
      this, // (formatPath(this.peg, this.absolute) as any),
339
      undefined
340
    )
341

342
    // TODO: refactor to use Site
343
    nil.path = this.path
24✔
344
    nil.url = this.url
24✔
345
    nil.row = this.row
24✔
346
    nil.col = this.col
24✔
347

348
    descErr(nil)
24✔
349

350
    if (ctx) {
24✔
351
      ctx.err.push(nil)
12✔
352
    }
353
    else {
354
      throw new Error(nil.msg)
12✔
355
    }
356

357
    return undefined
12✔
358
  }
359
}
360

361

362
export {
363
  RefVal,
364
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc