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

ecamp / hal-json-vuex / 4044415582

pending completion
4044415582

Pull #280

github

GitHub
Merge 4f06dbcf7 into 0e348e243
Pull Request #280: Fix baseUrl usage of axios

139 of 164 branches covered (84.76%)

Branch coverage included in aggregate %.

18 of 18 new or added lines in 2 files covered. (100.0%)

300 of 319 relevant lines covered (94.04%)

422.03 hits per line

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

80.0
/src/LoadingResource.ts
1
import LoadingCollection from './LoadingCollection'
3✔
2
import ResourceInterface from './interfaces/ResourceInterface'
3
import CollectionInterface from './interfaces/CollectionInterface'
4
import { InternalConfig } from './interfaces/Config'
5

6
/**
7
 * Creates a placeholder for an entity which has not yet finished loading from the API.
8
 * Such a LoadingResource can safely be used in Vue components, since it will render as an empty
9
 * string and Vue's reactivity system will replace it with the real data once that is available.
10
 *
11
 * Accessing nested functions in a LoadingResource yields another LoadingResource:
12
 * new LoadingResource(...).author().organization() // gives another LoadingResource
13
 *
14
 * Using a LoadingResource or a property of a LoadingResource in a view renders to empty strings:
15
 * let user = new LoadingResource(...)
16
 * 'The "' + user + '" is called "' + user.name + '"' // gives 'The "" is called ""'
17
 */
18
class LoadingResource implements ResourceInterface {
19
  public _meta: {
20
    self: string | null,
21
    selfUrl: string | null,
22
    load: Promise<ResourceInterface>
23
    loading: boolean
24
  }
25

26
  private loadResource: Promise<ResourceInterface>
27

28
  /**
29
   * @param entityLoaded a Promise that resolves to a Resource when the entity has finished
30
   *                     loading from the API
31
   * @param self optional URI of the entity being loaded, if available. If passed, the
32
   *                     returned LoadingResource will return it in calls to .self and ._meta.self
33
   */
34
  constructor (loadResource: Promise<ResourceInterface>, self: string | null = null, config: InternalConfig | null = null) {
60✔
35
    this._meta = {
272✔
36
      self: self,
37
      selfUrl: self ? config?.apiRoot + self : null,
779!
38
      load: loadResource,
39
      loading: true
40
    }
41

42
    this.loadResource = loadResource
272✔
43

44
    const handler = {
272✔
45
      get: function (target: LoadingResource, prop: string | number | symbol) {
46
        // This is necessary so that Vue's reactivity system understands to treat this LoadingResource
47
        // like a normal object.
48
        if (prop === Symbol.toPrimitive) {
228!
49
          return () => ''
×
50
        }
51

52
        // This is necessary so that Vue's reactivity system understands to treat this LoadingResource
53
        // like a normal object.
54
        if (['then', Symbol.toStringTag, 'state', 'getters', '$options', '_isVue', '__file', 'render', 'constructor'].includes(prop as string)) {
228!
55
          return undefined
×
56
        }
57

58
        // proxy to properties that actually exist on LoadingResource (_meta, $reload, etc.)
59
        if (Reflect.has(target, prop)) {
228✔
60
          return Reflect.get(target, prop)
176✔
61
        }
62

63
        // Proxy to all other unknown properties: return a function that yields another LoadingResource
64
        const loadProperty = loadResource.then(resource => resource[prop])
52✔
65

66
        const result = templateParams => new LoadingResource(loadProperty.then(property => {
52✔
67
          try {
30✔
68
            return property(templateParams)._meta.load
30✔
69
          } catch (e) {
70
            throw new Error(`Property '${prop.toString()}' on resource '${self}' was used like a relation, but no relation with this name was returned by the API (actual return value: ${JSON.stringify(property)})`)
4✔
71
          }
72
        }
73
        ))
74

75
        result.toString = () => ''
52✔
76
        return result
52✔
77
      }
78
    }
79
    return new Proxy(this, handler)
272✔
80
  }
81

82
  get items (): Array<ResourceInterface> {
83
    return LoadingCollection.create(this.loadResource.then(resource => (resource as CollectionInterface).items))
7✔
84
  }
85

86
  get allItems (): Array<ResourceInterface> {
87
    return LoadingCollection.create(this.loadResource.then(resource => (resource as CollectionInterface).allItems))
×
88
  }
89

90
  public $reload (): Promise<ResourceInterface> {
91
    // Skip reloading entities that are already loading
92
    return this._meta.load
1✔
93
  }
94

95
  public $loadItems (): Promise<CollectionInterface> {
96
    return this._meta.load.then(resource => (resource as CollectionInterface).$loadItems())
2✔
97
  }
98

99
  public $post (data: unknown): Promise<ResourceInterface | null> {
100
    return this._meta.load.then(resource => resource.$post(data))
1✔
101
  }
102

103
  public $patch (data: unknown): Promise<ResourceInterface> {
104
    return this._meta.load.then(resource => resource.$patch(data))
1✔
105
  }
106

107
  public $del (): Promise<string | void> {
108
    return this._meta.load.then(resource => resource.$del())
1✔
109
  }
110

111
  public $href (relation: string, templateParams = {}): Promise<string | undefined> {
×
112
    return this._meta.load.then(resource => resource.$href(relation, templateParams))
×
113
  }
114

115
  public toJSON (): string {
116
    return '{}'
6✔
117
  }
118
}
119

120
export default LoadingResource
3✔
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

© 2026 Coveralls, Inc