JS: Add new SourceType for angular templates

This commit is contained in:
Asger Feldthaus
2020-12-11 14:40:34 +00:00
parent b1d45a6773
commit c08ba1416d
4 changed files with 40 additions and 8 deletions

View File

@@ -14,9 +14,9 @@ import com.semmle.js.ast.SourceLocation;
* Parser for Angular template expressions, based on the JS parser with
* modified handling of the pipe operator.
*/
public class AngularExpressionParser extends Parser {
public AngularExpressionParser(String input, int startPos) {
super(new Options(), input, startPos);
public class AngularExpressionParser extends CustomParser {
public AngularExpressionParser(Options options, String input, int startPos) {
super(options, input, startPos);
}
@Override

View File

@@ -10,6 +10,10 @@ import java.util.LinkedHashSet;
import java.util.Set;
import com.semmle.extractor.html.HtmlPopulator;
import com.semmle.jcorn.AngularExpressionParser;
import com.semmle.jcorn.CustomParser;
import com.semmle.jcorn.Options;
import com.semmle.jcorn.Parser;
import com.semmle.js.parser.JcornWrapper;
import com.semmle.util.data.StringUtil;
import com.semmle.util.exception.UserError;
@@ -78,6 +82,9 @@ public class ExtractorConfig {
/** A CommonJS module that is not also an ES2015 module. */
COMMONJS_MODULE,
/** An Angular template expression. */
ANGULAR_TEMPLATE,
/** Automatically determined source type. */
AUTO;
@@ -86,6 +93,18 @@ public class ExtractorConfig {
return StringUtil.lc(name());
}
/**
* Gets the parser to use for parsing this source type.
*/
public Parser createParser(Options options, String input, int startPos) {
switch (this) {
case ANGULAR_TEMPLATE:
return new AngularExpressionParser(options, input, startPos);
default:
return new CustomParser(options, input, startPos);
}
}
/**
* Returns true if this source is executed directly in the global scope, or false if it has its
* own local scope.

View File

@@ -93,7 +93,7 @@ public class HTMLExtractor implements IExtractor {
String source = attr.getValue();
RowColumnVector valueStart = attr.getValueSegment().getRowColumnVector();
if (JS_ATTRIBUTE.matcher(attr.getName()).matches() || isAngularTemplateAttributeName(attr.getName())) {
if (JS_ATTRIBUTE.matcher(attr.getName()).matches()) {
snippetLoC =
extractSnippet(
TopLevelKind.eventHandler,
@@ -104,6 +104,19 @@ public class HTMLExtractor implements IExtractor {
valueStart.getRow(),
valueStart.getColumn(),
false /* isTypeScript */);
} else if (isAngularTemplateAttributeName(attr.getName())) {
// For an attribute *ngFor="let var of EXPR", start parsing at EXPR
int offset = attr.getName().equals("*ngFor") ? source.indexOf(" of ") + " of ".length() : 0;
snippetLoC =
extractSnippet(
TopLevelKind.eventHandler,
config.withSourceType(SourceType.ANGULAR_TEMPLATE),
scopeManager,
textualExtractor,
source,
valueStart.getRow(),
valueStart.getColumn() + offset,
false /* isTypeScript */);
} else if (source.startsWith("javascript:")) {
source = source.substring(11);
snippetLoC =

View File

@@ -1,6 +1,8 @@
package com.semmle.js.parser;
import com.semmle.jcorn.CustomParser;
import java.util.ArrayList;
import java.util.List;
import com.semmle.jcorn.Options;
import com.semmle.jcorn.SyntaxError;
import com.semmle.jcorn.jsx.JSXOptions;
@@ -10,8 +12,6 @@ import com.semmle.js.ast.Token;
import com.semmle.js.extractor.ExtractorConfig;
import com.semmle.js.extractor.ExtractorConfig.ECMAVersion;
import com.semmle.js.extractor.ExtractorConfig.SourceType;
import java.util.ArrayList;
import java.util.List;
public class JcornWrapper {
/** Parse source code as a program. */
@@ -41,7 +41,7 @@ public class JcornWrapper {
if (config.isTolerateParseErrors())
options.onRecoverableError((err) -> errors.add(mkParseError(err)));
program = new CustomParser(options, source, 0).parse();
program = sourceType.createParser(options, source, 0).parse();
} catch (SyntaxError e) {
errors.add(mkParseError(e));
}