UNPKG

9.46 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.replaceEnvVariables = exports.buildIgnorePattern = exports.sortMap = exports.dynamicRequireNoCache = exports.dynamicRequire = exports.DefaultStream = exports.BufferStream = exports.bufferStream = exports.prettifySyncErrors = exports.prettifyAsyncErrors = exports.releaseAfterUseAsync = exports.getMapWithDefault = exports.getSetWithDefault = exports.getArrayWithDefault = exports.getFactoryWithDefault = exports.isIndexableObject = exports.mapAndFind = exports.mapAndFilter = exports.validateEnum = exports.assertNever = exports.overrideType = exports.escapeRegExp = void 0;
4const tslib_1 = require("tslib");
5const fslib_1 = require("@yarnpkg/fslib");
6const clipanion_1 = require("clipanion");
7const micromatch_1 = tslib_1.__importDefault(require("micromatch"));
8const stream_1 = require("stream");
9function escapeRegExp(str) {
10 return str.replace(/[.*+?^${}()|[\]\\]/g, `\\$&`);
11}
12exports.escapeRegExp = escapeRegExp;
13function overrideType(val) {
14}
15exports.overrideType = overrideType;
16function assertNever(arg) {
17 throw new Error(`Assertion failed: Unexpected object '${arg}'`);
18}
19exports.assertNever = assertNever;
20function validateEnum(def, value) {
21 if (!Object.values(def).includes(value))
22 throw new Error(`Assertion failed: Invalid value for enumeration`);
23 return value;
24}
25exports.validateEnum = validateEnum;
26function mapAndFilter(iterable, cb) {
27 const output = [];
28 for (const value of iterable) {
29 const out = cb(value);
30 if (out !== mapAndFilterSkip) {
31 output.push(out);
32 }
33 }
34 return output;
35}
36exports.mapAndFilter = mapAndFilter;
37const mapAndFilterSkip = Symbol();
38mapAndFilter.skip = mapAndFilterSkip;
39function mapAndFind(iterable, cb) {
40 for (const value of iterable) {
41 const out = cb(value);
42 if (out !== mapAndFindSkip) {
43 return out;
44 }
45 }
46 return undefined;
47}
48exports.mapAndFind = mapAndFind;
49const mapAndFindSkip = Symbol();
50mapAndFind.skip = mapAndFindSkip;
51function isIndexableObject(value) {
52 return typeof value === `object` && value !== null;
53}
54exports.isIndexableObject = isIndexableObject;
55function getFactoryWithDefault(map, key, factory) {
56 let value = map.get(key);
57 if (typeof value === `undefined`)
58 map.set(key, value = factory());
59 return value;
60}
61exports.getFactoryWithDefault = getFactoryWithDefault;
62function getArrayWithDefault(map, key) {
63 let value = map.get(key);
64 if (typeof value === `undefined`)
65 map.set(key, value = []);
66 return value;
67}
68exports.getArrayWithDefault = getArrayWithDefault;
69function getSetWithDefault(map, key) {
70 let value = map.get(key);
71 if (typeof value === `undefined`)
72 map.set(key, value = new Set());
73 return value;
74}
75exports.getSetWithDefault = getSetWithDefault;
76function getMapWithDefault(map, key) {
77 let value = map.get(key);
78 if (typeof value === `undefined`)
79 map.set(key, value = new Map());
80 return value;
81}
82exports.getMapWithDefault = getMapWithDefault;
83// Executes a chunk of code and calls a cleanup function once it returns (even
84// if it throws an exception)
85async function releaseAfterUseAsync(fn, cleanup) {
86 if (cleanup == null)
87 return await fn();
88 try {
89 return await fn();
90 }
91 finally {
92 await cleanup();
93 }
94}
95exports.releaseAfterUseAsync = releaseAfterUseAsync;
96// Executes a chunk of code but slightly modify its exception message if it
97// throws something
98async function prettifyAsyncErrors(fn, update) {
99 try {
100 return await fn();
101 }
102 catch (error) {
103 error.message = update(error.message);
104 throw error;
105 }
106}
107exports.prettifyAsyncErrors = prettifyAsyncErrors;
108// Same thing but synchronous
109function prettifySyncErrors(fn, update) {
110 try {
111 return fn();
112 }
113 catch (error) {
114 error.message = update(error.message);
115 throw error;
116 }
117}
118exports.prettifySyncErrors = prettifySyncErrors;
119// Converts a Node stream into a Buffer instance
120async function bufferStream(stream) {
121 return await new Promise((resolve, reject) => {
122 const chunks = [];
123 stream.on(`error`, error => {
124 reject(error);
125 });
126 stream.on(`data`, chunk => {
127 chunks.push(chunk);
128 });
129 stream.on(`end`, () => {
130 resolve(Buffer.concat(chunks));
131 });
132 });
133}
134exports.bufferStream = bufferStream;
135// A stream implementation that buffers a stream to send it all at once
136class BufferStream extends stream_1.Transform {
137 constructor() {
138 super(...arguments);
139 this.chunks = [];
140 }
141 _transform(chunk, encoding, cb) {
142 if (encoding !== `buffer` || !Buffer.isBuffer(chunk))
143 throw new Error(`Assertion failed: BufferStream only accept buffers`);
144 this.chunks.push(chunk);
145 cb(null, null);
146 }
147 _flush(cb) {
148 cb(null, Buffer.concat(this.chunks));
149 }
150}
151exports.BufferStream = BufferStream;
152// A stream implementation that prints a message if nothing was output
153class DefaultStream extends stream_1.Transform {
154 constructor(ifEmpty = Buffer.alloc(0)) {
155 super();
156 this.active = true;
157 this.ifEmpty = ifEmpty;
158 }
159 _transform(chunk, encoding, cb) {
160 if (encoding !== `buffer` || !Buffer.isBuffer(chunk))
161 throw new Error(`Assertion failed: DefaultStream only accept buffers`);
162 this.active = false;
163 cb(null, chunk);
164 }
165 _flush(cb) {
166 if (this.active && this.ifEmpty.length > 0) {
167 cb(null, this.ifEmpty);
168 }
169 }
170}
171exports.DefaultStream = DefaultStream;
172// Webpack has this annoying tendency to replace dynamic requires by a stub
173// code that simply throws when called. It's all fine and dandy in the context
174// of a web application, but is quite annoying when working with Node projects!
175function dynamicRequire(path) {
176 // @ts-expect-error
177 if (typeof __non_webpack_require__ !== `undefined`) {
178 // @ts-expect-error
179 return __non_webpack_require__(path);
180 }
181 else {
182 return require(path);
183 }
184}
185exports.dynamicRequire = dynamicRequire;
186function dynamicRequireNoCache(path) {
187 const physicalPath = fslib_1.npath.fromPortablePath(path);
188 const currentCacheEntry = require.cache[physicalPath];
189 delete require.cache[physicalPath];
190 let result;
191 try {
192 result = dynamicRequire(physicalPath);
193 const freshCacheEntry = require.cache[physicalPath];
194 const freshCacheIndex = module.children.indexOf(freshCacheEntry);
195 if (freshCacheIndex !== -1) {
196 module.children.splice(freshCacheIndex, 1);
197 }
198 }
199 finally {
200 require.cache[physicalPath] = currentCacheEntry;
201 }
202 return result;
203}
204exports.dynamicRequireNoCache = dynamicRequireNoCache;
205// This function transforms an iterable into an array and sorts it according to
206// the mapper functions provided as parameter. The mappers are expected to take
207// each element from the iterable and generate a string from it, that will then
208// be used to compare the entries.
209//
210// Using sortMap is more efficient than kinda reimplementing the logic in a sort
211// predicate because sortMap caches the result of the mappers in such a way that
212// they are guaranteed to be executed exactly once for each element.
213function sortMap(values, mappers) {
214 const asArray = Array.from(values);
215 if (!Array.isArray(mappers))
216 mappers = [mappers];
217 const stringified = [];
218 for (const mapper of mappers)
219 stringified.push(asArray.map(value => mapper(value)));
220 const indices = asArray.map((_, index) => index);
221 indices.sort((a, b) => {
222 for (const layer of stringified) {
223 const comparison = layer[a] < layer[b] ? -1 : layer[a] > layer[b] ? +1 : 0;
224 if (comparison !== 0) {
225 return comparison;
226 }
227 }
228 return 0;
229 });
230 return indices.map(index => {
231 return asArray[index];
232 });
233}
234exports.sortMap = sortMap;
235/**
236 * Combines an Array of glob patterns into a regular expression.
237 *
238 * @param ignorePatterns An array of glob patterns
239 *
240 * @returns A `string` representing a regular expression or `null` if no glob patterns are provided
241 */
242function buildIgnorePattern(ignorePatterns) {
243 if (ignorePatterns.length === 0)
244 return null;
245 return ignorePatterns.map(pattern => {
246 return `(${micromatch_1.default.makeRe(pattern, {
247 windows: false,
248 }).source})`;
249 }).join(`|`);
250}
251exports.buildIgnorePattern = buildIgnorePattern;
252function replaceEnvVariables(value, { env }) {
253 const regex = /\${(?<variableName>[\d\w_]+)(?<colon>:)?-?(?<fallback>[^}]+)?}/g;
254 return value.replace(regex, (...args) => {
255 const { variableName, colon, fallback } = args[args.length - 1];
256 const variableExist = Object.prototype.hasOwnProperty.call(env, variableName);
257 const variableValue = env[variableName];
258 if (variableValue)
259 return variableValue;
260 if (variableExist && !variableValue && colon)
261 return fallback;
262 if (variableExist)
263 return variableValue;
264 if (fallback)
265 return fallback;
266 throw new clipanion_1.UsageError(`Environment variable not found (${variableName})`);
267 });
268}
269exports.replaceEnvVariables = replaceEnvVariables;