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

Fix some sourcemap transpile issues #249

Merged
merged 1 commit into from
Jan 6, 2024
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
6 changes: 3 additions & 3 deletions bsc-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,19 @@
"@types/node": "^14.18.41",
"@typescript-eslint/eslint-plugin": "^5.27.0",
"@typescript-eslint/parser": "^5.27.0",
"cz-conventional-changelog": "^3.3.0",
"brighterscript": "^0.61.3",
"brighterscript": "^0.65.15",
"chai": "^4.2.0",
"chai-subset": "^1.6.0",
"coveralls": "^3.0.0",
"cz-conventional-changelog": "^3.3.0",
"eslint": "^8.16.0",
"eslint-plugin-no-only-tests": "^2.4.0",
"fs-extra": "^10.1.0",
"minimatch": "^3.0.4",
"mocha": "^9.1.3",
"nyc": "^15.1.0",
"source-map-support": "^0.5.13",
"release-it": "^15.10.3",
"source-map-support": "^0.5.13",
"trim-whitespace": "^1.3.3",
"ts-node": "^9.0.0",
"typescript": "^4.9.5"
Expand Down
4 changes: 1 addition & 3 deletions bsc-plugin/src/lib/rooibos/MockUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ import { Range } from 'vscode-languageserver-types';
import type { FileFactory } from './FileFactory';
import undent from 'undent';
import type { RooibosSession } from './RooibosSession';
import { BrsTranspileState } from 'brighterscript/dist/parser/BrsTranspileState';
import { diagnosticErrorProcessingFile } from '../utils/Diagnostics';
import type { TestCase } from './TestCase';
import type { TestSuite } from './TestSuite';
import { getAllDottedGetParts, getRootObjectFromDottedGet, getStringPathFromDottedGet, overrideAstTranspile } from './Utils';
import { getAllDottedGetParts } from './Utils';

export class MockUtil {

Expand Down Expand Up @@ -188,4 +187,3 @@ export class MockUtil {
}

}

26 changes: 13 additions & 13 deletions bsc-plugin/src/lib/rooibos/TestGroup.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import type { AstEditor, CallExpression, DottedGetExpression, Expression } from 'brighterscript';
import { isCallExpression, isCallfuncExpression, isIndexedGetExpression, ArrayLiteralExpression, createInvalidLiteral, createStringLiteral, createToken, isDottedGetExpression, TokenKind, isLiteralExpression, isVariableExpression, isFunctionExpression } from 'brighterscript';
import type { AstEditor, CallExpression, DottedGetExpression } from 'brighterscript';
import { ArrayLiteralExpression, createInvalidLiteral, createStringLiteral, createToken, isDottedGetExpression, TokenKind, isFunctionExpression, Parser } from 'brighterscript';
import * as brighterscript from 'brighterscript';
import { BrsTranspileState } from 'brighterscript/dist/parser/BrsTranspileState';
import { TranspileState } from 'brighterscript/dist/parser/TranspileState';
import { diagnosticErrorProcessingFile } from '../utils/Diagnostics';
import type { RooibosAnnotation } from './Annotation';
import { RawCodeStatement } from './RawCodeStatement';
import type { TestCase } from './TestCase';
import type { TestSuite } from './TestSuite';
import { TestBlock } from './TestSuite';
import { getAllDottedGetParts, getRootObjectFromDottedGet, getStringPathFromDottedGet, overrideAstTranspile, sanitizeBsJsonString } from './Utils';
import undent from 'undent';
import { getAllDottedGetParts, getRootObjectFromDottedGet, getStringPathFromDottedGet, sanitizeBsJsonString } from './Utils';
import type { NamespaceContainer } from './RooibosSession';

export class TestGroup extends TestBlock {
Expand Down Expand Up @@ -59,7 +56,7 @@ export class TestGroup extends TestBlock {
try {
let func = this.testSuite.classStatement.methods.find((m) => m.name.text.toLowerCase() === testCase.funcName.toLowerCase());
func.walk(brighterscript.createVisitor({
ExpressionStatement: (expressionStatement, parent, owner) => {
ExpressionStatement: (expressionStatement, parent, owner, key) => {
let callExpression = expressionStatement.expression as CallExpression;
if (brighterscript.isCallExpression(callExpression) && brighterscript.isDottedGetExpression(callExpression.callee)) {
let dge = callExpression.callee;
Expand All @@ -75,12 +72,15 @@ export class TestGroup extends TestBlock {
if (dge.name.text === 'expectCalled' || dge.name.text === 'expectNotCalled') {
this.modifyModernRooibosExpectCallExpression(callExpression, editor, namespaceLookup);
}
//TODO change this to editor.setProperty(parentObj, parentKey, new SourceNode()) once bsc supports it
overrideAstTranspile(editor, expressionStatement, '\n' + undent`
m.currentAssertLineNumber = ${callExpression.range.start.line}
${callExpression.transpile(transpileState).join('')}
${noEarlyExit ? '' : `if m.currentResult?.isFail = true then m.done() : return ${isSub ? '' : 'invalid'}`}
` + '\n');
if (dge.name.text === 'expectCalled' || dge.name.text === 'expectNotCalled') {
this.modifyModernRooibosExpectCallExpression(callExpression, editor, namespaceLookup);
}
const trailingLine = Parser.parse(`${noEarlyExit ? '' : `if m.currentResult?.isFail = true then m.done() : return ${isSub ? '' : 'invalid'}`}`).ast.statements[0];

editor.arraySplice(owner, key + 1, 0, trailingLine);

const leadingLine = Parser.parse(`m.currentAssertLineNumber = ${callExpression.range.start.line}`).ast.statements[0];
editor.arraySplice(owner, key, 0, leadingLine);
}
}
}
Expand Down
19 changes: 1 addition & 18 deletions bsc-plugin/src/lib/rooibos/Utils.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,6 @@
import type { BrsFile, ClassStatement, Expression, FunctionStatement, Statement, AnnotationExpression, AstEditor } from 'brighterscript';
import type { BrsFile, ClassStatement, Expression, FunctionStatement, AnnotationExpression, AstEditor } from 'brighterscript';
import * as brighterscript from 'brighterscript';
import { diagnosticCorruptTestProduced } from '../utils/Diagnostics';
import { SourceNode } from 'source-map';

export function overrideAstTranspile(editor: AstEditor, node: Expression | Statement, value: string) {
editor.setProperty(node, 'transpile', function transpile(this: Expression | Statement, state) {
//indent every line with the current transpile indent level (except the first line, because that's pre-indented by bsc)
let source = value.replace(/\r?\n/g, (match, newline) => {
return state.newline + state.indent();
});

return [new SourceNode(
this.range.start.line + 1,
this.range.start.character,
state.srcPath,
source
)];
});
}

export function addOverriddenMethod(file: BrsFile, annotation: AnnotationExpression, target: ClassStatement, name: string, source: string, editor: AstEditor): boolean {
let functionSource = `
Expand Down
123 changes: 116 additions & 7 deletions bsc-plugin/src/plugin.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import type { BrsFile, CallExpression, ClassMethodStatement, ClassStatement, ExpressionStatement, FunctionStatement } from 'brighterscript';
import { CallfuncExpression, DiagnosticSeverity, DottedGetExpression, Program, ProgramBuilder, util, standardizePath as s, PrintStatement } from 'brighterscript';
import { CallfuncExpression, DiagnosticSeverity, DottedGetExpression, Position, Program, ProgramBuilder, util, standardizePath as s, PrintStatement } from 'brighterscript';
import { expect } from 'chai';
import { RooibosPlugin } from './plugin';
import * as fsExtra from 'fs-extra';
import * as path from 'path';
import * as trim from 'trim-whitespace';
import undent from 'undent';
import { SourceMapConsumer } from 'source-map';
let tmpPath = s`${process.cwd()}/tmp`;
let _rootDir = s`${tmpPath}/rootDir`;
let _stagingFolderPath = s`${tmpPath}/staging`;
Expand Down Expand Up @@ -363,6 +364,61 @@ describe('RooibosPlugin', () => {
expect(plugin.session.sessionInfo.testSuitesToRun).to.be.empty;
});

it('sanity check for sourcemaps', async () => {
await testSourcemapLocations(`
sub main()
print "hello"
end sub
`, `
sub main()
Rooibos_init("RooibosScene")
print "hello"
end sub'//# sourceMappingURL=./test.spec.bs.map
`, [
// print "h|ello" => print |"hello"
{ dest: [2, 12], src: [2, 26] }
]);
});

it('produces proper sourcemaps', async () => {
await testSourcemapLocations(`
@suite
class ATest
@describe("groupA")
@describe("groupB")
@it("is test1")
function Test_3()
number = 123
m.assertEqual("123", \`alpha-\${number}-beta\`)
m.assertEqual(123, 123)
end function
end class
`, `
function __ATest_builder()
instance = {}
instance.new = sub()
end sub
instance.groupB_is_test1 = function()
number = 123
m.assertEqual("123", ("alpha-" + bslib_toString(number) + "-beta"))
m.assertEqual(123, 123)
end function
return instance
end function
function ATest()
instance = __ATest_builder()
instance.new()
return instance
end function'//# sourceMappingURL=./test.spec.bs.map
`, [
// m.assert|Equal("123", ("alpha-" + bslib_toString(number) + "-beta")) => m.|assertEqual("123", `alpha-${number}-beta`)
{ dest: [6, 16], src: [8, 26] },
// m.assert|Equal(123, 123) => m.|assertEqual(123, 123)
{ dest: [7, 16], src: [9, 26] }

]);
});

it('test full transpile', async () => {
plugin.afterProgramCreate(program);
// program.validate();
Expand Down Expand Up @@ -1576,15 +1632,18 @@ describe('RooibosPlugin', () => {
item = {
id: "item"
}

m.currentAssertLineNumber = 7
m._expectNotCalled(item, "getFunction", item, "item")
if m.currentResult?.isFail = true then m.done() : return invalid


if m.currentResult?.isFail = true then
m.done()
return invalid
end if
m.currentAssertLineNumber = 8
m._expectNotCalled(item, "getFunction", item, "item")
if m.currentResult?.isFail = true then m.done() : return invalid
if m.currentResult?.isFail = true then
m.done()
return invalid
end if
`);

let a = getContents('rooibos/RuntimeConfig.brs');
Expand Down Expand Up @@ -1710,6 +1769,57 @@ describe('RooibosPlugin', () => {
console.log('done');
});
});


/**
* Test that the sourcemaps are generated properly and map each token back to their original location.
*
* Keep in mind, the expectedText is trimmed, so as you're calculating the dest positions, brighterscript will probably omit the leading newline when transpiled,
* so your dest lines might need to be 1 line smaller. Also, brighterscript does not honor source indentation, so your column numbers are probably going to be
* based on the standard brighterscript formatting.
* @param text the text to parse
* @param expectedText the expected output text
* @param expectedLocations an array of zero-based line and column arrays
*/
async function testSourcemapLocations(text: string, expectedText: string, expectedLocations: Array<{ src: [number, number]; dest: [number, number] }>) {
program.options.sourceMap = true;
builder.options.sourceMap = true;
fsExtra.outputFileSync(`${_rootDir}/source/test.spec.bs`, text);
//set the file
program.setFile('source/test.spec.bs', text);

program.validate();
//build the project
await builder.transpile();

const actualContents = getContents('test.spec.brs');
expect(actualContents).to.eql(undent`${expectedText}`);

const map = fsExtra.readFileSync(s`${_stagingFolderPath}/source/test.spec.brs.map`).toString();

//load the source map
await SourceMapConsumer.with(map, null, (consumer) => {
expect(
expectedLocations.map((x) => {
let originalPosition = consumer.originalPositionFor({
//convert 0-based line to source-map 1-based line for the lookup
line: x.dest[0] + 1,
column: x.dest[1],
bias: SourceMapConsumer.GREATEST_LOWER_BOUND
});
return Position.create(
//convert 1-based source-map line to 0-based for the test
originalPosition.line - 1,
originalPosition.column
);
})
).to.eql(
expectedLocations.map(
x => Position.create(x.src[0], x.src[1])
)
);
});
}
});

function getContents(filename: string) {
Expand Down Expand Up @@ -1745,4 +1855,3 @@ function getTestSubContents(trimEveryLine = false) {
function trimLeading(text: string) {
return text.split('\n').map((line) => line.trimStart()).join('\n');
}

2 changes: 2 additions & 0 deletions package-lock.json

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

14 changes: 9 additions & 5 deletions rooibos.code-workspace
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"folders": [
"folders": [
{
"path": "bsc-plugin"
},
Expand All @@ -16,17 +16,21 @@
"settings": {
"jira-plugin.workingProject": "",
"workbench.colorCustomizations": {
"statusBar.background": "#b3b024",
"statusBar.background": "#f1ee2f",
"statusBar.foreground": "#000000",
"statusBar.debuggingBackground": "#f1ee2f",
"statusBar.debuggingForeground": "#000000",
"panelTitle.activeBorder": "#ff0000",
"activityBar.background": "#f1ee2f",
"activityBar.foreground": "#1b1b1a",
"activityBar.activeBackground": "#b3b024",
"titleBar.activeBackground": "#b3b024",
"titleBar.activeForeground": "#F9F9F8"
"titleBar.activeBackground": "#f1ee2f",
"titleBar.activeForeground": "#000000",
"titleBar.inactiveBackground": "#f1ee2f",
"titleBar.inactiveForeground": "#000000"
},
"cSpell.words": [
"Inifnite"
]
}
}
}