1'use strict'
2
3const { kConstruct } = require('./symbols')
4const { Cache } = require('./cache')
5const { webidl } = require('../fetch/webidl')
6const { kEnumerableProperty } = require('../core/util')
7
8class CacheStorage {
9  /**
10   * @see https://w3c.github.io/ServiceWorker/#dfn-relevant-name-to-cache-map
11   * @type {Map<string, import('./cache').requestResponseList}
12   */
13  #caches = new Map()
14
15  constructor () {
16    if (arguments[0] !== kConstruct) {
17      webidl.illegalConstructor()
18    }
19  }
20
21  async match (request, options = {}) {
22    webidl.brandCheck(this, CacheStorage)
23    webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.match' })
24
25    request = webidl.converters.RequestInfo(request)
26    options = webidl.converters.MultiCacheQueryOptions(options)
27
28    // 1.
29    if (options.cacheName != null) {
30      // 1.1.1.1
31      if (this.#caches.has(options.cacheName)) {
32        // 1.1.1.1.1
33        const cacheList = this.#caches.get(options.cacheName)
34        const cache = new Cache(kConstruct, cacheList)
35
36        return await cache.match(request, options)
37      }
38    } else { // 2.
39      // 2.2
40      for (const cacheList of this.#caches.values()) {
41        const cache = new Cache(kConstruct, cacheList)
42
43        // 2.2.1.2
44        const response = await cache.match(request, options)
45
46        if (response !== undefined) {
47          return response
48        }
49      }
50    }
51  }
52
53  /**
54   * @see https://w3c.github.io/ServiceWorker/#cache-storage-has
55   * @param {string} cacheName
56   * @returns {Promise<boolean>}
57   */
58  async has (cacheName) {
59    webidl.brandCheck(this, CacheStorage)
60    webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.has' })
61
62    cacheName = webidl.converters.DOMString(cacheName)
63
64    // 2.1.1
65    // 2.2
66    return this.#caches.has(cacheName)
67  }
68
69  /**
70   * @see https://w3c.github.io/ServiceWorker/#dom-cachestorage-open
71   * @param {string} cacheName
72   * @returns {Promise<Cache>}
73   */
74  async open (cacheName) {
75    webidl.brandCheck(this, CacheStorage)
76    webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.open' })
77
78    cacheName = webidl.converters.DOMString(cacheName)
79
80    // 2.1
81    if (this.#caches.has(cacheName)) {
82      // await caches.open('v1') !== await caches.open('v1')
83
84      // 2.1.1
85      const cache = this.#caches.get(cacheName)
86
87      // 2.1.1.1
88      return new Cache(kConstruct, cache)
89    }
90
91    // 2.2
92    const cache = []
93
94    // 2.3
95    this.#caches.set(cacheName, cache)
96
97    // 2.4
98    return new Cache(kConstruct, cache)
99  }
100
101  /**
102   * @see https://w3c.github.io/ServiceWorker/#cache-storage-delete
103   * @param {string} cacheName
104   * @returns {Promise<boolean>}
105   */
106  async delete (cacheName) {
107    webidl.brandCheck(this, CacheStorage)
108    webidl.argumentLengthCheck(arguments, 1, { header: 'CacheStorage.delete' })
109
110    cacheName = webidl.converters.DOMString(cacheName)
111
112    return this.#caches.delete(cacheName)
113  }
114
115  /**
116   * @see https://w3c.github.io/ServiceWorker/#cache-storage-keys
117   * @returns {string[]}
118   */
119  async keys () {
120    webidl.brandCheck(this, CacheStorage)
121
122    // 2.1
123    const keys = this.#caches.keys()
124
125    // 2.2
126    return [...keys]
127  }
128}
129
130Object.defineProperties(CacheStorage.prototype, {
131  [Symbol.toStringTag]: {
132    value: 'CacheStorage',
133    configurable: true
134  },
135  match: kEnumerableProperty,
136  has: kEnumerableProperty,
137  open: kEnumerableProperty,
138  delete: kEnumerableProperty,
139  keys: kEnumerableProperty
140})
141
142module.exports = {
143  CacheStorage
144}
145