resafe 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +77 -36
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +77 -36
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -321,9 +321,21 @@ var Formatter = class _Formatter {
|
|
|
321
321
|
red() {
|
|
322
322
|
return this.code("38;2;255;85;85");
|
|
323
323
|
}
|
|
324
|
+
yellow() {
|
|
325
|
+
return this.code("38;2;255;200;50");
|
|
326
|
+
}
|
|
327
|
+
blue() {
|
|
328
|
+
return this.code("38;2;100;149;237");
|
|
329
|
+
}
|
|
330
|
+
green() {
|
|
331
|
+
return this.code("38;2;85;255;85");
|
|
332
|
+
}
|
|
324
333
|
pastelRedBg() {
|
|
325
334
|
return this.code("48;2;255;85;85");
|
|
326
335
|
}
|
|
336
|
+
pastelYellowBg() {
|
|
337
|
+
return this.code("48;2;255;200;50");
|
|
338
|
+
}
|
|
327
339
|
toString() {
|
|
328
340
|
return `${this.parts}${this.text}${ESC}0m`;
|
|
329
341
|
}
|
|
@@ -332,53 +344,82 @@ var Formatter = class _Formatter {
|
|
|
332
344
|
}
|
|
333
345
|
};
|
|
334
346
|
var fmt = (text) => Formatter.create(text);
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
},
|
|
345
|
-
warn: (msg, regex, extra) => {
|
|
346
|
-
let firstLine = `${fmt(" RESAFE ").bold().pastelRedBg().white()} ${fmt(msg).white()}`;
|
|
347
|
-
if (regex) {
|
|
348
|
-
firstLine += ` ${fmt("regex").red()}${fmt("=").darkGray()}${fmt(regex).white()}`;
|
|
349
|
-
}
|
|
350
|
-
import_node_process.stdout.write(`${firstLine}
|
|
347
|
+
function formatLogLine(prefixBg, msg, options) {
|
|
348
|
+
const prefix = prefixBg(fmt(" RESAFE ").bold()).white();
|
|
349
|
+
let line = `${prefix} ${fmt(msg).white()}`;
|
|
350
|
+
if (options?.property) {
|
|
351
|
+
const prop = options.property;
|
|
352
|
+
const nameFmt = prop.color ? prop.color(fmt(prop.name)) : fmt(prop.name).bold();
|
|
353
|
+
line += ` ${nameFmt}${fmt("=").darkGray()}${fmt(prop.value).white()}`;
|
|
354
|
+
}
|
|
355
|
+
import_node_process.stdout.write(`${line}
|
|
351
356
|
`);
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
const lines = Array.isArray(msg) ? msg : [msg];
|
|
356
|
-
log.quote(lines);
|
|
357
|
-
},
|
|
358
|
-
quote: (lines) => {
|
|
359
|
-
lines.forEach((line) => {
|
|
360
|
-
import_node_process.stdout.write(` ${fmt("\u2502").darkGray()} ${fmt(line).white()}
|
|
357
|
+
if (options?.lines) {
|
|
358
|
+
for (const l of options.lines) {
|
|
359
|
+
import_node_process.stdout.write(` ${fmt("\u2502").darkGray()} ${fmt(l).white()}
|
|
361
360
|
`);
|
|
362
|
-
}
|
|
361
|
+
}
|
|
363
362
|
import_node_process.stdout.write("\n");
|
|
364
363
|
}
|
|
364
|
+
}
|
|
365
|
+
var log = {
|
|
366
|
+
error: (msg, options) => formatLogLine((f) => f.pastelRedBg(), msg, options),
|
|
367
|
+
warn: (msg, options) => formatLogLine((f) => f.pastelYellowBg(), msg, options)
|
|
365
368
|
};
|
|
366
369
|
|
|
367
370
|
// src/index.ts
|
|
368
371
|
function check(regex, options = {}) {
|
|
372
|
+
if (regex == null || regex === "") {
|
|
373
|
+
const err = new Error("Empty regex. Provide a valid pattern.");
|
|
374
|
+
log.warn("Empty regex!", {
|
|
375
|
+
lines: ["? Provide a valid regex."]
|
|
376
|
+
});
|
|
377
|
+
if (options.throwErr) throw err;
|
|
378
|
+
return null;
|
|
379
|
+
}
|
|
380
|
+
if (typeof regex !== "string" && !(regex instanceof RegExp)) {
|
|
381
|
+
const err = new TypeError("Regex must be string or RegExp");
|
|
382
|
+
log.error("Invalid regex!", {
|
|
383
|
+
property: { name: "type", value: typeof regex }
|
|
384
|
+
});
|
|
385
|
+
throw err;
|
|
386
|
+
}
|
|
369
387
|
const pattern = typeof regex === "string" ? regex : regex.source;
|
|
388
|
+
try {
|
|
389
|
+
new RegExp(pattern);
|
|
390
|
+
} catch (err) {
|
|
391
|
+
if (err instanceof SyntaxError) {
|
|
392
|
+
log.error("Invalid regex syntax!", {
|
|
393
|
+
lines: [`? ${err.message}`]
|
|
394
|
+
});
|
|
395
|
+
if (options.throwErr) throw err;
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
throw err;
|
|
399
|
+
}
|
|
400
|
+
if (/\\u\{[0-9A-Fa-f]+\}/.test(pattern)) {
|
|
401
|
+
log.warn("Unicode escape sequences may not be fully supported", {
|
|
402
|
+
property: { name: "pattern", value: pattern }
|
|
403
|
+
});
|
|
404
|
+
}
|
|
370
405
|
const result = analyze(pattern, options);
|
|
371
406
|
const radius = Number(result.radius.toFixed(4));
|
|
372
|
-
if (!result.safe
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
"
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
407
|
+
if (!result.safe) {
|
|
408
|
+
const err = new Error(`Unsafe regex (spectral radius ${radius})`);
|
|
409
|
+
if (!options.silent) {
|
|
410
|
+
log.error("Unsafe Regex!", {
|
|
411
|
+
property: {
|
|
412
|
+
name: "regex",
|
|
413
|
+
value: `/${pattern}/`,
|
|
414
|
+
color: (f) => f.red()
|
|
415
|
+
},
|
|
416
|
+
lines: [
|
|
417
|
+
`Spectral radius: ${radius} (threshold: ${options.threshold ?? 1})`,
|
|
418
|
+
"? Consider simplifying quantifiers"
|
|
419
|
+
]
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
if (options.throwErr) throw err;
|
|
382
423
|
}
|
|
383
424
|
return result;
|
|
384
425
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -10,7 +10,7 @@ interface Options extends Config {
|
|
|
10
10
|
silent?: boolean;
|
|
11
11
|
throwErr?: boolean;
|
|
12
12
|
}
|
|
13
|
-
declare function check(regex: string | RegExp, options?: Options): Result;
|
|
14
|
-
declare function checkAsync(regex: string | RegExp, options?: Options): Promise<Result>;
|
|
13
|
+
declare function check(regex: string | RegExp, options?: Options): Result | null;
|
|
14
|
+
declare function checkAsync(regex: string | RegExp, options?: Options): Promise<Result | null>;
|
|
15
15
|
|
|
16
16
|
export { type Config, type Options, type Result, check, checkAsync };
|
package/dist/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ interface Options extends Config {
|
|
|
10
10
|
silent?: boolean;
|
|
11
11
|
throwErr?: boolean;
|
|
12
12
|
}
|
|
13
|
-
declare function check(regex: string | RegExp, options?: Options): Result;
|
|
14
|
-
declare function checkAsync(regex: string | RegExp, options?: Options): Promise<Result>;
|
|
13
|
+
declare function check(regex: string | RegExp, options?: Options): Result | null;
|
|
14
|
+
declare function checkAsync(regex: string | RegExp, options?: Options): Promise<Result | null>;
|
|
15
15
|
|
|
16
16
|
export { type Config, type Options, type Result, check, checkAsync };
|
package/dist/index.js
CHANGED
|
@@ -294,9 +294,21 @@ var Formatter = class _Formatter {
|
|
|
294
294
|
red() {
|
|
295
295
|
return this.code("38;2;255;85;85");
|
|
296
296
|
}
|
|
297
|
+
yellow() {
|
|
298
|
+
return this.code("38;2;255;200;50");
|
|
299
|
+
}
|
|
300
|
+
blue() {
|
|
301
|
+
return this.code("38;2;100;149;237");
|
|
302
|
+
}
|
|
303
|
+
green() {
|
|
304
|
+
return this.code("38;2;85;255;85");
|
|
305
|
+
}
|
|
297
306
|
pastelRedBg() {
|
|
298
307
|
return this.code("48;2;255;85;85");
|
|
299
308
|
}
|
|
309
|
+
pastelYellowBg() {
|
|
310
|
+
return this.code("48;2;255;200;50");
|
|
311
|
+
}
|
|
300
312
|
toString() {
|
|
301
313
|
return `${this.parts}${this.text}${ESC}0m`;
|
|
302
314
|
}
|
|
@@ -305,53 +317,82 @@ var Formatter = class _Formatter {
|
|
|
305
317
|
}
|
|
306
318
|
};
|
|
307
319
|
var fmt = (text) => Formatter.create(text);
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
},
|
|
318
|
-
warn: (msg, regex, extra) => {
|
|
319
|
-
let firstLine = `${fmt(" RESAFE ").bold().pastelRedBg().white()} ${fmt(msg).white()}`;
|
|
320
|
-
if (regex) {
|
|
321
|
-
firstLine += ` ${fmt("regex").red()}${fmt("=").darkGray()}${fmt(regex).white()}`;
|
|
322
|
-
}
|
|
323
|
-
stdout.write(`${firstLine}
|
|
320
|
+
function formatLogLine(prefixBg, msg, options) {
|
|
321
|
+
const prefix = prefixBg(fmt(" RESAFE ").bold()).white();
|
|
322
|
+
let line = `${prefix} ${fmt(msg).white()}`;
|
|
323
|
+
if (options?.property) {
|
|
324
|
+
const prop = options.property;
|
|
325
|
+
const nameFmt = prop.color ? prop.color(fmt(prop.name)) : fmt(prop.name).bold();
|
|
326
|
+
line += ` ${nameFmt}${fmt("=").darkGray()}${fmt(prop.value).white()}`;
|
|
327
|
+
}
|
|
328
|
+
stdout.write(`${line}
|
|
324
329
|
`);
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
const lines = Array.isArray(msg) ? msg : [msg];
|
|
329
|
-
log.quote(lines);
|
|
330
|
-
},
|
|
331
|
-
quote: (lines) => {
|
|
332
|
-
lines.forEach((line) => {
|
|
333
|
-
stdout.write(` ${fmt("\u2502").darkGray()} ${fmt(line).white()}
|
|
330
|
+
if (options?.lines) {
|
|
331
|
+
for (const l of options.lines) {
|
|
332
|
+
stdout.write(` ${fmt("\u2502").darkGray()} ${fmt(l).white()}
|
|
334
333
|
`);
|
|
335
|
-
}
|
|
334
|
+
}
|
|
336
335
|
stdout.write("\n");
|
|
337
336
|
}
|
|
337
|
+
}
|
|
338
|
+
var log = {
|
|
339
|
+
error: (msg, options) => formatLogLine((f) => f.pastelRedBg(), msg, options),
|
|
340
|
+
warn: (msg, options) => formatLogLine((f) => f.pastelYellowBg(), msg, options)
|
|
338
341
|
};
|
|
339
342
|
|
|
340
343
|
// src/index.ts
|
|
341
344
|
function check(regex, options = {}) {
|
|
345
|
+
if (regex == null || regex === "") {
|
|
346
|
+
const err = new Error("Empty regex. Provide a valid pattern.");
|
|
347
|
+
log.warn("Empty regex!", {
|
|
348
|
+
lines: ["? Provide a valid regex."]
|
|
349
|
+
});
|
|
350
|
+
if (options.throwErr) throw err;
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
if (typeof regex !== "string" && !(regex instanceof RegExp)) {
|
|
354
|
+
const err = new TypeError("Regex must be string or RegExp");
|
|
355
|
+
log.error("Invalid regex!", {
|
|
356
|
+
property: { name: "type", value: typeof regex }
|
|
357
|
+
});
|
|
358
|
+
throw err;
|
|
359
|
+
}
|
|
342
360
|
const pattern = typeof regex === "string" ? regex : regex.source;
|
|
361
|
+
try {
|
|
362
|
+
new RegExp(pattern);
|
|
363
|
+
} catch (err) {
|
|
364
|
+
if (err instanceof SyntaxError) {
|
|
365
|
+
log.error("Invalid regex syntax!", {
|
|
366
|
+
lines: [`? ${err.message}`]
|
|
367
|
+
});
|
|
368
|
+
if (options.throwErr) throw err;
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
371
|
+
throw err;
|
|
372
|
+
}
|
|
373
|
+
if (/\\u\{[0-9A-Fa-f]+\}/.test(pattern)) {
|
|
374
|
+
log.warn("Unicode escape sequences may not be fully supported", {
|
|
375
|
+
property: { name: "pattern", value: pattern }
|
|
376
|
+
});
|
|
377
|
+
}
|
|
343
378
|
const result = analyze(pattern, options);
|
|
344
379
|
const radius = Number(result.radius.toFixed(4));
|
|
345
|
-
if (!result.safe
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
"
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
380
|
+
if (!result.safe) {
|
|
381
|
+
const err = new Error(`Unsafe regex (spectral radius ${radius})`);
|
|
382
|
+
if (!options.silent) {
|
|
383
|
+
log.error("Unsafe Regex!", {
|
|
384
|
+
property: {
|
|
385
|
+
name: "regex",
|
|
386
|
+
value: `/${pattern}/`,
|
|
387
|
+
color: (f) => f.red()
|
|
388
|
+
},
|
|
389
|
+
lines: [
|
|
390
|
+
`Spectral radius: ${radius} (threshold: ${options.threshold ?? 1})`,
|
|
391
|
+
"? Consider simplifying quantifiers"
|
|
392
|
+
]
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
if (options.throwErr) throw err;
|
|
355
396
|
}
|
|
356
397
|
return result;
|
|
357
398
|
}
|
package/package.json
CHANGED