1 | const { Transform } = require('stream');
|
2 | const { checkRule } = require('./lib');
|
3 | let cleanStack = require('@artdeco/clean-stack'); if (cleanStack && cleanStack.__esModule) cleanStack = cleanStack.default;
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | class Replaceable extends Transform {
|
10 | |
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 | constructor(rules) {
|
25 | super()
|
26 | const re = Array.isArray(rules) ? rules : [rules]
|
27 | const fr = re.filter(checkRule)
|
28 | this.rules = fr
|
29 | }
|
30 |
|
31 | |
32 |
|
33 |
|
34 | brake() {
|
35 | this._broke = true
|
36 | }
|
37 |
|
38 | async reduce(chunk) {
|
39 |
|
40 | const s = await this.rules.reduce(async (acc, { re, replacement }) => {
|
41 |
|
42 | let string = await acc
|
43 | if (this._broke) return string
|
44 |
|
45 | if (typeof replacement == 'string') {
|
46 | string = string.replace(re, replacement)
|
47 | } else {
|
48 |
|
49 | const R = replacement.bind(this)
|
50 | const promises = []
|
51 | let commonError
|
52 | const t = string.replace(re, (match, ...args) => {
|
53 | commonError = new Error()
|
54 | try {
|
55 | if (this._broke) return match
|
56 | const p = R(match, ...args)
|
57 | if (p instanceof Promise) {
|
58 | promises.push(p)
|
59 | }
|
60 | return p
|
61 | } catch (e) {
|
62 | hideStack(commonError, e)
|
63 | }
|
64 | })
|
65 | if (promises.length) {
|
66 | try {
|
67 | const data = await Promise.all(promises)
|
68 | string = string.replace(re, () => data.shift())
|
69 | } catch (e) {
|
70 | hideStack(commonError, e)
|
71 | }
|
72 | } else {
|
73 | string = t
|
74 | }
|
75 | }
|
76 | return string
|
77 | }, `${chunk}`)
|
78 |
|
79 | return s
|
80 | }
|
81 | async _transform(chunk, _, next) {
|
82 | try {
|
83 | const s = await this.reduce(chunk)
|
84 | this.push(s)
|
85 | next()
|
86 | } catch (e) {
|
87 | const s = cleanStack(e.stack)
|
88 | e.stack = s
|
89 | next(e)
|
90 | }
|
91 | }
|
92 | }
|
93 |
|
94 | const hideStack = (commonError, thrownError) => {
|
95 | if (!(thrownError instanceof Error)) throw thrownError
|
96 | const [, , commonLine] = commonError.stack.split('\n', 3)
|
97 | const i = thrownError.stack.indexOf(commonLine)
|
98 | if (i == -1) throw thrownError
|
99 | const stack = thrownError.stack.substr(0, i - 1)
|
100 | const li = stack.lastIndexOf('\n')
|
101 | thrownError.stack = stack.substr(0, li)
|
102 | throw thrownError
|
103 | }
|
104 |
|
105 | module.exports = Replaceable
|
106 |
|
\ | No newline at end of file |