resafe 1.0.0 → 1.0.2
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/README.md +2 -2
- package/dist/index.cjs +95 -39
- package/dist/index.js +95 -39
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
<br/>
|
|
9
9
|
|
|
10
10
|
<p align="center">
|
|
11
|
-
<a href="https://github.com/ofabiodev/resafe/actions?query=branch%3Amain" rel="nofollow"><img alt="GitHub Actions Workflow Status" src="https://img.shields.io/github/actions/workflow/status/ofabiodev/resafe/
|
|
12
|
-
<a href="https://opensource.org/licenses/MIT" rel="nofollow"><img alt="
|
|
11
|
+
<a href="https://github.com/ofabiodev/resafe/actions?query=branch%3Amain" rel="nofollow"><img alt="GitHub Actions Workflow Status" src="https://img.shields.io/github/actions/workflow/status/ofabiodev/resafe/ci_test.yml?branch=main&event=push"></a>
|
|
12
|
+
<a href="https://opensource.org/licenses/MIT" rel="nofollow"><img alt="License" src="https://img.shields.io/badge/license-MIT-brightgreen"></a>
|
|
13
13
|
<a href="https://www.npmjs.com/package/resafe" rel="nofollow"><img alt="NPM Downloads" src="https://img.shields.io/npm/dw/resafe"></a>
|
|
14
14
|
</p>
|
|
15
15
|
|
package/dist/index.cjs
CHANGED
|
@@ -241,41 +241,40 @@ function spectralRadius(matrix) {
|
|
|
241
241
|
const n = matrix.length;
|
|
242
242
|
if (n === 0) return 0;
|
|
243
243
|
let v = Array(n).fill(1 / Math.sqrt(n));
|
|
244
|
-
|
|
244
|
+
const tolerance = 1e-6;
|
|
245
|
+
const maxIterations = 100;
|
|
246
|
+
for (let iter = 0; iter < maxIterations; iter++) {
|
|
245
247
|
const newV = Array(n).fill(0);
|
|
246
248
|
for (let i = 0; i < n; i++) {
|
|
247
|
-
const row = matrix[i];
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
const vec = v[j];
|
|
252
|
-
if (cell !== void 0 && vec !== void 0) {
|
|
253
|
-
newV[i] += cell * vec;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
249
|
+
const row = matrix[i] ?? [];
|
|
250
|
+
for (let j = 0; j < n; j++) {
|
|
251
|
+
const cell = row[j] ?? 0;
|
|
252
|
+
newV[i] += cell * v[j];
|
|
256
253
|
}
|
|
257
254
|
}
|
|
258
255
|
const norm = Math.sqrt(newV.reduce((sum, val) => sum + val * val, 0));
|
|
259
256
|
if (norm === 0) return 0;
|
|
260
|
-
|
|
257
|
+
const normalizedV = newV.map((val) => val / norm);
|
|
258
|
+
let converged = true;
|
|
259
|
+
for (let i = 0; i < n; i++) {
|
|
260
|
+
const a = normalizedV[i];
|
|
261
|
+
const b = v[i];
|
|
262
|
+
if (a !== void 0 && b !== void 0 && Math.abs(a - b) > tolerance) {
|
|
263
|
+
converged = false;
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (converged) break;
|
|
268
|
+
v = normalizedV;
|
|
261
269
|
}
|
|
262
270
|
let eigenvalue = 0;
|
|
263
271
|
for (let i = 0; i < n; i++) {
|
|
272
|
+
const row = matrix[i] ?? [];
|
|
264
273
|
let sum = 0;
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
for (let j = 0; j < n; j++) {
|
|
268
|
-
const cell = row[j];
|
|
269
|
-
const vec = v[j];
|
|
270
|
-
if (cell !== void 0 && vec !== void 0) {
|
|
271
|
-
sum += cell * vec;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
const vecI = v[i];
|
|
276
|
-
if (vecI !== void 0) {
|
|
277
|
-
eigenvalue += sum * vecI;
|
|
274
|
+
for (let j = 0; j < n; j++) {
|
|
275
|
+
sum += (row[j] ?? 0) * v[j];
|
|
278
276
|
}
|
|
277
|
+
eigenvalue += sum * v[i];
|
|
279
278
|
}
|
|
280
279
|
return Math.abs(eigenvalue);
|
|
281
280
|
}
|
|
@@ -295,33 +294,90 @@ function analyze(pattern, config = {}) {
|
|
|
295
294
|
}
|
|
296
295
|
|
|
297
296
|
// src/utils/logger.ts
|
|
298
|
-
var
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
297
|
+
var import_node_process = require("process");
|
|
298
|
+
var ESC = "\x1B[";
|
|
299
|
+
var Formatter = class _Formatter {
|
|
300
|
+
parts = "";
|
|
301
|
+
text;
|
|
302
|
+
constructor(text) {
|
|
303
|
+
this.text = text;
|
|
304
|
+
}
|
|
305
|
+
code(code) {
|
|
306
|
+
this.parts += `${ESC}${code}m`;
|
|
307
|
+
return this;
|
|
308
|
+
}
|
|
309
|
+
static create(text) {
|
|
310
|
+
return new _Formatter(text);
|
|
311
|
+
}
|
|
312
|
+
bold() {
|
|
313
|
+
return this.code("1");
|
|
314
|
+
}
|
|
315
|
+
white() {
|
|
316
|
+
return this.code("97");
|
|
317
|
+
}
|
|
318
|
+
darkGray() {
|
|
319
|
+
return this.code("90");
|
|
320
|
+
}
|
|
321
|
+
red() {
|
|
322
|
+
return this.code("38;2;255;85;85");
|
|
323
|
+
}
|
|
324
|
+
pastelRedBg() {
|
|
325
|
+
return this.code("48;2;255;85;85");
|
|
326
|
+
}
|
|
327
|
+
toString() {
|
|
328
|
+
return `${this.parts}${this.text}${ESC}0m`;
|
|
329
|
+
}
|
|
330
|
+
[Symbol.toPrimitive]() {
|
|
331
|
+
return this.toString();
|
|
332
|
+
}
|
|
303
333
|
};
|
|
304
|
-
var
|
|
334
|
+
var fmt = (text) => Formatter.create(text);
|
|
305
335
|
var log = {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
336
|
+
error: (msg, regex, extra) => {
|
|
337
|
+
let firstLine = `${fmt(" RESAFE ").bold().pastelRedBg().white()} ${fmt(msg).white()}`;
|
|
338
|
+
if (regex) {
|
|
339
|
+
firstLine += ` ${fmt("regex").red()}${fmt("=").darkGray()}${fmt(regex).white()}`;
|
|
340
|
+
}
|
|
341
|
+
import_node_process.stdout.write(`${firstLine}
|
|
342
|
+
`);
|
|
343
|
+
if (extra) log.quote(extra);
|
|
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}
|
|
351
|
+
`);
|
|
352
|
+
if (extra) log.quote(extra);
|
|
353
|
+
},
|
|
354
|
+
hint: (msg) => {
|
|
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()}
|
|
361
|
+
`);
|
|
362
|
+
});
|
|
363
|
+
import_node_process.stdout.write("\n");
|
|
364
|
+
}
|
|
309
365
|
};
|
|
310
366
|
|
|
311
367
|
// src/index.ts
|
|
312
368
|
function check(regex, options = {}) {
|
|
313
369
|
const pattern = typeof regex === "string" ? regex : regex.source;
|
|
314
370
|
const result = analyze(pattern, options);
|
|
371
|
+
const radius = Number(result.radius.toFixed(4));
|
|
315
372
|
if (!result.safe && !options.silent) {
|
|
316
|
-
log.error(
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
);
|
|
320
|
-
log.hint("Simplify regex structure to eliminate exponential paths");
|
|
373
|
+
log.error("Unsafe Regex!", `/${pattern}/`, [
|
|
374
|
+
`Spectral radius: ${radius} (threshold: ${options.threshold ?? 1})`,
|
|
375
|
+
"? Consider simplifying quantifiers"
|
|
376
|
+
]);
|
|
321
377
|
}
|
|
322
378
|
if (!result.safe && options.throwErr) {
|
|
323
379
|
throw new Error(
|
|
324
|
-
`
|
|
380
|
+
`Unsafe regex (spectral radius ${radius})`
|
|
325
381
|
);
|
|
326
382
|
}
|
|
327
383
|
return result;
|
package/dist/index.js
CHANGED
|
@@ -214,41 +214,40 @@ function spectralRadius(matrix) {
|
|
|
214
214
|
const n = matrix.length;
|
|
215
215
|
if (n === 0) return 0;
|
|
216
216
|
let v = Array(n).fill(1 / Math.sqrt(n));
|
|
217
|
-
|
|
217
|
+
const tolerance = 1e-6;
|
|
218
|
+
const maxIterations = 100;
|
|
219
|
+
for (let iter = 0; iter < maxIterations; iter++) {
|
|
218
220
|
const newV = Array(n).fill(0);
|
|
219
221
|
for (let i = 0; i < n; i++) {
|
|
220
|
-
const row = matrix[i];
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const vec = v[j];
|
|
225
|
-
if (cell !== void 0 && vec !== void 0) {
|
|
226
|
-
newV[i] += cell * vec;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
222
|
+
const row = matrix[i] ?? [];
|
|
223
|
+
for (let j = 0; j < n; j++) {
|
|
224
|
+
const cell = row[j] ?? 0;
|
|
225
|
+
newV[i] += cell * v[j];
|
|
229
226
|
}
|
|
230
227
|
}
|
|
231
228
|
const norm = Math.sqrt(newV.reduce((sum, val) => sum + val * val, 0));
|
|
232
229
|
if (norm === 0) return 0;
|
|
233
|
-
|
|
230
|
+
const normalizedV = newV.map((val) => val / norm);
|
|
231
|
+
let converged = true;
|
|
232
|
+
for (let i = 0; i < n; i++) {
|
|
233
|
+
const a = normalizedV[i];
|
|
234
|
+
const b = v[i];
|
|
235
|
+
if (a !== void 0 && b !== void 0 && Math.abs(a - b) > tolerance) {
|
|
236
|
+
converged = false;
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (converged) break;
|
|
241
|
+
v = normalizedV;
|
|
234
242
|
}
|
|
235
243
|
let eigenvalue = 0;
|
|
236
244
|
for (let i = 0; i < n; i++) {
|
|
245
|
+
const row = matrix[i] ?? [];
|
|
237
246
|
let sum = 0;
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
for (let j = 0; j < n; j++) {
|
|
241
|
-
const cell = row[j];
|
|
242
|
-
const vec = v[j];
|
|
243
|
-
if (cell !== void 0 && vec !== void 0) {
|
|
244
|
-
sum += cell * vec;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
const vecI = v[i];
|
|
249
|
-
if (vecI !== void 0) {
|
|
250
|
-
eigenvalue += sum * vecI;
|
|
247
|
+
for (let j = 0; j < n; j++) {
|
|
248
|
+
sum += (row[j] ?? 0) * v[j];
|
|
251
249
|
}
|
|
250
|
+
eigenvalue += sum * v[i];
|
|
252
251
|
}
|
|
253
252
|
return Math.abs(eigenvalue);
|
|
254
253
|
}
|
|
@@ -268,33 +267,90 @@ function analyze(pattern, config = {}) {
|
|
|
268
267
|
}
|
|
269
268
|
|
|
270
269
|
// src/utils/logger.ts
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
270
|
+
import { stdout } from "process";
|
|
271
|
+
var ESC = "\x1B[";
|
|
272
|
+
var Formatter = class _Formatter {
|
|
273
|
+
parts = "";
|
|
274
|
+
text;
|
|
275
|
+
constructor(text) {
|
|
276
|
+
this.text = text;
|
|
277
|
+
}
|
|
278
|
+
code(code) {
|
|
279
|
+
this.parts += `${ESC}${code}m`;
|
|
280
|
+
return this;
|
|
281
|
+
}
|
|
282
|
+
static create(text) {
|
|
283
|
+
return new _Formatter(text);
|
|
284
|
+
}
|
|
285
|
+
bold() {
|
|
286
|
+
return this.code("1");
|
|
287
|
+
}
|
|
288
|
+
white() {
|
|
289
|
+
return this.code("97");
|
|
290
|
+
}
|
|
291
|
+
darkGray() {
|
|
292
|
+
return this.code("90");
|
|
293
|
+
}
|
|
294
|
+
red() {
|
|
295
|
+
return this.code("38;2;255;85;85");
|
|
296
|
+
}
|
|
297
|
+
pastelRedBg() {
|
|
298
|
+
return this.code("48;2;255;85;85");
|
|
299
|
+
}
|
|
300
|
+
toString() {
|
|
301
|
+
return `${this.parts}${this.text}${ESC}0m`;
|
|
302
|
+
}
|
|
303
|
+
[Symbol.toPrimitive]() {
|
|
304
|
+
return this.toString();
|
|
305
|
+
}
|
|
276
306
|
};
|
|
277
|
-
var
|
|
307
|
+
var fmt = (text) => Formatter.create(text);
|
|
278
308
|
var log = {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
309
|
+
error: (msg, regex, extra) => {
|
|
310
|
+
let firstLine = `${fmt(" RESAFE ").bold().pastelRedBg().white()} ${fmt(msg).white()}`;
|
|
311
|
+
if (regex) {
|
|
312
|
+
firstLine += ` ${fmt("regex").red()}${fmt("=").darkGray()}${fmt(regex).white()}`;
|
|
313
|
+
}
|
|
314
|
+
stdout.write(`${firstLine}
|
|
315
|
+
`);
|
|
316
|
+
if (extra) log.quote(extra);
|
|
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}
|
|
324
|
+
`);
|
|
325
|
+
if (extra) log.quote(extra);
|
|
326
|
+
},
|
|
327
|
+
hint: (msg) => {
|
|
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()}
|
|
334
|
+
`);
|
|
335
|
+
});
|
|
336
|
+
stdout.write("\n");
|
|
337
|
+
}
|
|
282
338
|
};
|
|
283
339
|
|
|
284
340
|
// src/index.ts
|
|
285
341
|
function check(regex, options = {}) {
|
|
286
342
|
const pattern = typeof regex === "string" ? regex : regex.source;
|
|
287
343
|
const result = analyze(pattern, options);
|
|
344
|
+
const radius = Number(result.radius.toFixed(4));
|
|
288
345
|
if (!result.safe && !options.silent) {
|
|
289
|
-
log.error(
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
);
|
|
293
|
-
log.hint("Simplify regex structure to eliminate exponential paths");
|
|
346
|
+
log.error("Unsafe Regex!", `/${pattern}/`, [
|
|
347
|
+
`Spectral radius: ${radius} (threshold: ${options.threshold ?? 1})`,
|
|
348
|
+
"? Consider simplifying quantifiers"
|
|
349
|
+
]);
|
|
294
350
|
}
|
|
295
351
|
if (!result.safe && options.throwErr) {
|
|
296
352
|
throw new Error(
|
|
297
|
-
`
|
|
353
|
+
`Unsafe regex (spectral radius ${radius})`
|
|
298
354
|
);
|
|
299
355
|
}
|
|
300
356
|
return result;
|
package/package.json
CHANGED