UNPKG

2.74 kBJavaScriptView Raw
1'use strict'
2
3const { dirname, join } = require('path')
4const { createWriteStream } = require('fs')
5const { mkdir, unlink } = require('fs').promises
6const { capture } = require('reserve')
7const { getOutput } = require('./output')
8
9module.exports = job => {
10 if (job.disableUi5) {
11 return []
12 }
13
14 const [, hostName] = /https?:\/\/([^/]*)/.exec(job.ui5)
15 const [, version] = /(\d+\.\d+\.\d+)?$/.exec(job.ui5)
16 const cacheBase = join(job.cache || '', hostName.replace(':', '_'), version || '')
17 const match = /\/((?:test-)?resources\/.*)/
18 const ifCacheEnabled = (request, url, match) => job.cache ? match : false
19 const uncachable = {}
20 const cachingInProgress = {}
21
22 const mappings = [{
23 /* Prevent caching issues :
24 * - Caching was not possible (99% URL does not exist)
25 * - Caching is in progress (must wait for the end of the writing stream)
26 */
27 match,
28 'if-match': ifCacheEnabled,
29 custom: async (request, response, path) => {
30 if (uncachable[path]) {
31 response.writeHead(404)
32 response.end()
33 return
34 }
35 const cachingPromise = cachingInProgress[path]
36 /* istanbul ignore next */ // Hard to reproduce
37 if (cachingPromise) {
38 await cachingPromise
39 }
40 }
41 }, {
42 // UI5 from cache
43 match,
44 'if-match': ifCacheEnabled,
45 file: join(cacheBase, '$1'),
46 'ignore-if-not-found': true
47 }, {
48 // UI5 caching
49 method: 'GET',
50 match,
51 'if-match': ifCacheEnabled,
52 custom: async (request, response, path) => {
53 const filePath = /([^?#]+)/.exec(unescape(path))[1] // filter URL parameters & hash (assuming resources are static)
54 const cachePath = join(cacheBase, filePath)
55 const cacheFolder = dirname(cachePath)
56 await mkdir(cacheFolder, { recursive: true })
57 if (cachingInProgress[path]) {
58 return request.url // loop back to use cached result
59 }
60 const file = createWriteStream(cachePath)
61 cachingInProgress[path] = capture(response, file)
62 .catch(reason => {
63 file.end()
64 uncachable[path] = true
65 if (response.statusCode !== 404) {
66 getOutput(job).failedToCacheUI5resource(path, response.statusCode)
67 }
68 return unlink(cachePath)
69 })
70 .then(() => {
71 delete cachingInProgress[path]
72 })
73 }
74 }, {
75 // UI5 from url
76 method: ['GET', 'HEAD'],
77 match,
78 url: `${job.ui5}/$1`,
79 'ignore-unverifiable-certificate': true
80 }]
81
82 job.libs.forEach(({ relative, source }) => {
83 mappings.unshift({
84 match: new RegExp(`\\/resources\\/${relative.replace(/\//g, '\\/')}(.*)`),
85 file: join(source, '$1'),
86 'ignore-if-not-found': true
87 })
88 })
89
90 return mappings
91}