Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 372e1a3

Browse files
committed
support the "type" field on package.json files while extracting
1 parent ec7a657 commit 372e1a3

10 files changed

Lines changed: 161 additions & 80 deletions

File tree

javascript/extractor/src/com/semmle/js/extractor/ScriptExtractor.java

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
package com.semmle.js.extractor;
22

3+
import java.io.BufferedReader;
4+
import java.io.File;
5+
import java.io.FileNotFoundException;
6+
import java.io.FileReader;
7+
import java.io.IOException;
8+
import java.util.Map;
9+
import java.util.HashMap;
10+
11+
import com.google.gson.Gson;
12+
313
import com.semmle.js.extractor.ExtractorConfig.Platform;
414
import com.semmle.js.extractor.ExtractorConfig.SourceType;
515
import com.semmle.js.parser.ParseError;
@@ -14,14 +24,20 @@ public ScriptExtractor(ExtractorConfig config) {
1424
this.config = config;
1525
}
1626

17-
/** True if files with the given extension should always be treated as modules. */
18-
private boolean isAlwaysModule(String extension) {
19-
return extension.equals(".mjs") || extension.equals(".es6") || extension.equals(".es");
27+
/** True if the file specified by `locationManager` should always be treated as a module. */
28+
private boolean isAlwaysModule(LocationManager locationManager, String packageType) {
29+
String extension = locationManager.getSourceFileExtension();
30+
if (extension.equals(".mjs") || extension.equals(".es6") || extension.equals(".es")) {
31+
return true;
32+
}
33+
return "module".equals(packageType) && extension.equals(".js");
2034
}
2135

22-
/** True if files with the given extension should always be treated as CommonJS modules. */
23-
private boolean isAlwaysCommonJSModule(String extension) {
24-
return extension.equals(".cjs");
36+
/** True if the file specified by `locationManager` should always be treated as CommonJS modules. */
37+
private boolean isAlwaysCommonJSModule(LocationManager locationManager, String packageType) {
38+
String extension = locationManager.getSourceFileExtension();
39+
40+
return extension.equals(".cjs") || (extension.equals(".js") && "commonjs".equals(packageType));
2541
}
2642

2743
@Override
@@ -49,13 +65,15 @@ public LoCInfo extract(TextualExtractor textualExtractor) {
4965
locationManager.setStart(2, 1);
5066
}
5167

52-
// Some file extensions are interpreted as modules by default.
68+
String packageType = getPackageType(locationManager.getSourceFile().getParentFile());
69+
70+
// Some files are interpreted as modules by default.
5371
if (config.getSourceType() == SourceType.AUTO) {
54-
if (isAlwaysModule(locationManager.getSourceFileExtension())) {
72+
if (isAlwaysModule(locationManager, packageType)) {
5573
config = config.withSourceType(SourceType.MODULE);
5674
}
57-
if (isAlwaysCommonJSModule(locationManager.getSourceFileExtension())) {
58-
config = config.withSourceType(SourceType.COMMONJS_MODULE);
75+
if (isAlwaysCommonJSModule(locationManager, packageType)) {
76+
config = config.withSourceType(SourceType.COMMONJS_MODULE).withPlatform(Platform.NODE);
5977
}
6078
}
6179

@@ -78,4 +96,44 @@ public LoCInfo extract(TextualExtractor textualExtractor) {
7896

7997
return loc;
8098
}
99+
100+
/**
101+
* A minimal model of `package.json` files that can be used to read the "type" field.
102+
*/
103+
private static class PackageJSON {
104+
String type;
105+
}
106+
107+
// cache for `getPackageType`.
108+
private static final Map<File, String> cache = new HashMap<>();
109+
110+
/**
111+
* Returns the "type" field from the nearest `package.json` file (searching up the file hierarchy).
112+
*/
113+
private String getPackageType(File folder) {
114+
if (folder == null || !folder.isDirectory()) {
115+
return null;
116+
}
117+
if (cache.containsKey(folder)) {
118+
return cache.get(folder);
119+
}
120+
for (final File file : folder.listFiles()) {
121+
if (file.isDirectory()) {
122+
continue;
123+
}
124+
if ("package.json".equals(file.getName())) {
125+
try {
126+
BufferedReader reader = new BufferedReader(new FileReader(file));
127+
String result = new Gson().fromJson(reader, PackageJSON.class).type;
128+
cache.put(folder, result);
129+
return result;
130+
} catch (IOException e) {
131+
return null;
132+
}
133+
}
134+
}
135+
String result = getPackageType(folder.getParentFile());
136+
cache.put(folder, result);
137+
return result;
138+
}
81139
}

javascript/extractor/tests/extensions/output/trap/tst4.cjs.trap

Lines changed: 77 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -60,82 +60,89 @@ toplevels(#20001,0)
6060
#20020=@"loc,{#10000},1,1,2,0"
6161
locations_default(#20020,#10000,1,1,2,0)
6262
hasLocation(#20001,#20020)
63-
#20021=@"module;{#10000},1,1"
64-
scopes(#20021,3)
65-
scopenodes(#20001,#20021)
66-
scopenesting(#20021,#20000)
67-
#20022=@"var;{require};{#20021}"
68-
variables(#20022,"require",#20021)
69-
#20023=@"var;{module};{#20021}"
70-
variables(#20023,"module",#20021)
71-
#20024=@"var;{exports};{#20021}"
72-
variables(#20024,"exports",#20021)
73-
#20025=@"var;{__filename};{#20021}"
74-
variables(#20025,"__filename",#20021)
75-
#20026=@"var;{__dirname};{#20021}"
76-
variables(#20026,"__dirname",#20021)
77-
#20027=@"var;{arguments};{#20021}"
78-
variables(#20027,"arguments",#20021)
63+
#20021=@"var;{global};{#20000}"
64+
variables(#20021,"global",#20000)
65+
#20022=@"var;{process};{#20000}"
66+
variables(#20022,"process",#20000)
67+
#20023=@"var;{console};{#20000}"
68+
variables(#20023,"console",#20000)
69+
#20024=@"var;{Buffer};{#20000}"
70+
variables(#20024,"Buffer",#20000)
71+
#20025=@"module;{#10000},1,1"
72+
scopes(#20025,3)
73+
scopenodes(#20001,#20025)
74+
scopenesting(#20025,#20000)
75+
#20026=@"var;{require};{#20025}"
76+
variables(#20026,"require",#20025)
77+
#20027=@"var;{module};{#20025}"
78+
variables(#20027,"module",#20025)
79+
#20028=@"var;{exports};{#20025}"
80+
variables(#20028,"exports",#20025)
81+
#20029=@"var;{__filename};{#20025}"
82+
variables(#20029,"__filename",#20025)
83+
#20030=@"var;{__dirname};{#20025}"
84+
variables(#20030,"__dirname",#20025)
85+
#20031=@"var;{arguments};{#20025}"
86+
variables(#20031,"arguments",#20025)
7987
isModule(#20001)
80-
#20028=*
81-
stmts(#20028,2,#20001,0,"console ... onJS"");")
82-
hasLocation(#20028,#20003)
83-
stmtContainers(#20028,#20001)
84-
#20029=*
85-
exprs(#20029,13,#20028,0,"console ... monJS"")")
86-
#20030=@"loc,{#10000},1,1,1,29"
87-
locations_default(#20030,#10000,1,1,1,29)
88-
hasLocation(#20029,#20030)
89-
enclosingStmt(#20029,#20028)
90-
exprContainers(#20029,#20001)
91-
#20031=*
92-
exprs(#20031,14,#20029,-1,"console.log")
93-
#20032=@"loc,{#10000},1,1,1,11"
94-
locations_default(#20032,#10000,1,1,1,11)
95-
hasLocation(#20031,#20032)
96-
enclosingStmt(#20031,#20028)
97-
exprContainers(#20031,#20001)
88+
#20032=*
89+
stmts(#20032,2,#20001,0,"console ... onJS"");")
90+
hasLocation(#20032,#20003)
91+
stmtContainers(#20032,#20001)
9892
#20033=*
99-
exprs(#20033,79,#20031,0,"console")
100-
hasLocation(#20033,#20005)
101-
enclosingStmt(#20033,#20028)
93+
exprs(#20033,13,#20032,0,"console ... monJS"")")
94+
#20034=@"loc,{#10000},1,1,1,29"
95+
locations_default(#20034,#10000,1,1,1,29)
96+
hasLocation(#20033,#20034)
97+
enclosingStmt(#20033,#20032)
10298
exprContainers(#20033,#20001)
103-
literals("console","console",#20033)
104-
#20034=@"var;{console};{#20000}"
105-
variables(#20034,"console",#20000)
106-
bind(#20033,#20034)
10799
#20035=*
108-
exprs(#20035,0,#20031,1,"log")
109-
hasLocation(#20035,#20009)
110-
enclosingStmt(#20035,#20028)
100+
exprs(#20035,14,#20033,-1,"console.log")
101+
#20036=@"loc,{#10000},1,1,1,11"
102+
locations_default(#20036,#10000,1,1,1,11)
103+
hasLocation(#20035,#20036)
104+
enclosingStmt(#20035,#20032)
111105
exprContainers(#20035,#20001)
112-
literals("log","log",#20035)
113-
#20036=*
114-
exprs(#20036,4,#20029,0,"""Hello CommonJS""")
115-
hasLocation(#20036,#20013)
116-
enclosingStmt(#20036,#20028)
117-
exprContainers(#20036,#20001)
118-
literals("Hello CommonJS","""Hello CommonJS""",#20036)
119106
#20037=*
120-
regexpterm(#20037,14,#20036,0,"Hello CommonJS")
121-
#20038=@"loc,{#10000},1,14,1,27"
122-
locations_default(#20038,#10000,1,14,1,27)
123-
hasLocation(#20037,#20038)
124-
regexpConstValue(#20037,"Hello CommonJS")
107+
exprs(#20037,79,#20035,0,"console")
108+
hasLocation(#20037,#20005)
109+
enclosingStmt(#20037,#20032)
110+
exprContainers(#20037,#20001)
111+
literals("console","console",#20037)
112+
bind(#20037,#20023)
113+
#20038=*
114+
exprs(#20038,0,#20035,1,"log")
115+
hasLocation(#20038,#20009)
116+
enclosingStmt(#20038,#20032)
117+
exprContainers(#20038,#20001)
118+
literals("log","log",#20038)
125119
#20039=*
126-
entry_cfg_node(#20039,#20001)
127-
#20040=@"loc,{#10000},1,1,1,0"
128-
locations_default(#20040,#10000,1,1,1,0)
129-
hasLocation(#20039,#20040)
130-
#20041=*
131-
exit_cfg_node(#20041,#20001)
132-
hasLocation(#20041,#20019)
133-
successor(#20028,#20033)
134-
successor(#20036,#20029)
135-
successor(#20035,#20031)
136-
successor(#20033,#20035)
137-
successor(#20031,#20036)
138-
successor(#20029,#20041)
139-
successor(#20039,#20028)
120+
exprs(#20039,4,#20033,0,"""Hello CommonJS""")
121+
hasLocation(#20039,#20013)
122+
enclosingStmt(#20039,#20032)
123+
exprContainers(#20039,#20001)
124+
literals("Hello CommonJS","""Hello CommonJS""",#20039)
125+
#20040=*
126+
regexpterm(#20040,14,#20039,0,"Hello CommonJS")
127+
#20041=@"loc,{#10000},1,14,1,27"
128+
locations_default(#20041,#10000,1,14,1,27)
129+
hasLocation(#20040,#20041)
130+
regexpConstValue(#20040,"Hello CommonJS")
131+
#20042=*
132+
entry_cfg_node(#20042,#20001)
133+
#20043=@"loc,{#10000},1,1,1,0"
134+
locations_default(#20043,#10000,1,1,1,0)
135+
hasLocation(#20042,#20043)
136+
#20044=*
137+
exit_cfg_node(#20044,#20001)
138+
hasLocation(#20044,#20019)
139+
successor(#20032,#20037)
140+
successor(#20039,#20033)
141+
successor(#20038,#20035)
142+
successor(#20037,#20038)
143+
successor(#20035,#20039)
144+
successor(#20033,#20044)
145+
successor(#20042,#20032)
146+
isNodejs(#20001)
140147
numlines(#10000,1,1,0)
141148
filetype(#10000,"javascript")
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log(".mjs inside a `type:\"commonjs\" is still a ES2015 module`");
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "commonjs"
3+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log("I'm empty! The containing package.json determines the type.");
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"type": "module"
3+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log(".cjs inside a `type:\"module\" is still a CommonJS module`");
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log();
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log("I'm empty! The containing package.json determines the type.");
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
| commonjs.cjs:1:1:3:16 | <toplevel> | node |
2+
| commonjsPackage/innermjs.mjs:1:1:1:74 | <toplevel> | es2015 |
3+
| commonjsPackage/tst.js:1:1:1:75 | <toplevel> | node |
24
| import.js:1:1:5:2 | <toplevel> | es2015 |
35
| mjs.mjs:1:1:1:32 | <toplevel> | es2015 |
6+
| modulePackage/subdir/innercjs.cjs:1:1:1:74 | <toplevel> | node |
7+
| modulePackage/subdir/subfile.js:1:1:1:14 | <toplevel> | es2015 |
8+
| modulePackage/tst.js:1:1:1:75 | <toplevel> | es2015 |
49
| require.js:1:1:7:1 | <toplevel> | node |
510
| script.js:1:1:1:35 | <toplevel> | non-module |

0 commit comments

Comments
 (0)