Skip to content

Commit

Permalink
Plumb custom functions throughout. (#1784)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrimc62 authored Feb 25, 2020
1 parent 2b9b62b commit 3baf0e6
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { Util } from './util';
*/
export class ExpressionEngine implements ExpressionParserInterface {
/**
* The elegate to lookup function information from the type.
* The delegate to lookup function information from the type.
*/
public readonly EvaluatorLookup: EvaluatorLookup;

Expand Down
10 changes: 6 additions & 4 deletions libraries/botbuilder-lg/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@
"main": "./lib/index.js",
"typings": "./lib/index.d.ts",
"dependencies": {
"antlr4ts": "0.5.0-alpha.1",
"adaptive-expressions": "4.1.6",
"antlr4ts": "0.5.0-alpha.1",
"botbuilder-core": "4.1.6",
"lodash": "^4.17.11",
"uuid": "^3.3.3",
"botbuilder-core": "4.1.6"
"path": "^0.12.7",
"uuid": "^3.3.3"
},
"devDependencies": {
"@types/mocha": "^5.2.5",
"@types/node": "^10.12.18",
"mocha": "^5.2.0",
"nyc": "^11.4.1",
"ts-node": "^4.1.0",
"typescript": "3.5.3"
Expand All @@ -43,4 +45,4 @@
"/lib",
"/src"
]
}
}
2 changes: 1 addition & 1 deletion libraries/botbuilder-lg/src/lgFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export class LGFile {
this.references = references? references : [];
this.content = content? content : '';
this.id = id? id : '';
this.expressionEngine = expressionEngine? expressionEngine : new ExpressionEngine();
this.expressionEngine = expressionEngine || new ExpressionEngine();
this.importResolver = importResolverDelegate;
}

Expand Down
68 changes: 32 additions & 36 deletions libraries/botbuilder-lg/src/lgParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { Diagnostic, DiagnosticSeverity } from './diagnostic';
import { Position } from './position';
import { ParserRuleContext } from 'antlr4ts';
import { Range } from './range';

import { ExpressionEngine } from 'adaptive-expressions';

export declare type ImportResolverDelegate = (source: string, resourceId: string) => { content: string; id: string };

Expand All @@ -37,39 +37,43 @@ export class LGParser {
* parse a file and return LG file.
* @param filePath LG absolute file path..
* @param importResolver resolver to resolve LG import id to template text.
* @param expressionEngine Expression engine for evaluating expressions.
* @returns new lg file.
*/
public static parseFile(filePath: string, importResolver: ImportResolverDelegate): LGFile {
public static parseFile(filePath: string, importResolver?: ImportResolverDelegate, expressionEngine?: ExpressionEngine): LGFile {
const fullPath = LGExtensions.normalizePath(filePath);
const content = fs.readFileSync(fullPath, 'utf-8');

return LGParser.parseText(content, fullPath, importResolver);
return LGParser.parseText(content, fullPath, importResolver, expressionEngine);
}

/**
* Parser to turn lg content into a LGFile.
* @param content ext content contains lg templates.
* @param id id is the identifier of content. If importResolver is null, id must be a full path string.
* @param importResolver resolver to resolve LG import id to template text.
* @param expressionEngine Expression engine for evaluating expressions.
* @returns entity.
*/
public static parseText(content: string, id: string = '', importResolver: ImportResolverDelegate = null): LGFile {
importResolver = importResolver? importResolver : LGParser.defaultFileResolver;
public static parseText(content: string, id: string = '', importResolver?: ImportResolverDelegate, expressionEngine?: ExpressionEngine): LGFile {
importResolver = importResolver ? importResolver : LGParser.defaultFileResolver;
let lgFile = new LGFile();
lgFile.content = content;
lgFile.id = id;
lgFile.importResolver = importResolver;
if (expressionEngine) {
lgFile.expressionEngine = expressionEngine;
}
let diagnostics: Diagnostic[] = [];
try{
try {
const parsedResult = LGParser.antlrParse(content, id);
lgFile.templates = parsedResult.templates;
lgFile.imports = parsedResult.imports;
diagnostics = diagnostics.concat(parsedResult.invalidTemplateErrors);
lgFile.references = this.getReferences(lgFile, importResolver);
const semanticErrors = new StaticChecker(lgFile).check();
diagnostics = diagnostics.concat(semanticErrors);
} catch (err)
{
} catch (err) {
if (err instanceof LGException) {
diagnostics = diagnostics.concat(err.getDiagnostic());
} else {
Expand All @@ -89,8 +93,7 @@ export class LGParser {
/// <param name="lgFile">original LGFile.</param>
/// <returns>new <see cref="LGFile"/> entity.</returns>
public static parseTextWithRef(content: string, lgFile: LGFile): LGFile {
if (!lgFile)
{
if (!lgFile) {
throw Error(`LGFile`);
}

Expand All @@ -100,25 +103,23 @@ export class LGParser {
newLgFile.id = id;
newLgFile.importResolver = lgFile.importResolver;
let diagnostics: Diagnostic[] = [];
try
{
try {
const antlrResult = this.antlrParse(content, id);
const templates = antlrResult.templates;
const imports = antlrResult.imports;
const imports = antlrResult.imports;
const invalidTemplateErrors = antlrResult.invalidTemplateErrors;
newLgFile.templates = templates;
newLgFile.imports = imports;
diagnostics = diagnostics.concat(invalidTemplateErrors);

newLgFile.references = this.getReferences(newLgFile, newLgFile.importResolver)
.concat(lgFile.references)
.concat([ lgFile ]);
.concat([lgFile]);

var semanticErrors = new StaticChecker(newLgFile).check();
diagnostics = diagnostics.concat(semanticErrors);
}
catch (err)
{
catch (err) {
if (err instanceof LGException) {
diagnostics = diagnostics.concat(err.getDiagnostic());
} else {
Expand All @@ -131,27 +132,27 @@ export class LGParser {
return newLgFile;
}

public static defaultFileResolver(sourceId: string, resourceId: string): {content: string; id: string} {
public static defaultFileResolver(sourceId: string, resourceId: string): { content: string; id: string } {
let importPath = LGExtensions.normalizePath(resourceId);
if (!path.isAbsolute(importPath)) {
// get full path for importPath relative to path which is doing the import.
importPath = LGExtensions.normalizePath(path.join(path.dirname(sourceId), importPath));
}
if (!fs.existsSync(importPath) || !fs.statSync(importPath).isFile()) {
throw Error(`Could not find file: ${ importPath }`);
throw Error(`Could not find file: ${importPath}`);
}
const content: string = fs.readFileSync(importPath, 'utf-8');

return { content, id: importPath };
}

private static antlrParse(text: string, id: string = ''): { templates: LGTemplate[]; imports: LGImport[]; invalidTemplateErrors: Diagnostic[]} {
private static antlrParse(text: string, id: string = ''): { templates: LGTemplate[]; imports: LGImport[]; invalidTemplateErrors: Diagnostic[] } {
const fileContext: FileContext = this.getFileContentContext(text, id);
const templates: LGTemplate[] = this.extractLGTemplates(fileContext, text, id);
const imports: LGImport[] = this.extractLGImports(fileContext, id);
const invalidTemplateErrors: Diagnostic[] = this.getInvalidTemplateErrors(fileContext, id);

return { templates, imports, invalidTemplateErrors};
return { templates, imports, invalidTemplateErrors };
}

private static getReferences(file: LGFile, importResolver: ImportResolverDelegate): LGFile[] {
Expand All @@ -162,48 +163,43 @@ export class LGParser {
return Array.from(resourcesFound);
}

private static resolveImportResources(start: LGFile, resourcesFound: Set<LGFile>, importResolver: ImportResolverDelegate): void
{
private static resolveImportResources(start: LGFile, resourcesFound: Set<LGFile>, importResolver: ImportResolverDelegate): void {
var resourceIds = start.imports.map(lg => lg.id);
resourcesFound.add(start);

for (const id of resourceIds)
{
try
{
for (const id of resourceIds) {
try {
const result = importResolver(start.id, id);
const content = result.content;
const path = result.id;
const notExsit = Array.from(resourcesFound).filter(u => u.id === path).length === 0;
if (notExsit)
{
if (notExsit) {
var childResource = LGParser.parseText(content, path, importResolver);
this.resolveImportResources(childResource, resourcesFound, importResolver);
}
}
catch (err)
{
catch (err) {
if (err instanceof LGException) {
throw err;
} else {
throw new LGException(err.message, [ this.buildDiagnostic(err.message, undefined, start.id) ]);
throw new LGException(err.message, [this.buildDiagnostic(err.message, undefined, start.id)]);
}
}
}
}

private static buildDiagnostic(message: string, context: ParserRuleContext = undefined, source: string = undefined): Diagnostic {
message = message === undefined ? '' : message;
const startPosition: Position = context === undefined? new Position(0, 0) : new Position(context.start.line, context.start.charPositionInLine);
const endPosition: Position = context === undefined? new Position(0, 0) : new Position(context.stop.line, context.stop.charPositionInLine + context.stop.text.length);
const startPosition: Position = context === undefined ? new Position(0, 0) : new Position(context.start.line, context.start.charPositionInLine);
const endPosition: Position = context === undefined ? new Position(0, 0) : new Position(context.stop.line, context.stop.charPositionInLine + context.stop.text.length);
return new Diagnostic(new Range(startPosition, endPosition), message, DiagnosticSeverity.Error, source);
}

private static getInvalidTemplateErrors(fileContext: FileContext, id: string): Diagnostic[] {
let errorTemplates = [];
if (fileContext !== undefined) {
for (const parag of fileContext.paragraph()) {
const errTem =parag.errorTemplate();
const errTem = parag.errorTemplate();
if (errTem) {
errorTemplates = errorTemplates.concat(errTem);
}
Expand All @@ -212,7 +208,7 @@ export class LGParser {

return errorTemplates.map(u => this.buildDiagnostic("error context.", u, id));
}

private static getFileContentContext(text: string, source: string): FileContext {
if (!text) {
return undefined;
Expand Down
Loading

0 comments on commit 3baf0e6

Please sign in to comment.