apdev-js 0.1.1 → 0.2.1
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 +1 -1
- package/dist/cli.js +290 -98
- package/dist/index.cjs +269 -79
- package/dist/index.d.cts +42 -4
- package/dist/index.d.ts +42 -4
- package/dist/index.js +278 -92
- package/package.json +23 -7
- package/src/charsets/base.json +44 -0
- package/src/charsets/chinese.json +9 -0
- package/src/charsets/japanese.json +11 -0
- package/src/charsets/korean.json +11 -0
package/dist/index.cjs
CHANGED
|
@@ -37,7 +37,11 @@ __export(src_exports, {
|
|
|
37
37
|
fileToModule: () => fileToModule,
|
|
38
38
|
findCycles: () => findCycles,
|
|
39
39
|
isAllowedChar: () => isAllowedChar,
|
|
40
|
+
isDangerousChar: () => isDangerousChar,
|
|
41
|
+
loadCharset: () => loadCharset,
|
|
40
42
|
loadConfig: () => loadConfig,
|
|
43
|
+
resolveCharsets: () => resolveCharsets,
|
|
44
|
+
resolvePaths: () => resolvePaths,
|
|
41
45
|
version: () => version
|
|
42
46
|
});
|
|
43
47
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -49,80 +53,100 @@ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
|
49
53
|
// src/check-chars.ts
|
|
50
54
|
var import_node_fs = require("fs");
|
|
51
55
|
var import_node_path = require("path");
|
|
52
|
-
var
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
[
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
[
|
|
88
|
-
|
|
89
|
-
]
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
[8204, "ZERO WIDTH NON-JOINER"],
|
|
105
|
-
[8205, "ZERO WIDTH JOINER"],
|
|
106
|
-
[8206, "LEFT-TO-RIGHT MARK"],
|
|
107
|
-
[8207, "RIGHT-TO-LEFT MARK"],
|
|
108
|
-
[8288, "WORD JOINER"]
|
|
109
|
-
]);
|
|
110
|
-
var PYTHON_SUFFIXES = /* @__PURE__ */ new Set([".py"]);
|
|
111
|
-
var JS_SUFFIXES = /* @__PURE__ */ new Set([".js", ".ts", ".tsx", ".jsx", ".mjs", ".cjs"]);
|
|
112
|
-
function isAllowedChar(c) {
|
|
113
|
-
const code = c.codePointAt(0);
|
|
114
|
-
if (code <= 127) {
|
|
115
|
-
return true;
|
|
56
|
+
var import_node_url = require("url");
|
|
57
|
+
function getCharsetsDir() {
|
|
58
|
+
const thisDir = typeof __dirname !== "undefined" ? __dirname : (0, import_node_path.dirname)((0, import_node_url.fileURLToPath)(importMetaUrl));
|
|
59
|
+
const devPath = (0, import_node_path.join)(thisDir, "charsets");
|
|
60
|
+
if ((0, import_node_fs.existsSync)(devPath)) {
|
|
61
|
+
return devPath;
|
|
62
|
+
}
|
|
63
|
+
return (0, import_node_path.join)(thisDir, "..", "src", "charsets");
|
|
64
|
+
}
|
|
65
|
+
function loadCharset(nameOrPath) {
|
|
66
|
+
if (nameOrPath.includes(import_node_path.sep) || nameOrPath.includes("/") || nameOrPath.endsWith(".json")) {
|
|
67
|
+
if (!(0, import_node_fs.existsSync)(nameOrPath)) {
|
|
68
|
+
throw new Error(`Charset file not found: ${nameOrPath}`);
|
|
69
|
+
}
|
|
70
|
+
return JSON.parse((0, import_node_fs.readFileSync)(nameOrPath, "utf-8"));
|
|
71
|
+
}
|
|
72
|
+
const filePath = (0, import_node_path.join)(getCharsetsDir(), `${nameOrPath}.json`);
|
|
73
|
+
if (!(0, import_node_fs.existsSync)(filePath)) {
|
|
74
|
+
throw new Error(`Unknown charset: ${nameOrPath}`);
|
|
75
|
+
}
|
|
76
|
+
return JSON.parse((0, import_node_fs.readFileSync)(filePath, "utf-8"));
|
|
77
|
+
}
|
|
78
|
+
function parseRanges(entries) {
|
|
79
|
+
return entries.map((e) => [parseInt(e.start, 16), parseInt(e.end, 16)]);
|
|
80
|
+
}
|
|
81
|
+
function parseDangerous(entries) {
|
|
82
|
+
const map = /* @__PURE__ */ new Map();
|
|
83
|
+
for (const e of entries) {
|
|
84
|
+
map.set(parseInt(e.code, 16), e.name);
|
|
85
|
+
}
|
|
86
|
+
return map;
|
|
87
|
+
}
|
|
88
|
+
function resolveCharsets(charsetNames, charsetFiles) {
|
|
89
|
+
const base = loadCharset("base");
|
|
90
|
+
const rangesSet = /* @__PURE__ */ new Map();
|
|
91
|
+
const dangerous = parseDangerous(base.dangerous ?? []);
|
|
92
|
+
function addRanges(entries) {
|
|
93
|
+
for (const [s, e] of parseRanges(entries)) {
|
|
94
|
+
rangesSet.set(`${s}-${e}`, [s, e]);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
addRanges(base.emoji_ranges ?? []);
|
|
98
|
+
addRanges(base.extra_ranges ?? []);
|
|
99
|
+
for (const name of charsetNames) {
|
|
100
|
+
const data = loadCharset(name);
|
|
101
|
+
addRanges(data.emoji_ranges ?? []);
|
|
102
|
+
addRanges(data.extra_ranges ?? []);
|
|
103
|
+
if (data.dangerous) {
|
|
104
|
+
for (const [code, dname] of parseDangerous(data.dangerous)) {
|
|
105
|
+
dangerous.set(code, dname);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
116
108
|
}
|
|
117
|
-
for (const
|
|
118
|
-
|
|
119
|
-
|
|
109
|
+
for (const path of charsetFiles) {
|
|
110
|
+
const data = loadCharset(path);
|
|
111
|
+
addRanges(data.emoji_ranges ?? []);
|
|
112
|
+
addRanges(data.extra_ranges ?? []);
|
|
113
|
+
if (data.dangerous) {
|
|
114
|
+
for (const [code, dname] of parseDangerous(data.dangerous)) {
|
|
115
|
+
dangerous.set(code, dname);
|
|
116
|
+
}
|
|
120
117
|
}
|
|
121
118
|
}
|
|
119
|
+
const ranges = [...rangesSet.values()].sort((a, b) => a[0] - b[0]);
|
|
120
|
+
return { ranges, dangerous };
|
|
121
|
+
}
|
|
122
|
+
var PYTHON_SUFFIXES = /* @__PURE__ */ new Set([".py"]);
|
|
123
|
+
var JS_SUFFIXES = /* @__PURE__ */ new Set([".js", ".ts", ".tsx", ".jsx", ".mjs", ".cjs"]);
|
|
124
|
+
function isInRanges(code, ranges) {
|
|
125
|
+
if (code <= 127) return true;
|
|
126
|
+
for (const [start, end] of ranges) {
|
|
127
|
+
if (code >= start && code <= end) return true;
|
|
128
|
+
}
|
|
122
129
|
return false;
|
|
123
130
|
}
|
|
131
|
+
var _baseRanges = null;
|
|
132
|
+
var _baseDangerous = null;
|
|
133
|
+
function getBaseDefaults() {
|
|
134
|
+
if (!_baseRanges || !_baseDangerous) {
|
|
135
|
+
const defaults = resolveCharsets([], []);
|
|
136
|
+
_baseRanges = defaults.ranges;
|
|
137
|
+
_baseDangerous = defaults.dangerous;
|
|
138
|
+
}
|
|
139
|
+
return { ranges: _baseRanges, dangerous: _baseDangerous };
|
|
140
|
+
}
|
|
141
|
+
function isAllowedChar(c) {
|
|
142
|
+
const { ranges, dangerous } = getBaseDefaults();
|
|
143
|
+
const code = c.codePointAt(0);
|
|
144
|
+
if (dangerous.has(code)) return false;
|
|
145
|
+
return isInRanges(code, ranges);
|
|
146
|
+
}
|
|
124
147
|
function isDangerousChar(c) {
|
|
125
|
-
|
|
148
|
+
const { dangerous } = getBaseDefaults();
|
|
149
|
+
return dangerous.has(c.codePointAt(0));
|
|
126
150
|
}
|
|
127
151
|
function computeCommentMask(content, suffix) {
|
|
128
152
|
if (PYTHON_SUFFIXES.has(suffix)) {
|
|
@@ -241,8 +265,13 @@ function computeCommentMaskJs(content) {
|
|
|
241
265
|
}
|
|
242
266
|
return mask;
|
|
243
267
|
}
|
|
244
|
-
function checkFile(filePath, maxProblems = 5) {
|
|
268
|
+
function checkFile(filePath, maxProblems = 5, extraRanges, dangerousMap) {
|
|
245
269
|
const problems = [];
|
|
270
|
+
if (!extraRanges || !dangerousMap) {
|
|
271
|
+
const defaults = getBaseDefaults();
|
|
272
|
+
extraRanges ??= defaults.ranges;
|
|
273
|
+
dangerousMap ??= defaults.dangerous;
|
|
274
|
+
}
|
|
246
275
|
try {
|
|
247
276
|
const content = (0, import_node_fs.readFileSync)(filePath, "utf-8");
|
|
248
277
|
const suffix = (0, import_node_path.extname)(filePath).toLowerCase();
|
|
@@ -252,15 +281,15 @@ function checkFile(filePath, maxProblems = 5) {
|
|
|
252
281
|
for (const char of content) {
|
|
253
282
|
position++;
|
|
254
283
|
const code = char.codePointAt(0);
|
|
255
|
-
if (
|
|
284
|
+
if (dangerousMap.has(code)) {
|
|
256
285
|
if (!commentMask.has(offset)) {
|
|
257
|
-
const name =
|
|
286
|
+
const name = dangerousMap.get(code);
|
|
258
287
|
const hex = code.toString(16).toUpperCase().padStart(4, "0");
|
|
259
288
|
problems.push(
|
|
260
289
|
`Dangerous character in code at position ${position}: U+${hex} (${name})`
|
|
261
290
|
);
|
|
262
291
|
}
|
|
263
|
-
} else if (!
|
|
292
|
+
} else if (!isInRanges(code, extraRanges)) {
|
|
264
293
|
const hex = code.toString(16).toUpperCase().padStart(4, "0");
|
|
265
294
|
problems.push(
|
|
266
295
|
`Illegal character at position ${position}: ${JSON.stringify(char)} (U+${hex})`
|
|
@@ -271,15 +300,169 @@ function checkFile(filePath, maxProblems = 5) {
|
|
|
271
300
|
}
|
|
272
301
|
offset += char.length;
|
|
273
302
|
}
|
|
274
|
-
} catch {
|
|
275
|
-
problems.push(`Failed to read file: ${filePath}`);
|
|
303
|
+
} catch (e) {
|
|
304
|
+
problems.push(`Failed to read file: ${filePath} (${e})`);
|
|
276
305
|
}
|
|
277
306
|
return problems;
|
|
278
307
|
}
|
|
279
|
-
|
|
308
|
+
var SKIP_SUFFIXES = /* @__PURE__ */ new Set([
|
|
309
|
+
// Bytecode
|
|
310
|
+
".pyc",
|
|
311
|
+
".pyo",
|
|
312
|
+
// Images
|
|
313
|
+
".png",
|
|
314
|
+
".jpg",
|
|
315
|
+
".jpeg",
|
|
316
|
+
".gif",
|
|
317
|
+
".bmp",
|
|
318
|
+
".ico",
|
|
319
|
+
".svg",
|
|
320
|
+
".webp",
|
|
321
|
+
// Fonts
|
|
322
|
+
".ttf",
|
|
323
|
+
".otf",
|
|
324
|
+
".woff",
|
|
325
|
+
".woff2",
|
|
326
|
+
".eot",
|
|
327
|
+
// Archives
|
|
328
|
+
".zip",
|
|
329
|
+
".tar",
|
|
330
|
+
".gz",
|
|
331
|
+
".bz2",
|
|
332
|
+
".xz",
|
|
333
|
+
".7z",
|
|
334
|
+
// Compiled / binary
|
|
335
|
+
".so",
|
|
336
|
+
".dylib",
|
|
337
|
+
".dll",
|
|
338
|
+
".exe",
|
|
339
|
+
".o",
|
|
340
|
+
".a",
|
|
341
|
+
".whl",
|
|
342
|
+
".egg",
|
|
343
|
+
// Media
|
|
344
|
+
".mp3",
|
|
345
|
+
".mp4",
|
|
346
|
+
".wav",
|
|
347
|
+
".avi",
|
|
348
|
+
".mov",
|
|
349
|
+
".flac",
|
|
350
|
+
".ogg",
|
|
351
|
+
// Documents
|
|
352
|
+
".pdf",
|
|
353
|
+
".doc",
|
|
354
|
+
".docx",
|
|
355
|
+
".xls",
|
|
356
|
+
".xlsx",
|
|
357
|
+
".ppt",
|
|
358
|
+
".pptx",
|
|
359
|
+
// Data
|
|
360
|
+
".db",
|
|
361
|
+
".sqlite",
|
|
362
|
+
".sqlite3",
|
|
363
|
+
".pickle",
|
|
364
|
+
".pkl"
|
|
365
|
+
]);
|
|
366
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
367
|
+
"__pycache__",
|
|
368
|
+
"node_modules",
|
|
369
|
+
".git",
|
|
370
|
+
".venv",
|
|
371
|
+
"venv",
|
|
372
|
+
".tox",
|
|
373
|
+
".mypy_cache",
|
|
374
|
+
".pytest_cache",
|
|
375
|
+
".ruff_cache",
|
|
376
|
+
"dist",
|
|
377
|
+
"build"
|
|
378
|
+
]);
|
|
379
|
+
var DEFAULT_DIRS = ["src", "tests", "examples"];
|
|
380
|
+
var DEFAULT_GLOBS = ["*.md", "*.yml", "*.yaml", "*.json", ".gitignore"];
|
|
381
|
+
function walkDir(directory) {
|
|
382
|
+
const files = [];
|
|
383
|
+
let entries;
|
|
384
|
+
try {
|
|
385
|
+
entries = (0, import_node_fs.readdirSync)(directory).sort();
|
|
386
|
+
} catch {
|
|
387
|
+
return files;
|
|
388
|
+
}
|
|
389
|
+
for (const name of entries) {
|
|
390
|
+
if (name.startsWith(".")) continue;
|
|
391
|
+
const fullPath = (0, import_node_path.join)(directory, name);
|
|
392
|
+
let stat;
|
|
393
|
+
try {
|
|
394
|
+
stat = (0, import_node_fs.statSync)(fullPath);
|
|
395
|
+
} catch {
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
if (stat.isDirectory()) {
|
|
399
|
+
if (SKIP_DIRS.has(name) || name.endsWith(".egg-info")) continue;
|
|
400
|
+
files.push(...walkDir(fullPath));
|
|
401
|
+
} else if (stat.isFile()) {
|
|
402
|
+
if (SKIP_SUFFIXES.has((0, import_node_path.extname)(name).toLowerCase())) continue;
|
|
403
|
+
files.push(fullPath);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return files;
|
|
407
|
+
}
|
|
408
|
+
function defaultProjectFiles() {
|
|
409
|
+
const cwd = process.cwd();
|
|
410
|
+
const files = [];
|
|
411
|
+
for (const dirname3 of DEFAULT_DIRS) {
|
|
412
|
+
const d = (0, import_node_path.join)(cwd, dirname3);
|
|
413
|
+
if ((0, import_node_fs.existsSync)(d) && (0, import_node_fs.statSync)(d).isDirectory()) {
|
|
414
|
+
files.push(...walkDir(d));
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
for (const pattern of DEFAULT_GLOBS) {
|
|
418
|
+
if (pattern.startsWith("*.")) {
|
|
419
|
+
const suffix = pattern.slice(1);
|
|
420
|
+
try {
|
|
421
|
+
for (const name of (0, import_node_fs.readdirSync)(cwd).sort()) {
|
|
422
|
+
if (name.endsWith(suffix) && (0, import_node_fs.statSync)((0, import_node_path.join)(cwd, name)).isFile()) {
|
|
423
|
+
files.push((0, import_node_path.join)(cwd, name));
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
} catch {
|
|
427
|
+
}
|
|
428
|
+
} else {
|
|
429
|
+
const fullPath = (0, import_node_path.join)(cwd, pattern);
|
|
430
|
+
if ((0, import_node_fs.existsSync)(fullPath) && (0, import_node_fs.statSync)(fullPath).isFile()) {
|
|
431
|
+
files.push(fullPath);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
return files;
|
|
436
|
+
}
|
|
437
|
+
function resolvePaths(paths) {
|
|
438
|
+
if (paths.length === 0) {
|
|
439
|
+
return defaultProjectFiles();
|
|
440
|
+
}
|
|
441
|
+
const result = [];
|
|
442
|
+
for (const p of paths) {
|
|
443
|
+
try {
|
|
444
|
+
if ((0, import_node_fs.statSync)(p).isDirectory()) {
|
|
445
|
+
result.push(...walkDir(p));
|
|
446
|
+
} else {
|
|
447
|
+
result.push(p);
|
|
448
|
+
}
|
|
449
|
+
} catch {
|
|
450
|
+
result.push(p);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return result;
|
|
454
|
+
}
|
|
455
|
+
function checkPaths(paths, extraRanges, dangerousMap) {
|
|
456
|
+
const resolved = resolvePaths(paths);
|
|
457
|
+
if (resolved.length === 0) {
|
|
458
|
+
console.log("No files to check.");
|
|
459
|
+
return 0;
|
|
460
|
+
}
|
|
280
461
|
let hasError = false;
|
|
281
|
-
|
|
282
|
-
|
|
462
|
+
let checked = 0;
|
|
463
|
+
for (const path of resolved) {
|
|
464
|
+
const problems = checkFile(path, 5, extraRanges, dangerousMap);
|
|
465
|
+
checked++;
|
|
283
466
|
if (problems.length > 0) {
|
|
284
467
|
hasError = true;
|
|
285
468
|
console.log(`
|
|
@@ -289,6 +472,9 @@ ${path} contains illegal characters:`);
|
|
|
289
472
|
}
|
|
290
473
|
}
|
|
291
474
|
}
|
|
475
|
+
if (!hasError) {
|
|
476
|
+
console.log(`All ${checked} files passed.`);
|
|
477
|
+
}
|
|
292
478
|
return hasError ? 1 : 0;
|
|
293
479
|
}
|
|
294
480
|
|
|
@@ -525,9 +711,9 @@ function loadConfig(projectDir) {
|
|
|
525
711
|
// src/index.ts
|
|
526
712
|
var import_node_fs4 = require("fs");
|
|
527
713
|
var import_node_path4 = require("path");
|
|
528
|
-
var
|
|
714
|
+
var import_node_url2 = require("url");
|
|
529
715
|
function readVersion() {
|
|
530
|
-
const thisDir = typeof __dirname !== "undefined" ? __dirname : (0, import_node_path4.dirname)((0,
|
|
716
|
+
const thisDir = typeof __dirname !== "undefined" ? __dirname : (0, import_node_path4.dirname)((0, import_node_url2.fileURLToPath)(importMetaUrl));
|
|
531
717
|
try {
|
|
532
718
|
const pkg = JSON.parse((0, import_node_fs4.readFileSync)((0, import_node_path4.join)(thisDir, "..", "package.json"), "utf-8"));
|
|
533
719
|
return pkg.version ?? "0.0.0";
|
|
@@ -545,6 +731,10 @@ var version = readVersion();
|
|
|
545
731
|
fileToModule,
|
|
546
732
|
findCycles,
|
|
547
733
|
isAllowedChar,
|
|
734
|
+
isDangerousChar,
|
|
735
|
+
loadCharset,
|
|
548
736
|
loadConfig,
|
|
737
|
+
resolveCharsets,
|
|
738
|
+
resolvePaths,
|
|
549
739
|
version
|
|
550
740
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,14 +1,52 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Character validation tool.
|
|
3
|
+
*
|
|
4
|
+
* Checks that files contain only allowed characters: ASCII, common emoji,
|
|
5
|
+
* and standard technical symbols (arrows, box-drawing, math operators, etc.).
|
|
6
|
+
*
|
|
7
|
+
* Additionally flags dangerous invisible/bidi characters in code regions
|
|
8
|
+
* (Trojan Source - CVE-2021-42574) while allowing them in comments.
|
|
9
|
+
*/
|
|
10
|
+
interface RangeEntry {
|
|
11
|
+
start: string;
|
|
12
|
+
end: string;
|
|
13
|
+
name: string;
|
|
14
|
+
}
|
|
15
|
+
interface DangerousEntry {
|
|
16
|
+
code: string;
|
|
17
|
+
name: string;
|
|
18
|
+
}
|
|
19
|
+
interface CharsetData {
|
|
20
|
+
name: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
emoji_ranges?: RangeEntry[];
|
|
23
|
+
extra_ranges?: RangeEntry[];
|
|
24
|
+
dangerous?: DangerousEntry[];
|
|
25
|
+
}
|
|
26
|
+
declare function loadCharset(nameOrPath: string): CharsetData;
|
|
27
|
+
declare function resolveCharsets(charsetNames: string[], charsetFiles: string[]): {
|
|
28
|
+
ranges: [number, number][];
|
|
29
|
+
dangerous: Map<number, string>;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Return true if the character is in the base allowed set.
|
|
33
|
+
*
|
|
34
|
+
* Dangerous codepoints (Trojan Source vectors) are excluded even though
|
|
35
|
+
* they fall within allowed Unicode ranges.
|
|
36
|
+
*/
|
|
2
37
|
declare function isAllowedChar(c: string): boolean;
|
|
38
|
+
/** Return true if the character is a dangerous invisible/bidi codepoint. */
|
|
39
|
+
declare function isDangerousChar(c: string): boolean;
|
|
3
40
|
/**
|
|
4
41
|
* Check a single file for illegal characters.
|
|
5
42
|
* Returns a list of problem descriptions (empty if the file is clean).
|
|
6
43
|
*/
|
|
7
|
-
declare function checkFile(filePath: string, maxProblems?: number): string[];
|
|
44
|
+
declare function checkFile(filePath: string, maxProblems?: number, extraRanges?: [number, number][], dangerousMap?: Map<number, string>): string[];
|
|
45
|
+
declare function resolvePaths(paths: string[]): string[];
|
|
8
46
|
/**
|
|
9
47
|
* Check multiple files. Returns 0 if all clean, 1 if any have problems.
|
|
10
48
|
*/
|
|
11
|
-
declare function checkPaths(paths: string[]): number;
|
|
49
|
+
declare function checkPaths(paths: string[], extraRanges?: [number, number][], dangerousMap?: Map<number, string>): number;
|
|
12
50
|
|
|
13
51
|
/**
|
|
14
52
|
* Circular import detection tool.
|
|
@@ -38,4 +76,4 @@ declare function loadConfig(projectDir?: string): Record<string, unknown>;
|
|
|
38
76
|
|
|
39
77
|
declare const version: string;
|
|
40
78
|
|
|
41
|
-
export { buildDependencyGraph, checkCircularImports, checkFile, checkPaths, fileToModule, findCycles, isAllowedChar, loadConfig, version };
|
|
79
|
+
export { buildDependencyGraph, checkCircularImports, checkFile, checkPaths, fileToModule, findCycles, isAllowedChar, isDangerousChar, loadCharset, loadConfig, resolveCharsets, resolvePaths, version };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,52 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Character validation tool.
|
|
3
|
+
*
|
|
4
|
+
* Checks that files contain only allowed characters: ASCII, common emoji,
|
|
5
|
+
* and standard technical symbols (arrows, box-drawing, math operators, etc.).
|
|
6
|
+
*
|
|
7
|
+
* Additionally flags dangerous invisible/bidi characters in code regions
|
|
8
|
+
* (Trojan Source - CVE-2021-42574) while allowing them in comments.
|
|
9
|
+
*/
|
|
10
|
+
interface RangeEntry {
|
|
11
|
+
start: string;
|
|
12
|
+
end: string;
|
|
13
|
+
name: string;
|
|
14
|
+
}
|
|
15
|
+
interface DangerousEntry {
|
|
16
|
+
code: string;
|
|
17
|
+
name: string;
|
|
18
|
+
}
|
|
19
|
+
interface CharsetData {
|
|
20
|
+
name: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
emoji_ranges?: RangeEntry[];
|
|
23
|
+
extra_ranges?: RangeEntry[];
|
|
24
|
+
dangerous?: DangerousEntry[];
|
|
25
|
+
}
|
|
26
|
+
declare function loadCharset(nameOrPath: string): CharsetData;
|
|
27
|
+
declare function resolveCharsets(charsetNames: string[], charsetFiles: string[]): {
|
|
28
|
+
ranges: [number, number][];
|
|
29
|
+
dangerous: Map<number, string>;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Return true if the character is in the base allowed set.
|
|
33
|
+
*
|
|
34
|
+
* Dangerous codepoints (Trojan Source vectors) are excluded even though
|
|
35
|
+
* they fall within allowed Unicode ranges.
|
|
36
|
+
*/
|
|
2
37
|
declare function isAllowedChar(c: string): boolean;
|
|
38
|
+
/** Return true if the character is a dangerous invisible/bidi codepoint. */
|
|
39
|
+
declare function isDangerousChar(c: string): boolean;
|
|
3
40
|
/**
|
|
4
41
|
* Check a single file for illegal characters.
|
|
5
42
|
* Returns a list of problem descriptions (empty if the file is clean).
|
|
6
43
|
*/
|
|
7
|
-
declare function checkFile(filePath: string, maxProblems?: number): string[];
|
|
44
|
+
declare function checkFile(filePath: string, maxProblems?: number, extraRanges?: [number, number][], dangerousMap?: Map<number, string>): string[];
|
|
45
|
+
declare function resolvePaths(paths: string[]): string[];
|
|
8
46
|
/**
|
|
9
47
|
* Check multiple files. Returns 0 if all clean, 1 if any have problems.
|
|
10
48
|
*/
|
|
11
|
-
declare function checkPaths(paths: string[]): number;
|
|
49
|
+
declare function checkPaths(paths: string[], extraRanges?: [number, number][], dangerousMap?: Map<number, string>): number;
|
|
12
50
|
|
|
13
51
|
/**
|
|
14
52
|
* Circular import detection tool.
|
|
@@ -38,4 +76,4 @@ declare function loadConfig(projectDir?: string): Record<string, unknown>;
|
|
|
38
76
|
|
|
39
77
|
declare const version: string;
|
|
40
78
|
|
|
41
|
-
export { buildDependencyGraph, checkCircularImports, checkFile, checkPaths, fileToModule, findCycles, isAllowedChar, loadConfig, version };
|
|
79
|
+
export { buildDependencyGraph, checkCircularImports, checkFile, checkPaths, fileToModule, findCycles, isAllowedChar, isDangerousChar, loadCharset, loadConfig, resolveCharsets, resolvePaths, version };
|