Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plumb custom functions throughout. #1784

Merged
merged 1 commit into from
Feb 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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