Skip to content

Commit

Permalink
Convert plugin params to single event object (#824)
Browse files Browse the repository at this point in the history
  • Loading branch information
TwitchBronBron committed Jun 10, 2023
1 parent 3f9311f commit 3386eb8
Show file tree
Hide file tree
Showing 14 changed files with 215 additions and 105 deletions.
3 changes: 2 additions & 1 deletion src/LanguageServer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1072,7 +1072,8 @@ describe('LanguageServer', () => {
//make a plugin that changes string text
server.projects[0].builder.program.plugins.add({
name: 'test-plugin',
beforeProgramTranspile: (program, entries, editor) => {
beforeProgramTranspile: (event) => {
const { program, editor } = event;
const file = program.getFile('source/main.bs');
if (isBrsFile(file)) {
file.ast.walk(createVisitor({
Expand Down
11 changes: 6 additions & 5 deletions src/PluginInterface.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ describe('PluginInterface', () => {
name: 'allows adding a plugin',
beforePublish: beforePublish
};
pluginInterface.emit('beforePublish', undefined, []);
pluginInterface.emit('beforePublish', { builder: undefined, program: undefined, files: [] });
pluginInterface.add(plugin);
pluginInterface.emit('beforePublish', undefined, []);
pluginInterface.emit('beforePublish', { builder: undefined, program: undefined, files: [] });
expect(beforePublish.callCount).to.equal(1);
});

Expand All @@ -39,7 +39,8 @@ describe('PluginInterface', () => {
};
pluginInterface.add(plugin);
pluginInterface.add(plugin);
pluginInterface.emit('beforePublish', undefined, []);
pluginInterface.emit('beforePublish', { builder: undefined, program: undefined, files: [] });

expect(beforePublish.callCount).to.equal(1);
pluginInterface.remove(plugin);
expect(pluginInterface.has(plugin)).to.be.false;
Expand All @@ -52,10 +53,10 @@ describe('PluginInterface', () => {
beforePublish: beforePublish
};
pluginInterface.add(plugin);
pluginInterface.emit('beforePublish', undefined, []);
pluginInterface.emit('beforePublish', { builder: undefined, program: undefined, files: [] });
expect(beforePublish.callCount).to.equal(1);
pluginInterface.remove(plugin);
pluginInterface.emit('beforePublish', undefined, []);
pluginInterface.emit('beforePublish', { builder: undefined, program: undefined, files: [] });
expect(beforePublish.callCount).to.equal(1);
});
});
6 changes: 2 additions & 4 deletions src/Program.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import * as fsExtra from 'fs-extra';
import { DiagnosticMessages } from './DiagnosticMessages';
import type { BrsFile } from './files/BrsFile';
import type { XmlFile } from './files/XmlFile';
import type { TranspileObj } from './Program';
import { Program } from './Program';
import { standardizePath as s, util } from './util';
import { URI } from 'vscode-uri';
Expand All @@ -19,7 +18,6 @@ import { Logger } from './Logger';
import { createVisitor, WalkMode } from './astUtils/visitors';
import { isBrsFile } from './astUtils/reflection';
import type { LiteralExpression } from './parser/Expression';
import type { AstEditor } from './astUtils/AstEditor';
import { tempDir, rootDir, stagingDir } from './testHelpers.spec';

let sinon = sinonImport.createSandbox();
Expand Down Expand Up @@ -1951,11 +1949,11 @@ describe('Program', () => {
//replace all strings with "goodbye world"
program.plugins.add({
name: 'TestPlugin',
beforeProgramTranspile: (program: Program, entries: TranspileObj[], editor: AstEditor) => {
beforeProgramTranspile: (event) => {
file.ast.walk(createVisitor({
LiteralExpression: (literal) => {
literalExpression = literal;
editor.setProperty(literal.token, 'text', '"goodbye world"');
event.editor.setProperty(literal.token, 'text', '"goodbye world"');
}
}), {
walkMode: WalkMode.visitExpressionsRecursive
Expand Down
78 changes: 53 additions & 25 deletions src/Program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Scope } from './Scope';
import { DiagnosticMessages } from './DiagnosticMessages';
import { BrsFile } from './files/BrsFile';
import { XmlFile } from './files/XmlFile';
import type { BsDiagnostic, File, FileReference, FileObj, BscFile, SemanticToken, AfterFileTranspileEvent, FileLink, ProvideHoverEvent, ProvideCompletionsEvent, Hover } from './interfaces';
import type { BsDiagnostic, File, FileReference, FileObj, BscFile, SemanticToken, AfterFileTranspileEvent, FileLink, ProvideHoverEvent, ProvideCompletionsEvent, Hover, BeforeFileParseEvent } from './interfaces';
import { standardizePath as s, util } from './util';
import { XmlScope } from './XmlScope';
import { DiagnosticFilterer } from './DiagnosticFilterer';
Expand Down Expand Up @@ -203,7 +203,10 @@ export class Program {

protected addScope(scope: Scope) {
this.scopes[scope.name] = scope;
this.plugins.emit('afterScopeCreate', scope);
this.plugins.emit('afterScopeCreate', {
program: this,
scope: scope
});
}

/**
Expand Down Expand Up @@ -445,18 +448,22 @@ export class Program {
this.dependencyGraph.addDependency('scope:source', brsFile.dependencyGraphKey);
}

let sourceObj: SourceObj = {
let beforeFileParseEvent: BeforeFileParseEvent = {
program: this,
srcPath: srcPath,
source: fileContents
};
this.plugins.emit('beforeFileParse', sourceObj);
this.plugins.emit('beforeFileParse', beforeFileParseEvent);

this.logger.time(LogLevel.debug, ['parse', chalk.green(srcPath)], () => {
brsFile.parse(sourceObj.source);
brsFile.parse(beforeFileParseEvent.source);
});

//notify plugins that this file has finished parsing
this.plugins.emit('afterFileParse', brsFile);
this.plugins.emit('afterFileParse', {
program: this,
file: brsFile
});

file = brsFile;

Expand All @@ -473,18 +480,22 @@ export class Program {
new XmlFile(srcPath, pkgPath, this)
);

let sourceObj: SourceObj = {
let event: BeforeFileParseEvent = {
program: this,
srcPath: srcPath,
source: fileContents
};
this.plugins.emit('beforeFileParse', sourceObj);
this.plugins.emit('beforeFileParse', event);

this.logger.time(LogLevel.debug, ['parse', chalk.green(srcPath)], () => {
xmlFile.parse(sourceObj.source);
xmlFile.parse(event.source);
});

//notify plugins that this file has finished parsing
this.plugins.emit('afterFileParse', xmlFile);
this.plugins.emit('afterFileParse', {
program: this,
file: xmlFile
});

file = xmlFile;

Expand Down Expand Up @@ -606,17 +617,25 @@ export class Program {

let file = this.getFile(filePath, normalizePath);
if (file) {
this.plugins.emit('beforeFileDispose', file);
const fileDisposeEvent = {
program: this,
file: file
};
this.plugins.emit('beforeFileDispose', fileDisposeEvent);

//if there is a scope named the same as this file's path, remove it (i.e. xml scopes)
let scope = this.scopes[file.pkgPath];
if (scope) {
this.plugins.emit('beforeScopeDispose', scope);
const scopeDisposeEvent = {
program: this,
scope: scope
};
this.plugins.emit('beforeScopeDispose', scopeDisposeEvent);
scope.dispose();
//notify dependencies of this scope that it has been removed
this.dependencyGraph.remove(scope.dependencyGraphKey);
delete this.scopes[file.pkgPath];
this.plugins.emit('afterScopeDispose', scope);
this.plugins.emit('afterScopeDispose', scopeDisposeEvent);
}
//remove the file from the program
this.unassignFile(file);
Expand All @@ -634,7 +653,7 @@ export class Program {
}
//dispose file
file?.dispose();
this.plugins.emit('afterFileDispose', file);
this.plugins.emit('afterFileDispose', fileDisposeEvent);
}
}

Expand All @@ -644,25 +663,26 @@ export class Program {
public validate() {
this.logger.time(LogLevel.log, ['Validating project'], () => {
this.diagnostics = [];
this.plugins.emit('beforeProgramValidate', this);
const programValidateEvent = {
program: this
};
this.plugins.emit('beforeProgramValidate', programValidateEvent);

//validate every file
for (const file of Object.values(this.files)) {
//for every unvalidated file, validate it
if (!file.isValidated) {
this.plugins.emit('beforeFileValidate', {
const validateFileEvent = {
program: this,
file: file
});
};
this.plugins.emit('beforeFileValidate', validateFileEvent);

//emit an event to allow plugins to contribute to the file validation process
this.plugins.emit('onFileValidate', {
program: this,
file: file
});
this.plugins.emit('onFileValidate', validateFileEvent);
file.isValidated = true;

this.plugins.emit('afterFileValidate', file);
this.plugins.emit('afterFileValidate', validateFileEvent);
}
}

Expand All @@ -677,7 +697,7 @@ export class Program {

this.detectDuplicateComponentNames();

this.plugins.emit('afterProgramValidate', this);
this.plugins.emit('afterProgramValidate', programValidateEvent);
});
}

Expand Down Expand Up @@ -1172,7 +1192,11 @@ export class Program {

const astEditor = new AstEditor();

this.plugins.emit('beforeProgramTranspile', this, entries, astEditor);
this.plugins.emit('beforeProgramTranspile', {
program: this,
entries: entries,
editor: astEditor
});
return {
entries: entries,
getOutputPath: getOutputPath,
Expand Down Expand Up @@ -1249,7 +1273,11 @@ export class Program {
}

private afterProgramTranspile(entries: TranspileObj[], astEditor: AstEditor) {
this.plugins.emit('afterProgramTranspile', this, entries, astEditor);
this.plugins.emit('afterProgramTranspile', {
program: this,
entries: entries,
editor: astEditor
});
astEditor.undoAll();
}

Expand Down
28 changes: 21 additions & 7 deletions src/ProgramBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,10 @@ export class ProgramBuilder {
protected createProgram() {
const program = new Program(this.options, undefined, this.plugins);

this.plugins.emit('afterProgramCreate', program);
this.plugins.emit('afterProgramCreate', {
builder: this,
program: program
});
return program;
}

Expand All @@ -161,7 +164,9 @@ export class ProgramBuilder {
this.plugins.add(plugin);
}

this.plugins.emit('beforeProgramCreate', this);
this.plugins.emit('beforeProgramCreate', {
builder: this
});
}

/**
Expand Down Expand Up @@ -417,8 +422,12 @@ export class ProgramBuilder {
filteredFileMap.push(fileEntry);
}
}

this.plugins.emit('beforePrepublish', this, filteredFileMap);
const prepublishEvent = {
builder: this,
program: this.program,
files: filteredFileMap
};
this.plugins.emit('beforePrepublish', prepublishEvent);

await this.logger.time(LogLevel.log, ['Copying to staging directory'], async () => {
//prepublish all non-program-loaded files to staging
Expand All @@ -428,15 +437,20 @@ export class ProgramBuilder {
});
});

this.plugins.emit('afterPrepublish', this, filteredFileMap);
this.plugins.emit('beforePublish', this, fileMap);
this.plugins.emit('afterPrepublish', prepublishEvent);
const publishEvent = {
builder: this,
program: this.program,
files: fileMap
};
this.plugins.emit('beforePublish', publishEvent);

await this.logger.time(LogLevel.log, ['Transpiling'], async () => {
//transpile any brighterscript files
await this.program.transpile(fileMap, options.stagingDir);
});

this.plugins.emit('afterPublish', this, fileMap);
this.plugins.emit('afterPublish', publishEvent);
});
}

Expand Down
12 changes: 7 additions & 5 deletions src/Scope.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1135,20 +1135,22 @@ describe('Scope', () => {
afterScopeValidate: sinon.spy()
});
program.validate();
const scopeNames = program.getScopes().map(x => x.name).filter(x => x !== 'global').sort();
let scopeNames = program.getScopes().map(x => x.name).filter(x => x !== 'global').sort();

const scopes = plugin.beforeScopeValidate.getCalls().map(x => x.args[0].scope);
expect(plugin.beforeScopeValidate.callCount).to.equal(2);
expect(plugin.beforeScopeValidate.calledWith(sourceScope)).to.be.true;
expect(plugin.beforeScopeValidate.calledWith(compScope)).to.be.true;
expect(scopes).to.include(sourceScope);
expect(scopes).to.include(compScope);

expect(plugin.onScopeValidate.callCount).to.equal(2);
expect(plugin.onScopeValidate.getCalls().map(
x => (x.args[0] as OnScopeValidateEvent).scope.name
).sort()).to.eql(scopeNames);

scopeNames = program.getScopes().map(x => x.name).filter(x => x !== 'global').sort();
expect(plugin.afterScopeValidate.callCount).to.equal(2);
expect(plugin.afterScopeValidate.calledWith(sourceScope)).to.be.true;
expect(plugin.afterScopeValidate.calledWith(compScope)).to.be.true;
expect(scopes).to.include(sourceScope);
expect(scopes).to.include(compScope);
});

it('supports parameter types in functions in AA literals defined in other scope', () => {
Expand Down
12 changes: 6 additions & 6 deletions src/Scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -698,19 +698,19 @@ export class Scope {

//get a list of all callables, indexed by their lower case names
let callableContainerMap = util.getCallableContainersByLowerName(callables);
let files = this.getOwnFiles();

//Since statements from files are shared across multiple scopes, we need to link those statements to the current scope
this.linkSymbolTable();
this.program.plugins.emit('beforeScopeValidate', this, files, callableContainerMap);

this.program.plugins.emit('onScopeValidate', {
const scopeValidateEvent = {
program: this.program,
scope: this
});
};
this.program.plugins.emit('beforeScopeValidate', scopeValidateEvent);

this.program.plugins.emit('onScopeValidate', scopeValidateEvent);
this._validate(callableContainerMap);

this.program.plugins.emit('afterScopeValidate', this, files, callableContainerMap);
this.program.plugins.emit('afterScopeValidate', scopeValidateEvent);
//unlink all symbol tables from this scope (so they don't accidentally stick around)
this.unlinkSymbolTable();

Expand Down

0 comments on commit 3386eb8

Please sign in to comment.