Skip to content

Commit f548a44

Browse files
authored
fix(js-x-ray): exclude d.ts from EFA and automatically apply TsSourceParser with .ts extension
* feat: support native Node.js type striping for JS parser * fix(js-x-ray): exclude d.ts from EFA and automatically apply TsSourceParser with .ts extension
1 parent 0fb6c8c commit f548a44

11 files changed

Lines changed: 114 additions & 12 deletions

File tree

.changeset/odd-wolves-read.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@nodesecure/js-x-ray": patch
3+
---
4+
5+
Exclude d.ts from EFA to avoid error and add .ts detection to automatically load TsSourceParser when required

tsconfig.base.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"extends": "@openally/config.typescript/esm-ts-next",
33
"compilerOptions": {
4-
"composite": true
4+
"composite": true,
5+
"types": ["node"]
56
}
67
}

workspaces/js-x-ray/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"scripts": {
2121
"prepublishOnly": "npm run build",
2222
"build": "tsc",
23-
"test-only": "node --test-reporter=spec --test './test/**/*.spec.ts'",
23+
"test-only": "node --test-reporter=spec --test ./test/**/*.spec.ts",
2424
"test": "c8 --all --src ./src -r html npm run test-only",
2525
"bench": "node --expose-gc --experimental-strip-types ./benchmark/index.ts"
2626
},

workspaces/js-x-ray/src/AstAnalyser.ts

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ import path from "node:path";
77
import type { ESTree } from "meriyah";
88

99
// Import Internal Dependencies
10-
import { JsSourceParser, type SourceParser } from "./parsers/JsSourceParser.ts";
10+
import {
11+
JsSourceParser,
12+
type SourceParser
13+
} from "./parsers/JsSourceParser.ts";
14+
import {
15+
TsSourceParser
16+
} from "./parsers/TsSourceParser.ts";
1117
import * as trojan from "./obfuscators/trojan-source.ts";
1218
import {
1319
PipelineRunner,
@@ -254,6 +260,14 @@ export class AstAnalyser {
254260
pathToFile: string | URL,
255261
options: RuntimeOptions = {}
256262
): Promise<ReportOnFile> {
263+
const filePathString = pathToFile instanceof URL ?
264+
pathToFile.href :
265+
pathToFile;
266+
267+
if (filePathString.includes("d.ts")) {
268+
throw new Error("Declaration files are not supported");
269+
}
270+
257271
try {
258272
const {
259273
packageName,
@@ -264,17 +278,20 @@ export class AstAnalyser {
264278
metadata
265279
} = options;
266280

267-
const str = await fs.readFile(pathToFile, "utf-8");
268-
const filePathString = pathToFile instanceof URL ? pathToFile.href : pathToFile;
281+
let customParserToUse = customParser;
282+
if (!customParser && path.extname(filePathString) === ".ts") {
283+
customParserToUse = new TsSourceParser();
284+
}
269285

286+
const str = await fs.readFile(pathToFile, "utf-8");
270287
const isMin = filePathString.includes(".min") || isMinifiedCode(str);
271288
const data = this.analyse(str, {
272289
location: path.dirname(filePathString),
273290
isMinified: isMin,
274291
removeHTMLComments,
275292
initialize,
276293
finalize,
277-
customParser,
294+
customParser: customParserToUse,
278295
metadata,
279296
packageName
280297
});
@@ -306,6 +323,14 @@ export class AstAnalyser {
306323
pathToFile: string | URL,
307324
options: RuntimeOptions = {}
308325
): ReportOnFile {
326+
const filePathString = pathToFile instanceof URL ?
327+
pathToFile.href :
328+
pathToFile;
329+
330+
if (filePathString.includes("d.ts")) {
331+
throw new Error("Declaration files are not supported");
332+
}
333+
309334
try {
310335
const {
311336
packageName,
@@ -316,17 +341,20 @@ export class AstAnalyser {
316341
metadata
317342
} = options;
318343

319-
const str = fsSync.readFileSync(pathToFile, "utf-8");
320-
const filePathString = pathToFile instanceof URL ? pathToFile.href : pathToFile;
344+
let customParserToUse = customParser;
345+
if (!customParser && path.extname(filePathString) === ".ts") {
346+
customParserToUse = new TsSourceParser();
347+
}
321348

349+
const str = fsSync.readFileSync(pathToFile, "utf-8");
322350
const isMin = filePathString.includes(".min") || isMinifiedCode(str);
323351
const data = this.analyse(str, {
324352
location: path.dirname(filePathString),
325353
isMinified: isMin,
326354
removeHTMLComments,
327355
initialize,
328356
finalize,
329-
customParser,
357+
customParser: customParserToUse,
330358
metadata,
331359
packageName
332360
});

workspaces/js-x-ray/src/EntryFilesAnalyser.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ export class EntryFilesAnalyser {
134134
relativeFile: string,
135135
options: RuntimeOptions
136136
) {
137+
// Skip declaration files as they are not meant to be analysed
138+
if (file.includes("d.ts")) {
139+
return;
140+
}
141+
137142
this.dependencies.addVertex({
138143
id: relativeFile,
139144
adjacentTo: [],

workspaces/js-x-ray/src/parsers/TsSourceParser.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
// Import Third-party Dependencies
22
import {
33
parse,
4-
TSESTree,
54
type TSESTreeOptions
65
} from "@typescript-eslint/typescript-estree";
6+
import {
7+
type ESTree
8+
} from "meriyah";
79

810
// CONSTANTS
911
const kTypeScriptParsingOptions: TSESTreeOptions = {
@@ -26,12 +28,17 @@ export class TsSourceParser {
2628
parse(
2729
source: string,
2830
options: TSESTreeOptions = {}
29-
): TSESTree.Program["body"] {
31+
): ESTree.Statement[] {
3032
const { body } = parse(source, {
3133
...kTypeScriptParsingOptions,
3234
...options
3335
});
3436

35-
return body;
37+
/**
38+
* Not pretty but the types are not compatible and we know
39+
* that the body is compatible with ESTree.Statement[]
40+
* since the parser is designed to be compatible with ESTree.
41+
*/
42+
return body as unknown as ESTree.Statement[];
3643
}
3744
}

workspaces/js-x-ray/test/AstAnalyser.spec.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,23 @@ describe("AstAnalyser", () => {
294294
});
295295

296296
describe("analyseFile", () => {
297+
it("should detect typescript extension and use TsSourceParser automatically", async() => {
298+
const result = await new AstAnalyser().analyseFile(
299+
new URL("test.ts", kFixtureURL),
300+
{ packageName: "foobar" }
301+
);
302+
303+
assert.ok(result.ok);
304+
assert.strictEqual(result.warnings.length, 0);
305+
});
306+
307+
it("should throw when providing a typescript declaration file", async() => {
308+
await assert.rejects(() => new AstAnalyser().analyseFile(
309+
new URL("test.d.ts", kFixtureURL),
310+
{ packageName: "foobar" }
311+
), { message: "Declaration files are not supported" });
312+
});
313+
297314
it("remove the packageName from the dependencies list", async() => {
298315
const dependencySet = new DefaultCollectableSet<Dependency>("dependency");
299316
const result = await new AstAnalyser({ collectables: [dependencySet] }).analyseFile(
@@ -535,6 +552,23 @@ describe("AstAnalyser", () => {
535552
});
536553

537554
describe("analyseFileSync", () => {
555+
it("should detect typescript extension and use TsSourceParser automatically", () => {
556+
const result = new AstAnalyser().analyseFileSync(
557+
new URL("test.ts", kFixtureURL),
558+
{ packageName: "foobar" }
559+
);
560+
561+
assert.ok(result.ok);
562+
assert.strictEqual(result.warnings.length, 0);
563+
});
564+
565+
it("should throw when providing a typescript declaration file", () => {
566+
assert.throws(() => new AstAnalyser().analyseFileSync(
567+
new URL("test.d.ts", kFixtureURL),
568+
{ packageName: "foobar" }
569+
), { message: "Declaration files are not supported" });
570+
});
571+
538572
it("remove the packageName from the dependencies list", () => {
539573
const dependencySet = new DefaultCollectableSet<Dependency>("dependency");
540574
const result = new AstAnalyser({ collectables: [dependencySet] }).analyseFileSync(
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export type yoo = string;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
import { foo } from "./entryExport.ts";
2+
import type { yoo } from "./declaration.d.ts";
23
console.log(foo);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
interface Foo {
2+
bar: string;
3+
}
4+
5+
export function test() {
6+
const foo: Foo = { bar: "baz" };
7+
console.log(foo);
8+
}

0 commit comments

Comments
 (0)