Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: rokucommunity/brighterscript
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.9.3
Choose a base ref
...
head repository: rokucommunity/brighterscript
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.9.4
Choose a head ref
  • 17 commits
  • 28 files changed
  • 1 contributor

Commits on May 3, 2020

  1. Copy the full SHA
    d91da2c View commit details
  2. Copy the full SHA
    2a86086 View commit details

Commits on May 4, 2020

  1. Copy the full SHA
    911f765 View commit details

Commits on May 5, 2020

  1. Fixed broken tests.

    TwitchBronBron committed May 5, 2020
    Copy the full SHA
    e7b3f6c View commit details
  2. Performance enhancements part 1.

    Removing several findDeep calls.
    TwitchBronBron committed May 5, 2020
    Copy the full SHA
    5299966 View commit details
  3. Copy the full SHA
    aa96045 View commit details
  4. Copy the full SHA
    6a0a8ff View commit details
  5. Copy the full SHA
    9a05640 View commit details
  6. Copy the full SHA
    2bae35e View commit details
  7. Copy the full SHA
    5960c06 View commit details
  8. update changelog.

    TwitchBronBron committed May 5, 2020
    Copy the full SHA
    b024830 View commit details
  9. Copy the full SHA
    03de3a7 View commit details

Commits on May 6, 2020

  1. Copy the full SHA
    f49f8df View commit details
  2. Copy the full SHA
    aa73b17 View commit details
  3. Copy the full SHA
    f5717da View commit details
  4. Copy the full SHA
    fcac1ce View commit details
  5. 0.9.4

    TwitchBronBron committed May 6, 2020
    Copy the full SHA
    bc838e7 View commit details
18 changes: 16 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -6,7 +6,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0



## 0.9.3
## [0.9.4] - 2020-05-05
### Added
- diagnostic for detecting unnecessary script imports when `autoImportComponentScript` is enabled
### Changed
- filter duplicate dignostics from multiple projects. ([#75](https://github.com/rokucommunity/brighterscript/issues/75))
### Fixed
- bug that was flagging namespaced functions with the same name as a stdlib function.
- bug that was not properly transpiling brighterscript script tags in xml components.
- several performance issues introduced in v0.8.2.
- Replace `type="text/brighterscript"` with `type="text/brightscript"` in xml script imports during transpile. ([#73](https://github.com/rokucommunity/brighterscript/issues/73))



## [0.9.3] - 2020-05-04
### Changed
- do not show BRS1013 for standalone files ([#72](https://github.com/rokucommunity/brighterscript/issues/72))
- BS1011 (same name as global function) is no longer shown for local variables that are not of type `function` ([#70](https://github.com/rokucommunity/brighterscript/issues/70))
@@ -15,7 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0



## 0.9.2 - 2020-05-02
## [0.9.2] - 2020-05-02
### Changed
- intellisense anywhere other than next to a dot now includes keywords (#67)

@@ -227,6 +240,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0



[0.9.4]: https://github.com/rokucommunity/brighterscript/compare/v0.9.3...v0.9.4
[0.9.3]: https://github.com/rokucommunity/brighterscript/compare/v0.9.2...v0.9.3
[0.9.2]: https://github.com/rokucommunity/brighterscript/compare/v0.9.1...v0.9.2
[0.9.1]: https://github.com/rokucommunity/brighterscript/compare/v0.9.0...v0.9.1
7 changes: 6 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "brighterscript",
"version": "0.9.3",
"version": "0.9.4",
"description": "A superset of Roku's BrightScript language.",
"scripts": {
"preversion": "npm run build && npm run lint && npm run test",
@@ -32,7 +32,7 @@
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"bin": {
"bsc": "dist/cli.js"
"bsc2": "dist/cli.js"
},
"repository": {
"type": "git",
@@ -105,6 +105,7 @@
"command-line-usage": "^5.0.5",
"cross-platform-clear-console": "^2.3.0",
"debounce-promise": "^3.1.0",
"eventemitter3": "^4.0.0",
"fs-extra": "^7.0.1",
"glob": "^7.1.6",
"jsonc-parser": "^2.1.1",
62 changes: 62 additions & 0 deletions src/DependencyGraph.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { DependencyGraph } from './DependencyGraph';
import * as sinon from 'sinon';
import { expect } from 'chai';

describe('DependencyGraph', () => {
let graph: DependencyGraph;
let onchange;
beforeEach(() => {
onchange = sinon.stub();
graph = new DependencyGraph();
});

it('supports subscribing to item before it exists', () => {
graph.onchange('a', onchange);
graph.addOrReplace('a');
expect(onchange.callCount).to.equal(1);
});

it('supports subscribing to item after it exists', () => {
graph.addOrReplace('a', ['b']);
graph.onchange('a', onchange);
graph.addOrReplace('a', ['c']);
expect(onchange.callCount).to.equal(1);
});

it('does not emit when dependencies did not change', () => {
graph.addOrReplace('a', ['b']);
graph.onchange('a', onchange);
graph.addOrReplace('a', ['b']);
expect(onchange.callCount).to.equal(0);
});

it('notifies grandparent of grandchild changes', () => {
graph.onchange('a', onchange);
graph.addOrReplace('a', ['b']);
expect(onchange.callCount).to.equal(1);
graph.addOrReplace('b', ['c']);
expect(onchange.callCount).to.equal(2);
graph.addOrReplace('c', ['d']);
expect(onchange.callCount).to.equal(3);
graph.addOrReplace('c', ['e']);
expect(onchange.callCount).to.equal(4);
});

it('updates allDependencies list when dependency changes', () => {
graph.addOrReplace('a', ['b']);
graph.addOrReplace('b', ['c']);
expect(graph.nodes['a'].allDependencies.sort()).to.eql(['b', 'c']);
graph.addOrReplace('b', ['d', 'e']);
expect(graph.nodes['a'].allDependencies.sort()).to.eql(['b', 'd', 'e']);
});

describe('remove', () => {
it('notifies parents', () => {
graph.addOrReplace('a', ['b']);
graph.addOrReplace('b', ['c']);
expect(graph.nodes['a'].allDependencies.sort()).to.eql(['b', 'c']);
graph.remove('b');
expect(graph.nodes['a'].allDependencies.sort()).to.eql(['b']);
});
});
});
119 changes: 119 additions & 0 deletions src/DependencyGraph.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { EventEmitter } from 'eventemitter3';
import { util } from './util';
/**
* A graph of files and their dependencies.
* Each file will only contain nodes that they directly reference (i.e. script imports, inheritance, etc)
*/
export class DependencyGraph {
/**
* A dictionary of all unique nodes in the entire graph
*/
public nodes = {} as { [key: string]: Node };

private onchangeEmitter = new EventEmitter();

public addOrReplace(key: string, dependencies?: string[]) {
//sort the dependencies
dependencies = dependencies?.sort() ?? [];

let existingNode = this.nodes[key];

//if the dependencies array hasn't changed
if (existingNode && util.areArraysEqual(dependencies, existingNode.dependencies)) {
//do nothing, the dependencies haven't changed

//create a new dependency node
} else {
let node = new Node(key, dependencies, this);
this.nodes[key] = node;
this.onchangeEmitter.emit(key, node);
}
}

/**
* Remove the item. This will emit an onchange event for all dependent nodes
*/
public remove(key: string) {
delete this.nodes[key];
this.onchangeEmitter.emit(key);
}

/**
* Emit event that this item has changed
*/
public emit(key: string) {
this.onchangeEmitter.emit(key);
}

public onchange(key: string, handler: (key) => void) {
this.onchangeEmitter.on(key, handler);
return () => {
this.onchangeEmitter.off(key, handler);
};
}
}

export class Node {
public constructor(
public key: string,
public dependencies: string[],
public graph: DependencyGraph
) {
if (dependencies.length > 0) {
this.subscriptions = [];
}
for (let dependency of this.dependencies) {
let sub = this.graph.onchange(dependency, (dependency) => {
//notify the graph that we changed since one of our dependencies changed
this.graph.emit(this.key);

//erase our full dependency list so it can be regenerated on next read
this._allDependencies = undefined;
});

this.subscriptions.push(sub);
}
}
private subscriptions: Array<() => void>;

/**
* The full list of dependencies for this node and all descendent nodes
*/
public get allDependencies() {
if (!this._allDependencies) {
this._allDependencies = this.getAllDependencies();
}
return this._allDependencies;
}
private _allDependencies: string[];

/**
* Return the full list of unique dependencies for this node by traversing all descendents
*/
private getAllDependencies() {
let dependencyMap = {};
let dependencyStack = [...this.dependencies];
//keep walking the dependency graph until we run out of unseen dependencies
while (dependencyStack.length > 0) {
let dependency = dependencyStack.pop();

//if this is a new dependency
if (!dependencyMap[dependency]) {
dependencyMap[dependency] = true;

//get the node for this dependency
let node = this.graph.nodes[dependency];
if (node) {
dependencyStack.push(...node.dependencies);
}
}
}
return Object.keys(dependencyMap);
}

public dispose() {
for (let unsubscribe of this.subscriptions ?? []) {
unsubscribe();
}
}
}
10 changes: 10 additions & 0 deletions src/DiagnosticMessages.ts
Original file line number Diff line number Diff line change
@@ -544,6 +544,16 @@ export let DiagnosticMessages = {
message: `Scope function has same name as built-in function and will not be accessible`,
code: 1105,
severity: DiagnosticSeverity.Warning
}),
brighterscriptScriptTagMissingTypeAttribute: () => ({
message: `All BrighterScript script tags must include the type="text/brighterscript" attribute`,
code: 1106,
severity: DiagnosticSeverity.Error
}),
unnecessaryCodebehindScriptImport: () => ({
message: `This import is unnecessary because compiler option 'autoImportComponentScript' is enabled`,
code: 1107,
severity: DiagnosticSeverity.Warning
})
};

4 changes: 2 additions & 2 deletions src/FunctionScope.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { VariableDeclaration } from './interfaces';
import { FunctionExpression as ExpressionFunction } from './parser/Expression';
import { FunctionExpression } from './parser/Expression';

export class FunctionScope {
constructor(
public func: ExpressionFunction
public func: FunctionExpression
) {
}

74 changes: 54 additions & 20 deletions src/LanguageServer.spec.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ import { expect } from 'chai';
import * as fsExtra from 'fs-extra';
import * as glob from 'glob';
import * as path from 'path';
import { DidChangeWatchedFilesParams, FileChangeType, TextDocumentSyncKind } from 'vscode-languageserver';
import { DidChangeWatchedFilesParams, FileChangeType, TextDocumentSyncKind, Range } from 'vscode-languageserver';
import { Deferred } from './deferred';
import { LanguageServer, Workspace } from './LanguageServer';
import { ProgramBuilder } from './ProgramBuilder';
@@ -30,6 +30,25 @@ describe('LanguageServer', () => {

let vfs = {} as { [filePath: string]: string };
let physicalFilePaths = [] as string[];
let connection = {
onInitialize: () => null,
onInitialized: () => null,
onDidChangeConfiguration: () => null,
onDidChangeWatchedFiles: () => null,
onCompletion: () => null,
onCompletionResolve: () => null,
onDefinition: () => null,
onHover: () => null,
listen: () => null,
sendNotification: () => null,
sendDiagnostics: () => null,
workspace: {
getWorkspaceFolders: () => workspaceFolders,
getConfiguration: () => {
return {};
}
}
};

beforeEach(() => {
server = new LanguageServer();
@@ -50,25 +69,6 @@ describe('LanguageServer', () => {

//mock the connection stuff
svr.createConnection = () => {
let connection = {
onInitialize: () => null,
onInitialized: () => null,
onDidChangeConfiguration: () => null,
onDidChangeWatchedFiles: () => null,
onCompletion: () => null,
onCompletionResolve: () => null,
onDefinition: () => null,
onHover: () => null,
listen: () => null,
sendNotification: () => null,
sendDiagnostics: () => null,
workspace: {
getWorkspaceFolders: () => workspaceFolders,
getConfiguration: () => {
return {};
}
}
};
return connection;
};

@@ -149,6 +149,40 @@ describe('LanguageServer', () => {
await p;
//test passed because no exceptions were thrown
});

it('dedupes diagnostics found at same location from multiple projects', async () => {
server.workspaces.push(<any>{
firstRunPromise: Promise.resolve(),
builder: {
getDiagnostics: () => {
return [{
file: {
pathAbsolute: s`${rootDir}/source/main.brs`
},
code: 1000,
range: Range.create(1, 2, 3, 4)
}];
}
}
}, <any>{
firstRunPromise: Promise.resolve(),
builder: {
getDiagnostics: () => {
return [{
file: {
pathAbsolute: s`${rootDir}/source/main.brs`
},
code: 1000,
range: Range.create(1, 2, 3, 4)
}];
}
}
});
svr.connection = connection;
let stub = sinon.stub(svr.connection, 'sendDiagnostics');
await svr.sendDiagnostics();
expect(stub.getCall(0).args?.[0]?.diagnostics).to.be.lengthOf(1);
});
});

describe('createWorkspace', () => {
Loading