[79a0317] | 1 | /*
|
---|
| 2 | MIT License http://www.opensource.org/licenses/mit-license.php
|
---|
| 3 | Author Tobias Koppers @sokra
|
---|
| 4 | */
|
---|
| 5 | "use strict";
|
---|
| 6 |
|
---|
| 7 | const Source = require("./Source");
|
---|
| 8 | const streamChunksOfSourceMap = require("./helpers/streamChunksOfSourceMap");
|
---|
| 9 | const streamChunksOfRawSource = require("./helpers/streamChunksOfRawSource");
|
---|
| 10 | const streamAndGetSourceAndMap = require("./helpers/streamAndGetSourceAndMap");
|
---|
| 11 |
|
---|
| 12 | const mapToBufferedMap = map => {
|
---|
| 13 | if (typeof map !== "object" || !map) return map;
|
---|
| 14 | const bufferedMap = Object.assign({}, map);
|
---|
| 15 | if (map.mappings) {
|
---|
| 16 | bufferedMap.mappings = Buffer.from(map.mappings, "utf-8");
|
---|
| 17 | }
|
---|
| 18 | if (map.sourcesContent) {
|
---|
| 19 | bufferedMap.sourcesContent = map.sourcesContent.map(
|
---|
| 20 | str => str && Buffer.from(str, "utf-8")
|
---|
| 21 | );
|
---|
| 22 | }
|
---|
| 23 | return bufferedMap;
|
---|
| 24 | };
|
---|
| 25 |
|
---|
| 26 | const bufferedMapToMap = bufferedMap => {
|
---|
| 27 | if (typeof bufferedMap !== "object" || !bufferedMap) return bufferedMap;
|
---|
| 28 | const map = Object.assign({}, bufferedMap);
|
---|
| 29 | if (bufferedMap.mappings) {
|
---|
| 30 | map.mappings = bufferedMap.mappings.toString("utf-8");
|
---|
| 31 | }
|
---|
| 32 | if (bufferedMap.sourcesContent) {
|
---|
| 33 | map.sourcesContent = bufferedMap.sourcesContent.map(
|
---|
| 34 | buffer => buffer && buffer.toString("utf-8")
|
---|
| 35 | );
|
---|
| 36 | }
|
---|
| 37 | return map;
|
---|
| 38 | };
|
---|
| 39 |
|
---|
| 40 | class CachedSource extends Source {
|
---|
| 41 | constructor(source, cachedData) {
|
---|
| 42 | super();
|
---|
| 43 | this._source = source;
|
---|
| 44 | this._cachedSourceType = cachedData ? cachedData.source : undefined;
|
---|
| 45 | this._cachedSource = undefined;
|
---|
| 46 | this._cachedBuffer = cachedData ? cachedData.buffer : undefined;
|
---|
| 47 | this._cachedSize = cachedData ? cachedData.size : undefined;
|
---|
| 48 | this._cachedMaps = cachedData ? cachedData.maps : new Map();
|
---|
| 49 | this._cachedHashUpdate = cachedData ? cachedData.hash : undefined;
|
---|
| 50 | }
|
---|
| 51 |
|
---|
| 52 | getCachedData() {
|
---|
| 53 | const bufferedMaps = new Map();
|
---|
| 54 | for (const pair of this._cachedMaps) {
|
---|
| 55 | let cacheEntry = pair[1];
|
---|
| 56 | if (cacheEntry.bufferedMap === undefined) {
|
---|
| 57 | cacheEntry.bufferedMap = mapToBufferedMap(
|
---|
| 58 | this._getMapFromCacheEntry(cacheEntry)
|
---|
| 59 | );
|
---|
| 60 | }
|
---|
| 61 | bufferedMaps.set(pair[0], {
|
---|
| 62 | map: undefined,
|
---|
| 63 | bufferedMap: cacheEntry.bufferedMap
|
---|
| 64 | });
|
---|
| 65 | }
|
---|
| 66 | // We don't want to cache strings
|
---|
| 67 | // So if we have a caches sources
|
---|
| 68 | // create a buffer from it and only store
|
---|
| 69 | // if it was a Buffer or string
|
---|
| 70 | if (this._cachedSource) {
|
---|
| 71 | this.buffer();
|
---|
| 72 | }
|
---|
| 73 | return {
|
---|
| 74 | buffer: this._cachedBuffer,
|
---|
| 75 | source:
|
---|
| 76 | this._cachedSourceType !== undefined
|
---|
| 77 | ? this._cachedSourceType
|
---|
| 78 | : typeof this._cachedSource === "string"
|
---|
| 79 | ? true
|
---|
| 80 | : Buffer.isBuffer(this._cachedSource)
|
---|
| 81 | ? false
|
---|
| 82 | : undefined,
|
---|
| 83 | size: this._cachedSize,
|
---|
| 84 | maps: bufferedMaps,
|
---|
| 85 | hash: this._cachedHashUpdate
|
---|
| 86 | };
|
---|
| 87 | }
|
---|
| 88 |
|
---|
| 89 | originalLazy() {
|
---|
| 90 | return this._source;
|
---|
| 91 | }
|
---|
| 92 |
|
---|
| 93 | original() {
|
---|
| 94 | if (typeof this._source === "function") this._source = this._source();
|
---|
| 95 | return this._source;
|
---|
| 96 | }
|
---|
| 97 |
|
---|
| 98 | source() {
|
---|
| 99 | const source = this._getCachedSource();
|
---|
| 100 | if (source !== undefined) return source;
|
---|
| 101 | return (this._cachedSource = this.original().source());
|
---|
| 102 | }
|
---|
| 103 |
|
---|
| 104 | _getMapFromCacheEntry(cacheEntry) {
|
---|
| 105 | if (cacheEntry.map !== undefined) {
|
---|
| 106 | return cacheEntry.map;
|
---|
| 107 | } else if (cacheEntry.bufferedMap !== undefined) {
|
---|
| 108 | return (cacheEntry.map = bufferedMapToMap(cacheEntry.bufferedMap));
|
---|
| 109 | }
|
---|
| 110 | }
|
---|
| 111 |
|
---|
| 112 | _getCachedSource() {
|
---|
| 113 | if (this._cachedSource !== undefined) return this._cachedSource;
|
---|
| 114 | if (this._cachedBuffer && this._cachedSourceType !== undefined) {
|
---|
| 115 | return (this._cachedSource = this._cachedSourceType
|
---|
| 116 | ? this._cachedBuffer.toString("utf-8")
|
---|
| 117 | : this._cachedBuffer);
|
---|
| 118 | }
|
---|
| 119 | }
|
---|
| 120 |
|
---|
| 121 | buffer() {
|
---|
| 122 | if (this._cachedBuffer !== undefined) return this._cachedBuffer;
|
---|
| 123 | if (this._cachedSource !== undefined) {
|
---|
| 124 | if (Buffer.isBuffer(this._cachedSource)) {
|
---|
| 125 | return (this._cachedBuffer = this._cachedSource);
|
---|
| 126 | }
|
---|
| 127 | return (this._cachedBuffer = Buffer.from(this._cachedSource, "utf-8"));
|
---|
| 128 | }
|
---|
| 129 | if (typeof this.original().buffer === "function") {
|
---|
| 130 | return (this._cachedBuffer = this.original().buffer());
|
---|
| 131 | }
|
---|
| 132 | const bufferOrString = this.source();
|
---|
| 133 | if (Buffer.isBuffer(bufferOrString)) {
|
---|
| 134 | return (this._cachedBuffer = bufferOrString);
|
---|
| 135 | }
|
---|
| 136 | return (this._cachedBuffer = Buffer.from(bufferOrString, "utf-8"));
|
---|
| 137 | }
|
---|
| 138 |
|
---|
| 139 | size() {
|
---|
| 140 | if (this._cachedSize !== undefined) return this._cachedSize;
|
---|
| 141 | if (this._cachedBuffer !== undefined) {
|
---|
| 142 | return (this._cachedSize = this._cachedBuffer.length);
|
---|
| 143 | }
|
---|
| 144 | const source = this._getCachedSource();
|
---|
| 145 | if (source !== undefined) {
|
---|
| 146 | return (this._cachedSize = Buffer.byteLength(source));
|
---|
| 147 | }
|
---|
| 148 | return (this._cachedSize = this.original().size());
|
---|
| 149 | }
|
---|
| 150 |
|
---|
| 151 | sourceAndMap(options) {
|
---|
| 152 | const key = options ? JSON.stringify(options) : "{}";
|
---|
| 153 | const cacheEntry = this._cachedMaps.get(key);
|
---|
| 154 | // Look for a cached map
|
---|
| 155 | if (cacheEntry !== undefined) {
|
---|
| 156 | // We have a cached map in some representation
|
---|
| 157 | const map = this._getMapFromCacheEntry(cacheEntry);
|
---|
| 158 | // Either get the cached source or compute it
|
---|
| 159 | return { source: this.source(), map };
|
---|
| 160 | }
|
---|
| 161 | // Look for a cached source
|
---|
| 162 | let source = this._getCachedSource();
|
---|
| 163 | // Compute the map
|
---|
| 164 | let map;
|
---|
| 165 | if (source !== undefined) {
|
---|
| 166 | map = this.original().map(options);
|
---|
| 167 | } else {
|
---|
| 168 | // Compute the source and map together.
|
---|
| 169 | const sourceAndMap = this.original().sourceAndMap(options);
|
---|
| 170 | source = sourceAndMap.source;
|
---|
| 171 | map = sourceAndMap.map;
|
---|
| 172 | this._cachedSource = source;
|
---|
| 173 | }
|
---|
| 174 | this._cachedMaps.set(key, {
|
---|
| 175 | map,
|
---|
| 176 | bufferedMap: undefined
|
---|
| 177 | });
|
---|
| 178 | return { source, map };
|
---|
| 179 | }
|
---|
| 180 |
|
---|
| 181 | streamChunks(options, onChunk, onSource, onName) {
|
---|
| 182 | const key = options ? JSON.stringify(options) : "{}";
|
---|
| 183 | if (
|
---|
| 184 | this._cachedMaps.has(key) &&
|
---|
| 185 | (this._cachedBuffer !== undefined || this._cachedSource !== undefined)
|
---|
| 186 | ) {
|
---|
| 187 | const { source, map } = this.sourceAndMap(options);
|
---|
| 188 | if (map) {
|
---|
| 189 | return streamChunksOfSourceMap(
|
---|
| 190 | source,
|
---|
| 191 | map,
|
---|
| 192 | onChunk,
|
---|
| 193 | onSource,
|
---|
| 194 | onName,
|
---|
| 195 | !!(options && options.finalSource),
|
---|
| 196 | true
|
---|
| 197 | );
|
---|
| 198 | } else {
|
---|
| 199 | return streamChunksOfRawSource(
|
---|
| 200 | source,
|
---|
| 201 | onChunk,
|
---|
| 202 | onSource,
|
---|
| 203 | onName,
|
---|
| 204 | !!(options && options.finalSource)
|
---|
| 205 | );
|
---|
| 206 | }
|
---|
| 207 | }
|
---|
| 208 | const { result, source, map } = streamAndGetSourceAndMap(
|
---|
| 209 | this.original(),
|
---|
| 210 | options,
|
---|
| 211 | onChunk,
|
---|
| 212 | onSource,
|
---|
| 213 | onName
|
---|
| 214 | );
|
---|
| 215 | this._cachedSource = source;
|
---|
| 216 | this._cachedMaps.set(key, {
|
---|
| 217 | map,
|
---|
| 218 | bufferedMap: undefined
|
---|
| 219 | });
|
---|
| 220 | return result;
|
---|
| 221 | }
|
---|
| 222 |
|
---|
| 223 | map(options) {
|
---|
| 224 | const key = options ? JSON.stringify(options) : "{}";
|
---|
| 225 | const cacheEntry = this._cachedMaps.get(key);
|
---|
| 226 | if (cacheEntry !== undefined) {
|
---|
| 227 | return this._getMapFromCacheEntry(cacheEntry);
|
---|
| 228 | }
|
---|
| 229 | const map = this.original().map(options);
|
---|
| 230 | this._cachedMaps.set(key, {
|
---|
| 231 | map,
|
---|
| 232 | bufferedMap: undefined
|
---|
| 233 | });
|
---|
| 234 | return map;
|
---|
| 235 | }
|
---|
| 236 |
|
---|
| 237 | updateHash(hash) {
|
---|
| 238 | if (this._cachedHashUpdate !== undefined) {
|
---|
| 239 | for (const item of this._cachedHashUpdate) hash.update(item);
|
---|
| 240 | return;
|
---|
| 241 | }
|
---|
| 242 | const update = [];
|
---|
| 243 | let currentString = undefined;
|
---|
| 244 | const tracker = {
|
---|
| 245 | update: item => {
|
---|
| 246 | if (typeof item === "string" && item.length < 10240) {
|
---|
| 247 | if (currentString === undefined) {
|
---|
| 248 | currentString = item;
|
---|
| 249 | } else {
|
---|
| 250 | currentString += item;
|
---|
| 251 | if (currentString.length > 102400) {
|
---|
| 252 | update.push(Buffer.from(currentString));
|
---|
| 253 | currentString = undefined;
|
---|
| 254 | }
|
---|
| 255 | }
|
---|
| 256 | } else {
|
---|
| 257 | if (currentString !== undefined) {
|
---|
| 258 | update.push(Buffer.from(currentString));
|
---|
| 259 | currentString = undefined;
|
---|
| 260 | }
|
---|
| 261 | update.push(item);
|
---|
| 262 | }
|
---|
| 263 | }
|
---|
| 264 | };
|
---|
| 265 | this.original().updateHash(tracker);
|
---|
| 266 | if (currentString !== undefined) {
|
---|
| 267 | update.push(Buffer.from(currentString));
|
---|
| 268 | }
|
---|
| 269 | for (const item of update) hash.update(item);
|
---|
| 270 | this._cachedHashUpdate = update;
|
---|
| 271 | }
|
---|
| 272 | }
|
---|
| 273 |
|
---|
| 274 | module.exports = CachedSource;
|
---|