forked from mediaxml/mediaxml
-
Notifications
You must be signed in to change notification settings - Fork 0
/
loader.js
97 lines (77 loc) · 2.2 KB
/
loader.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
const { ValidationError } = require('./validate')
const { Parser } = require('./parser')
const { fetch } = require('./fetch')
const { hash } = require('./hash')
const debug = require('debug')('mediaxml')
function createLoader(context, opts) {
opts = { ...opts }
const { cache = opts.cache || new Map() } = context
return async function load(uri) {
if (!uri) {
throw new Error('Missing URI for load function.')
}
let stream = null
const { imports } = context
const cacheKey = hash(uri)
const buffers = []
if (cache.has(cacheKey)) {
return cache.get(cacheKey)
}
const promise = new Promise(resolver)
cache.set(cacheKey, promise)
return promise
async function resolver(resolve, reject) {
try {
stream = await fetch(uri)
} catch (err) {
debug(err)
imports.pending.delete(uri)
return resolve(null)
}
if ('function' === typeof opts.onbeforeload) {
opts.onbeforeload({ uri, imports })
}
stream.once('error', onerror)
stream.on('data', ondata)
stream.on('end', onend)
function onerror(err) {
if ('function' === typeof opts.onerror) {
opts.onerror(err, { uri, imports })
}
reject(err)
}
function ondata(buffer) {
if ('function' === typeof opts.ondata) {
opts.ondata(buffer, { uri, imports })
}
buffers.push(buffer)
}
async function onend() {
const buffer = Buffer.concat(buffers)
const string = String(buffer)
let result = string
// attempt to load a parsed XML source from buffer string
try {
const tmp = Parser.from(string)
// valid XML was just parsed
if (tmp.rootNode) {
context.rootNode = tmp.rootNode
result = tmp.rootNode
}
} catch (err) {
debug(err.stack || err)
if (!(err instanceof ValidationError)) {
return reject(err)
}
}
if ('function' === typeof opts.onload) {
opts.onload(result, { uri, imports })
}
resolve(result)
}
}
}
}
module.exports = {
createLoader
}