UNPKG

@krassowski/jupyterlab_go_to_definition

Version:

Jump to definition of a variable or function in JupyterLab

116 lines (94 loc) 3.61 kB
import { expect } from 'chai'; import { CodeEditor } from '@jupyterlab/codeeditor'; import { CodeMirrorEditor } from '@jupyterlab/codemirror'; import { CodeMirrorTokensProvider } from '../editors/codemirror/tokens'; import { TokenContext } from './analyzer'; import { RAnalyzer } from './r'; describe('RAnalyzer', () => { let analyzer: RAnalyzer; let editor: CodeMirrorEditor; let tokensProvider: CodeMirrorTokensProvider; let model: CodeEditor.Model; let host: HTMLElement; function tokenNeighbourhood( tokenName: string, tokenOccurrence = 1, tokenType = 'variable' ) { let tokens = tokensProvider.getTokens(); let matchedTokens = tokens.filter( token => token.value === tokenName && token.type === tokenType ); let token = matchedTokens[tokenOccurrence - 1]; let tokenId = tokens.indexOf(token); return new TokenContext(token, tokens, tokenId); } beforeEach(() => { host = document.createElement('div'); document.body.appendChild(host); model = new CodeEditor.Model({ mimeType: 'text/x-rsrc' }); editor = new CodeMirrorEditor({ host, model, config: { mode: 'rsrc' } }); tokensProvider = new CodeMirrorTokensProvider(editor); analyzer = new RAnalyzer(tokensProvider); }); afterEach(() => { editor.dispose(); document.body.removeChild(host); }); describe('#isStandaloneAssignment()', () => { it('should recognize assignments', () => { const cases = ['x = 1', 'x <- 1', 'x <<- 1', '1 -> x', '1 ->> x']; let text: string; for (text of cases) { model.value.text = text; expect(analyzer.isStandaloneAssignment(tokenNeighbourhood('x'))).to.be .true; } }); it('should ignore increments', () => { model.value.text = 'x += 1'; expect(analyzer.isStandaloneAssignment(tokenNeighbourhood('x'))).not.to.be .true; }); }); describe('#isForLoop', () => { it('should recognize variables declared inside of loops', () => { model.value.text = 'for (x in 1:10){}'; expect(analyzer.isForLoop(tokenNeighbourhood('x'))).to.be.true; }); }); describe('#isImport', () => { it('should recognize the most common ways to load namespaces', () => { model.value.text = 'library(shiny)\nshiny::p'; expect(analyzer.isImport(tokenNeighbourhood('shiny'))).to.be.true; model.value.text = 'require(dplyr)\ndplyr:filter'; expect(analyzer.isImport(tokenNeighbourhood('dplyr'))).to.be.true; }); it('should work with R "import" package', () => { model.value.text = 'import::here(fun_a, fun_b, .from = "other_resources.R")'; expect(analyzer.isImport(tokenNeighbourhood('fun_a'))).to.be.true; expect(analyzer.isImport(tokenNeighbourhood('fun_b'))).to.be.true; // TODO: import::from }); }); describe('#isCrossFileReference', () => { it('should recognize source', () => { model.value.text = "source('test.R')"; expect(analyzer.isCrossFileReference(tokenNeighbourhood('source'))).to.be .true; model.value.text = 'source("test.R")'; expect(analyzer.isCrossFileReference(tokenNeighbourhood('source'))).to.be .true; }); it('should work with R "import" package', () => { model.value.text = 'import::here(fun_a, fun_b, .from = "other_resources.R")'; expect(analyzer.isCrossFileReference(tokenNeighbourhood('.from'))).to.be .true; expect(analyzer.guessReferencePath(tokenNeighbourhood('.from'))).to.eql([ 'other_resources.R' ]); }); }); });