apdev-js 0.2.0 → 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 +164 -7
- package/dist/index.cjs +160 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +164 -6
- package/package.json +11 -4
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# apdev
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
General-purpose development tools for TypeScript/JavaScript projects - character validation, circular import detection, and more.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
package/dist/cli.js
CHANGED
|
@@ -15,7 +15,7 @@ import { execFileSync } from "child_process";
|
|
|
15
15
|
import { Command } from "commander";
|
|
16
16
|
|
|
17
17
|
// src/check-chars.ts
|
|
18
|
-
import { readFileSync, existsSync } from "fs";
|
|
18
|
+
import { readFileSync, existsSync, readdirSync, statSync } from "fs";
|
|
19
19
|
import { extname, dirname, join, sep } from "path";
|
|
20
20
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
21
21
|
function getCharsetsDir() {
|
|
@@ -259,10 +259,164 @@ function checkFile(filePath, maxProblems = 5, extraRanges, dangerousMap) {
|
|
|
259
259
|
}
|
|
260
260
|
return problems;
|
|
261
261
|
}
|
|
262
|
+
var SKIP_SUFFIXES = /* @__PURE__ */ new Set([
|
|
263
|
+
// Bytecode
|
|
264
|
+
".pyc",
|
|
265
|
+
".pyo",
|
|
266
|
+
// Images
|
|
267
|
+
".png",
|
|
268
|
+
".jpg",
|
|
269
|
+
".jpeg",
|
|
270
|
+
".gif",
|
|
271
|
+
".bmp",
|
|
272
|
+
".ico",
|
|
273
|
+
".svg",
|
|
274
|
+
".webp",
|
|
275
|
+
// Fonts
|
|
276
|
+
".ttf",
|
|
277
|
+
".otf",
|
|
278
|
+
".woff",
|
|
279
|
+
".woff2",
|
|
280
|
+
".eot",
|
|
281
|
+
// Archives
|
|
282
|
+
".zip",
|
|
283
|
+
".tar",
|
|
284
|
+
".gz",
|
|
285
|
+
".bz2",
|
|
286
|
+
".xz",
|
|
287
|
+
".7z",
|
|
288
|
+
// Compiled / binary
|
|
289
|
+
".so",
|
|
290
|
+
".dylib",
|
|
291
|
+
".dll",
|
|
292
|
+
".exe",
|
|
293
|
+
".o",
|
|
294
|
+
".a",
|
|
295
|
+
".whl",
|
|
296
|
+
".egg",
|
|
297
|
+
// Media
|
|
298
|
+
".mp3",
|
|
299
|
+
".mp4",
|
|
300
|
+
".wav",
|
|
301
|
+
".avi",
|
|
302
|
+
".mov",
|
|
303
|
+
".flac",
|
|
304
|
+
".ogg",
|
|
305
|
+
// Documents
|
|
306
|
+
".pdf",
|
|
307
|
+
".doc",
|
|
308
|
+
".docx",
|
|
309
|
+
".xls",
|
|
310
|
+
".xlsx",
|
|
311
|
+
".ppt",
|
|
312
|
+
".pptx",
|
|
313
|
+
// Data
|
|
314
|
+
".db",
|
|
315
|
+
".sqlite",
|
|
316
|
+
".sqlite3",
|
|
317
|
+
".pickle",
|
|
318
|
+
".pkl"
|
|
319
|
+
]);
|
|
320
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
321
|
+
"__pycache__",
|
|
322
|
+
"node_modules",
|
|
323
|
+
".git",
|
|
324
|
+
".venv",
|
|
325
|
+
"venv",
|
|
326
|
+
".tox",
|
|
327
|
+
".mypy_cache",
|
|
328
|
+
".pytest_cache",
|
|
329
|
+
".ruff_cache",
|
|
330
|
+
"dist",
|
|
331
|
+
"build"
|
|
332
|
+
]);
|
|
333
|
+
var DEFAULT_DIRS = ["src", "tests", "examples"];
|
|
334
|
+
var DEFAULT_GLOBS = ["*.md", "*.yml", "*.yaml", "*.json", ".gitignore"];
|
|
335
|
+
function walkDir(directory) {
|
|
336
|
+
const files = [];
|
|
337
|
+
let entries;
|
|
338
|
+
try {
|
|
339
|
+
entries = readdirSync(directory).sort();
|
|
340
|
+
} catch {
|
|
341
|
+
return files;
|
|
342
|
+
}
|
|
343
|
+
for (const name of entries) {
|
|
344
|
+
if (name.startsWith(".")) continue;
|
|
345
|
+
const fullPath = join(directory, name);
|
|
346
|
+
let stat;
|
|
347
|
+
try {
|
|
348
|
+
stat = statSync(fullPath);
|
|
349
|
+
} catch {
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
if (stat.isDirectory()) {
|
|
353
|
+
if (SKIP_DIRS.has(name) || name.endsWith(".egg-info")) continue;
|
|
354
|
+
files.push(...walkDir(fullPath));
|
|
355
|
+
} else if (stat.isFile()) {
|
|
356
|
+
if (SKIP_SUFFIXES.has(extname(name).toLowerCase())) continue;
|
|
357
|
+
files.push(fullPath);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return files;
|
|
361
|
+
}
|
|
362
|
+
function defaultProjectFiles() {
|
|
363
|
+
const cwd = process.cwd();
|
|
364
|
+
const files = [];
|
|
365
|
+
for (const dirname3 of DEFAULT_DIRS) {
|
|
366
|
+
const d = join(cwd, dirname3);
|
|
367
|
+
if (existsSync(d) && statSync(d).isDirectory()) {
|
|
368
|
+
files.push(...walkDir(d));
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
for (const pattern of DEFAULT_GLOBS) {
|
|
372
|
+
if (pattern.startsWith("*.")) {
|
|
373
|
+
const suffix = pattern.slice(1);
|
|
374
|
+
try {
|
|
375
|
+
for (const name of readdirSync(cwd).sort()) {
|
|
376
|
+
if (name.endsWith(suffix) && statSync(join(cwd, name)).isFile()) {
|
|
377
|
+
files.push(join(cwd, name));
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
} catch {
|
|
381
|
+
}
|
|
382
|
+
} else {
|
|
383
|
+
const fullPath = join(cwd, pattern);
|
|
384
|
+
if (existsSync(fullPath) && statSync(fullPath).isFile()) {
|
|
385
|
+
files.push(fullPath);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return files;
|
|
390
|
+
}
|
|
391
|
+
function resolvePaths(paths) {
|
|
392
|
+
if (paths.length === 0) {
|
|
393
|
+
return defaultProjectFiles();
|
|
394
|
+
}
|
|
395
|
+
const result = [];
|
|
396
|
+
for (const p of paths) {
|
|
397
|
+
try {
|
|
398
|
+
if (statSync(p).isDirectory()) {
|
|
399
|
+
result.push(...walkDir(p));
|
|
400
|
+
} else {
|
|
401
|
+
result.push(p);
|
|
402
|
+
}
|
|
403
|
+
} catch {
|
|
404
|
+
result.push(p);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return result;
|
|
408
|
+
}
|
|
262
409
|
function checkPaths(paths, extraRanges, dangerousMap) {
|
|
410
|
+
const resolved = resolvePaths(paths);
|
|
411
|
+
if (resolved.length === 0) {
|
|
412
|
+
console.log("No files to check.");
|
|
413
|
+
return 0;
|
|
414
|
+
}
|
|
263
415
|
let hasError = false;
|
|
264
|
-
|
|
416
|
+
let checked = 0;
|
|
417
|
+
for (const path2 of resolved) {
|
|
265
418
|
const problems = checkFile(path2, 5, extraRanges, dangerousMap);
|
|
419
|
+
checked++;
|
|
266
420
|
if (problems.length > 0) {
|
|
267
421
|
hasError = true;
|
|
268
422
|
console.log(`
|
|
@@ -272,11 +426,14 @@ ${path2} contains illegal characters:`);
|
|
|
272
426
|
}
|
|
273
427
|
}
|
|
274
428
|
}
|
|
429
|
+
if (!hasError) {
|
|
430
|
+
console.log(`All ${checked} files passed.`);
|
|
431
|
+
}
|
|
275
432
|
return hasError ? 1 : 0;
|
|
276
433
|
}
|
|
277
434
|
|
|
278
435
|
// src/check-imports.ts
|
|
279
|
-
import { readFileSync as readFileSync2, readdirSync, statSync } from "fs";
|
|
436
|
+
import { readFileSync as readFileSync2, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
280
437
|
import { join as join2, relative, sep as sep2, extname as extname2, basename } from "path";
|
|
281
438
|
import ts from "typescript";
|
|
282
439
|
var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
@@ -365,13 +522,13 @@ function resolveImports(rawImports, basePackage, currentModule, isPackage) {
|
|
|
365
522
|
function findSourceFiles(dir) {
|
|
366
523
|
const results = [];
|
|
367
524
|
function walk(d) {
|
|
368
|
-
const entries =
|
|
525
|
+
const entries = readdirSync2(d);
|
|
369
526
|
for (const entry of entries) {
|
|
370
527
|
if (entry === "node_modules" || entry === "dist" || entry === ".git") {
|
|
371
528
|
continue;
|
|
372
529
|
}
|
|
373
530
|
const full = join2(d, entry);
|
|
374
|
-
const stat =
|
|
531
|
+
const stat = statSync2(full);
|
|
375
532
|
if (stat.isDirectory()) {
|
|
376
533
|
walk(full);
|
|
377
534
|
} else if (SUPPORTED_EXTENSIONS.has(extname2(entry))) {
|
|
@@ -459,7 +616,7 @@ function findCycles(graph) {
|
|
|
459
616
|
function checkCircularImports(srcDir, basePackage) {
|
|
460
617
|
let stat;
|
|
461
618
|
try {
|
|
462
|
-
stat =
|
|
619
|
+
stat = statSync2(srcDir);
|
|
463
620
|
} catch {
|
|
464
621
|
console.error(`Error: ${srcDir}/ directory not found`);
|
|
465
622
|
return 1;
|
|
@@ -526,7 +683,7 @@ function getReleaseScript() {
|
|
|
526
683
|
function buildProgram() {
|
|
527
684
|
const program2 = new Command();
|
|
528
685
|
program2.name("apdev").description("Shared development tools for TypeScript/JavaScript projects").version(getVersion());
|
|
529
|
-
program2.command("check-chars").description("Validate files contain only allowed characters").argument("
|
|
686
|
+
program2.command("check-chars").description("Validate files contain only allowed characters").argument("[files...]", "Files or directories to check (defaults to src/, tests/, examples/ and config files)").option("--charset <name>", "Extra charset preset (repeatable)", collect, []).option("--charset-file <path>", "Custom charset JSON file (repeatable)", collect, []).action((files, opts) => {
|
|
530
687
|
let charsetNames = opts.charset;
|
|
531
688
|
let charsetFiles = opts.charsetFile;
|
|
532
689
|
if (charsetNames.length === 0 && charsetFiles.length === 0) {
|
package/dist/index.cjs
CHANGED
|
@@ -41,6 +41,7 @@ __export(src_exports, {
|
|
|
41
41
|
loadCharset: () => loadCharset,
|
|
42
42
|
loadConfig: () => loadConfig,
|
|
43
43
|
resolveCharsets: () => resolveCharsets,
|
|
44
|
+
resolvePaths: () => resolvePaths,
|
|
44
45
|
version: () => version
|
|
45
46
|
});
|
|
46
47
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -304,10 +305,164 @@ function checkFile(filePath, maxProblems = 5, extraRanges, dangerousMap) {
|
|
|
304
305
|
}
|
|
305
306
|
return problems;
|
|
306
307
|
}
|
|
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
|
+
}
|
|
307
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
|
+
}
|
|
308
461
|
let hasError = false;
|
|
309
|
-
|
|
462
|
+
let checked = 0;
|
|
463
|
+
for (const path of resolved) {
|
|
310
464
|
const problems = checkFile(path, 5, extraRanges, dangerousMap);
|
|
465
|
+
checked++;
|
|
311
466
|
if (problems.length > 0) {
|
|
312
467
|
hasError = true;
|
|
313
468
|
console.log(`
|
|
@@ -317,6 +472,9 @@ ${path} contains illegal characters:`);
|
|
|
317
472
|
}
|
|
318
473
|
}
|
|
319
474
|
}
|
|
475
|
+
if (!hasError) {
|
|
476
|
+
console.log(`All ${checked} files passed.`);
|
|
477
|
+
}
|
|
320
478
|
return hasError ? 1 : 0;
|
|
321
479
|
}
|
|
322
480
|
|
|
@@ -577,5 +735,6 @@ var version = readVersion();
|
|
|
577
735
|
loadCharset,
|
|
578
736
|
loadConfig,
|
|
579
737
|
resolveCharsets,
|
|
738
|
+
resolvePaths,
|
|
580
739
|
version
|
|
581
740
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -42,6 +42,7 @@ declare function isDangerousChar(c: string): boolean;
|
|
|
42
42
|
* Returns a list of problem descriptions (empty if the file is clean).
|
|
43
43
|
*/
|
|
44
44
|
declare function checkFile(filePath: string, maxProblems?: number, extraRanges?: [number, number][], dangerousMap?: Map<number, string>): string[];
|
|
45
|
+
declare function resolvePaths(paths: string[]): string[];
|
|
45
46
|
/**
|
|
46
47
|
* Check multiple files. Returns 0 if all clean, 1 if any have problems.
|
|
47
48
|
*/
|
|
@@ -75,4 +76,4 @@ declare function loadConfig(projectDir?: string): Record<string, unknown>;
|
|
|
75
76
|
|
|
76
77
|
declare const version: string;
|
|
77
78
|
|
|
78
|
-
export { buildDependencyGraph, checkCircularImports, checkFile, checkPaths, fileToModule, findCycles, isAllowedChar, isDangerousChar, loadCharset, loadConfig, resolveCharsets, version };
|
|
79
|
+
export { buildDependencyGraph, checkCircularImports, checkFile, checkPaths, fileToModule, findCycles, isAllowedChar, isDangerousChar, loadCharset, loadConfig, resolveCharsets, resolvePaths, version };
|
package/dist/index.d.ts
CHANGED
|
@@ -42,6 +42,7 @@ declare function isDangerousChar(c: string): boolean;
|
|
|
42
42
|
* Returns a list of problem descriptions (empty if the file is clean).
|
|
43
43
|
*/
|
|
44
44
|
declare function checkFile(filePath: string, maxProblems?: number, extraRanges?: [number, number][], dangerousMap?: Map<number, string>): string[];
|
|
45
|
+
declare function resolvePaths(paths: string[]): string[];
|
|
45
46
|
/**
|
|
46
47
|
* Check multiple files. Returns 0 if all clean, 1 if any have problems.
|
|
47
48
|
*/
|
|
@@ -75,4 +76,4 @@ declare function loadConfig(projectDir?: string): Record<string, unknown>;
|
|
|
75
76
|
|
|
76
77
|
declare const version: string;
|
|
77
78
|
|
|
78
|
-
export { buildDependencyGraph, checkCircularImports, checkFile, checkPaths, fileToModule, findCycles, isAllowedChar, isDangerousChar, loadCharset, loadConfig, resolveCharsets, version };
|
|
79
|
+
export { buildDependencyGraph, checkCircularImports, checkFile, checkPaths, fileToModule, findCycles, isAllowedChar, isDangerousChar, loadCharset, loadConfig, resolveCharsets, resolvePaths, version };
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ var getDirname = () => path.dirname(getFilename());
|
|
|
6
6
|
var __dirname = /* @__PURE__ */ getDirname();
|
|
7
7
|
|
|
8
8
|
// src/check-chars.ts
|
|
9
|
-
import { readFileSync, existsSync } from "fs";
|
|
9
|
+
import { readFileSync, existsSync, readdirSync, statSync } from "fs";
|
|
10
10
|
import { extname, dirname, join, sep } from "path";
|
|
11
11
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
12
12
|
function getCharsetsDir() {
|
|
@@ -260,10 +260,164 @@ function checkFile(filePath, maxProblems = 5, extraRanges, dangerousMap) {
|
|
|
260
260
|
}
|
|
261
261
|
return problems;
|
|
262
262
|
}
|
|
263
|
+
var SKIP_SUFFIXES = /* @__PURE__ */ new Set([
|
|
264
|
+
// Bytecode
|
|
265
|
+
".pyc",
|
|
266
|
+
".pyo",
|
|
267
|
+
// Images
|
|
268
|
+
".png",
|
|
269
|
+
".jpg",
|
|
270
|
+
".jpeg",
|
|
271
|
+
".gif",
|
|
272
|
+
".bmp",
|
|
273
|
+
".ico",
|
|
274
|
+
".svg",
|
|
275
|
+
".webp",
|
|
276
|
+
// Fonts
|
|
277
|
+
".ttf",
|
|
278
|
+
".otf",
|
|
279
|
+
".woff",
|
|
280
|
+
".woff2",
|
|
281
|
+
".eot",
|
|
282
|
+
// Archives
|
|
283
|
+
".zip",
|
|
284
|
+
".tar",
|
|
285
|
+
".gz",
|
|
286
|
+
".bz2",
|
|
287
|
+
".xz",
|
|
288
|
+
".7z",
|
|
289
|
+
// Compiled / binary
|
|
290
|
+
".so",
|
|
291
|
+
".dylib",
|
|
292
|
+
".dll",
|
|
293
|
+
".exe",
|
|
294
|
+
".o",
|
|
295
|
+
".a",
|
|
296
|
+
".whl",
|
|
297
|
+
".egg",
|
|
298
|
+
// Media
|
|
299
|
+
".mp3",
|
|
300
|
+
".mp4",
|
|
301
|
+
".wav",
|
|
302
|
+
".avi",
|
|
303
|
+
".mov",
|
|
304
|
+
".flac",
|
|
305
|
+
".ogg",
|
|
306
|
+
// Documents
|
|
307
|
+
".pdf",
|
|
308
|
+
".doc",
|
|
309
|
+
".docx",
|
|
310
|
+
".xls",
|
|
311
|
+
".xlsx",
|
|
312
|
+
".ppt",
|
|
313
|
+
".pptx",
|
|
314
|
+
// Data
|
|
315
|
+
".db",
|
|
316
|
+
".sqlite",
|
|
317
|
+
".sqlite3",
|
|
318
|
+
".pickle",
|
|
319
|
+
".pkl"
|
|
320
|
+
]);
|
|
321
|
+
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
322
|
+
"__pycache__",
|
|
323
|
+
"node_modules",
|
|
324
|
+
".git",
|
|
325
|
+
".venv",
|
|
326
|
+
"venv",
|
|
327
|
+
".tox",
|
|
328
|
+
".mypy_cache",
|
|
329
|
+
".pytest_cache",
|
|
330
|
+
".ruff_cache",
|
|
331
|
+
"dist",
|
|
332
|
+
"build"
|
|
333
|
+
]);
|
|
334
|
+
var DEFAULT_DIRS = ["src", "tests", "examples"];
|
|
335
|
+
var DEFAULT_GLOBS = ["*.md", "*.yml", "*.yaml", "*.json", ".gitignore"];
|
|
336
|
+
function walkDir(directory) {
|
|
337
|
+
const files = [];
|
|
338
|
+
let entries;
|
|
339
|
+
try {
|
|
340
|
+
entries = readdirSync(directory).sort();
|
|
341
|
+
} catch {
|
|
342
|
+
return files;
|
|
343
|
+
}
|
|
344
|
+
for (const name of entries) {
|
|
345
|
+
if (name.startsWith(".")) continue;
|
|
346
|
+
const fullPath = join(directory, name);
|
|
347
|
+
let stat;
|
|
348
|
+
try {
|
|
349
|
+
stat = statSync(fullPath);
|
|
350
|
+
} catch {
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
if (stat.isDirectory()) {
|
|
354
|
+
if (SKIP_DIRS.has(name) || name.endsWith(".egg-info")) continue;
|
|
355
|
+
files.push(...walkDir(fullPath));
|
|
356
|
+
} else if (stat.isFile()) {
|
|
357
|
+
if (SKIP_SUFFIXES.has(extname(name).toLowerCase())) continue;
|
|
358
|
+
files.push(fullPath);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return files;
|
|
362
|
+
}
|
|
363
|
+
function defaultProjectFiles() {
|
|
364
|
+
const cwd = process.cwd();
|
|
365
|
+
const files = [];
|
|
366
|
+
for (const dirname3 of DEFAULT_DIRS) {
|
|
367
|
+
const d = join(cwd, dirname3);
|
|
368
|
+
if (existsSync(d) && statSync(d).isDirectory()) {
|
|
369
|
+
files.push(...walkDir(d));
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
for (const pattern of DEFAULT_GLOBS) {
|
|
373
|
+
if (pattern.startsWith("*.")) {
|
|
374
|
+
const suffix = pattern.slice(1);
|
|
375
|
+
try {
|
|
376
|
+
for (const name of readdirSync(cwd).sort()) {
|
|
377
|
+
if (name.endsWith(suffix) && statSync(join(cwd, name)).isFile()) {
|
|
378
|
+
files.push(join(cwd, name));
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
} catch {
|
|
382
|
+
}
|
|
383
|
+
} else {
|
|
384
|
+
const fullPath = join(cwd, pattern);
|
|
385
|
+
if (existsSync(fullPath) && statSync(fullPath).isFile()) {
|
|
386
|
+
files.push(fullPath);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return files;
|
|
391
|
+
}
|
|
392
|
+
function resolvePaths(paths) {
|
|
393
|
+
if (paths.length === 0) {
|
|
394
|
+
return defaultProjectFiles();
|
|
395
|
+
}
|
|
396
|
+
const result = [];
|
|
397
|
+
for (const p of paths) {
|
|
398
|
+
try {
|
|
399
|
+
if (statSync(p).isDirectory()) {
|
|
400
|
+
result.push(...walkDir(p));
|
|
401
|
+
} else {
|
|
402
|
+
result.push(p);
|
|
403
|
+
}
|
|
404
|
+
} catch {
|
|
405
|
+
result.push(p);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return result;
|
|
409
|
+
}
|
|
263
410
|
function checkPaths(paths, extraRanges, dangerousMap) {
|
|
411
|
+
const resolved = resolvePaths(paths);
|
|
412
|
+
if (resolved.length === 0) {
|
|
413
|
+
console.log("No files to check.");
|
|
414
|
+
return 0;
|
|
415
|
+
}
|
|
264
416
|
let hasError = false;
|
|
265
|
-
|
|
417
|
+
let checked = 0;
|
|
418
|
+
for (const path2 of resolved) {
|
|
266
419
|
const problems = checkFile(path2, 5, extraRanges, dangerousMap);
|
|
420
|
+
checked++;
|
|
267
421
|
if (problems.length > 0) {
|
|
268
422
|
hasError = true;
|
|
269
423
|
console.log(`
|
|
@@ -273,11 +427,14 @@ ${path2} contains illegal characters:`);
|
|
|
273
427
|
}
|
|
274
428
|
}
|
|
275
429
|
}
|
|
430
|
+
if (!hasError) {
|
|
431
|
+
console.log(`All ${checked} files passed.`);
|
|
432
|
+
}
|
|
276
433
|
return hasError ? 1 : 0;
|
|
277
434
|
}
|
|
278
435
|
|
|
279
436
|
// src/check-imports.ts
|
|
280
|
-
import { readFileSync as readFileSync2, readdirSync, statSync } from "fs";
|
|
437
|
+
import { readFileSync as readFileSync2, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
281
438
|
import { join as join2, relative, sep as sep2, extname as extname2, basename } from "path";
|
|
282
439
|
import ts from "typescript";
|
|
283
440
|
var SUPPORTED_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
@@ -366,13 +523,13 @@ function resolveImports(rawImports, basePackage, currentModule, isPackage) {
|
|
|
366
523
|
function findSourceFiles(dir) {
|
|
367
524
|
const results = [];
|
|
368
525
|
function walk(d) {
|
|
369
|
-
const entries =
|
|
526
|
+
const entries = readdirSync2(d);
|
|
370
527
|
for (const entry of entries) {
|
|
371
528
|
if (entry === "node_modules" || entry === "dist" || entry === ".git") {
|
|
372
529
|
continue;
|
|
373
530
|
}
|
|
374
531
|
const full = join2(d, entry);
|
|
375
|
-
const stat =
|
|
532
|
+
const stat = statSync2(full);
|
|
376
533
|
if (stat.isDirectory()) {
|
|
377
534
|
walk(full);
|
|
378
535
|
} else if (SUPPORTED_EXTENSIONS.has(extname2(entry))) {
|
|
@@ -460,7 +617,7 @@ function findCycles(graph) {
|
|
|
460
617
|
function checkCircularImports(srcDir, basePackage) {
|
|
461
618
|
let stat;
|
|
462
619
|
try {
|
|
463
|
-
stat =
|
|
620
|
+
stat = statSync2(srcDir);
|
|
464
621
|
} catch {
|
|
465
622
|
console.error(`Error: ${srcDir}/ directory not found`);
|
|
466
623
|
return 1;
|
|
@@ -532,5 +689,6 @@ export {
|
|
|
532
689
|
loadCharset,
|
|
533
690
|
loadConfig,
|
|
534
691
|
resolveCharsets,
|
|
692
|
+
resolvePaths,
|
|
535
693
|
version
|
|
536
694
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apdev-js",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.1",
|
|
4
|
+
"description": "General-purpose development tools for TypeScript/JavaScript projects - character validation, circular import detection, and more",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -31,9 +31,16 @@
|
|
|
31
31
|
},
|
|
32
32
|
"keywords": [
|
|
33
33
|
"development-tools",
|
|
34
|
+
"quality-assurance",
|
|
35
|
+
"linting",
|
|
36
|
+
"static-analysis",
|
|
34
37
|
"character-validation",
|
|
35
38
|
"circular-imports",
|
|
36
|
-
"
|
|
39
|
+
"release-automation",
|
|
40
|
+
"unicode-checker",
|
|
41
|
+
"trojan-source-detection",
|
|
42
|
+
"typescript",
|
|
43
|
+
"javascript"
|
|
37
44
|
],
|
|
38
45
|
"author": "aipartnerup <tercel.yi@gmail.com>",
|
|
39
46
|
"license": "Apache-2.0",
|
|
@@ -63,4 +70,4 @@
|
|
|
63
70
|
"typescript": "^5.7.0",
|
|
64
71
|
"vitest": "^3.0.0"
|
|
65
72
|
}
|
|
66
|
-
}
|
|
73
|
+
}
|