editorcontextDummy
filip mertens 2 years ago
parent 3af5c0c737
commit fb42aff834
  1. 6
      apps/remix-ide/src/app.js
  2. 1
      libs/remix-core-plugin/src/index.ts
  3. 503
      libs/remix-core-plugin/src/lib/code-parser.ts
  4. 374
      libs/remix-core-plugin/src/lib/editor-context-listener.ts
  5. 247
      libs/remix-ui/editor/src/lib/providers/completionProvider.ts
  6. 55
      libs/remix-ui/editor/src/lib/providers/hoverProvider.ts
  7. 4
      libs/remix-ui/editor/src/lib/providers/referenceProvider.ts
  8. 4
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
  9. 60
      yarn.lock

@ -13,7 +13,7 @@ import { LandingPage } from './app/ui/landing-page/landing-page'
import { MainPanel } from './app/components/main-panel' import { MainPanel } from './app/components/main-panel'
import { PermissionHandlerPlugin } from './app/plugins/permission-handler-plugin' import { PermissionHandlerPlugin } from './app/plugins/permission-handler-plugin'
import { AstWalker } from '@remix-project/remix-astwalker' import { AstWalker } from '@remix-project/remix-astwalker'
import { LinkLibraries, DeployLibraries, OpenZeppelinProxy } from '@remix-project/core-plugin' import { LinkLibraries, DeployLibraries, OpenZeppelinProxy, CodeParser } from '@remix-project/core-plugin'
import { WalkthroughService } from './walkthroughService' import { WalkthroughService } from './walkthroughService'
@ -201,6 +201,7 @@ class AppComponent {
} }
) )
const contextualListener = new EditorContextListener(new AstWalker()) const contextualListener = new EditorContextListener(new AstWalker())
const codeParser = new CodeParser(new AstWalker())
this.notification = new NotificationPlugin() this.notification = new NotificationPlugin()
@ -225,6 +226,7 @@ class AppComponent {
networkModule, networkModule,
offsetToLineColumnConverter, offsetToLineColumnConverter,
contextualListener, contextualListener,
codeParser,
terminal, terminal,
web3Provider, web3Provider,
compileAndRun, compileAndRun,
@ -350,7 +352,7 @@ class AppComponent {
await this.appManager.activatePlugin(['sidePanel']) // activating host plugin separately await this.appManager.activatePlugin(['sidePanel']) // activating host plugin separately
await this.appManager.activatePlugin(['home']) await this.appManager.activatePlugin(['home'])
await this.appManager.activatePlugin(['settings', 'config']) await this.appManager.activatePlugin(['settings', 'config'])
await this.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'contextualListener', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport', 'gistHandler']) await this.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'contextualListener', 'codeParser', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport', 'gistHandler'])
await this.appManager.activatePlugin(['settings']) await this.appManager.activatePlugin(['settings'])
await this.appManager.activatePlugin(['walkthrough','storage', 'search','compileAndRun']) await this.appManager.activatePlugin(['walkthrough','storage', 'search','compileAndRun'])

@ -8,3 +8,4 @@ export { GistHandler } from './lib/gist-handler'
export * from './types/contract' export * from './types/contract'
export { LinkLibraries, DeployLibraries } from './lib/link-libraries' export { LinkLibraries, DeployLibraries } from './lib/link-libraries'
export { OpenZeppelinProxy } from './lib/openzeppelin-proxy' export { OpenZeppelinProxy } from './lib/openzeppelin-proxy'
export { CodeParser } from './lib/code-parser'

@ -4,26 +4,42 @@ import { sourceMappingDecoder } from '@remix-project/remix-debug'
import { CompilerAbstract } from '@remix-project/remix-solidity' import { CompilerAbstract } from '@remix-project/remix-solidity'
import { Compiler } from '@remix-project/remix-solidity' import { Compiler } from '@remix-project/remix-solidity'
import { AstNode, CompilationError, CompilationResult, CompilationSource, helper } from '@remix-project/remix-solidity-ts'
import { CompilationError, CompilationResult, CompilationSource, helper } from '@remix-project/remix-solidity-ts'
const SolidityParser = (window as any).SolidityParser = (window as any).SolidityParser || [] const SolidityParser = (window as any).SolidityParser = (window as any).SolidityParser || []
const profile = { const profile = {
name: 'codeParser', name: 'codeParser',
methods: ['getBlockName', 'getLastNodeInLine', 'resolveImports', 'parseSolidity', 'getAST', 'nodesWithScope', 'nodesWithName', 'getNodes', 'compile', 'getNodeById', 'getLastCompilationResult', 'positionOfDefinition', 'definitionAtPosition', 'jumpToDefinition', 'referrencesAtPosition', 'nodesAtEditorPosition', 'referencesOf', 'getActiveHighlights', 'gasEstimation', 'declarationOf', 'jumpToPosition'], methods: ['nodesAtPosition', 'getFunctionParamaters', 'getDeclaration', 'getFunctionReturnParameters', 'getVariableDeclaration', 'getNodeDocumentation', 'getNodeLink', 'listAstNodes', 'getBlockAtPosition', 'getLastNodeInLine', 'resolveImports', 'parseSolidity', 'getNodesWithScope', 'getNodesWithName', 'getNodes', 'compile', 'getNodeById', 'getLastCompilationResult', 'positionOfDefinition', 'definitionAtPosition', 'jumpToDefinition', 'referrencesAtPosition', 'referencesOf', 'getActiveHighlights', 'gasEstimation', 'declarationOf'],
events: [], events: [],
version: '0.0.1' version: '0.0.1'
} }
export function isNodeDefinition(node: any) {
return node.nodeType === 'ContractDefinition' ||
node.nodeType === 'FunctionDefinition' ||
node.nodeType === 'ModifierDefinition' ||
node.nodeType === 'VariableDeclaration' ||
node.nodeType === 'StructDefinition' ||
node.nodeType === 'EventDefinition'
}
export class CodeParser extends Plugin { export class CodeParser extends Plugin {
currentFileAST: any // contains the simple parsed AST for the current file currentFileAST: any // contains the simple parsed AST for the current file
compiler: any // used to compile the current file seperately from the main compiler compiler: any // used to compile the current file seperately from the main compiler
onAstFinished: (success: any, data: any, source: any, input: any, version: any) => Promise<void> lastCompilationResult: any
currentFile: any currentFile: any
_index: any
astWalker: any
onAstFinished: (success: any, data: CompilationResult, source: CompilationSource, input: any, version: any) => Promise<void>
constructor() { constructor(astWalker) {
super(profile) super(profile)
this.astWalker = astWalker
this._index = {
Declarations: {},
FlatReferences: {}
}
} }
async onActivation() { async onActivation() {
@ -38,11 +54,82 @@ export class CodeParser extends Plugin {
await this.compile() await this.compile()
}) })
this.on('solidity', 'loadingCompiler', async (url) => {
console.log('loading compiler', url)
this.compiler.loadVersion(true, url)
this.compiler.event.register('compilerLoaded', async () => {
console.log('compiler loaded')
})
})
/**
* - processes compilation results
* - calls the editor to add markers on the errors
* - builds the flat index of nodes
*/
this.onAstFinished = async (success, data: CompilationResult, source: CompilationSource, input: any, version) => {
console.log('compile success', success, data, this)
this.call('editor', 'clearAnnotations')
let noFatalErrors = true // ie warnings are ok
const checkIfFatalError = (error: CompilationError) => {
// Ignore warnings and the 'Deferred import' error as those are generated by us as a workaround
const isValidError = (error.message && error.message.includes('Deferred import')) ? false : error.severity !== 'warning'
if (isValidError) {
console.log(error)
noFatalErrors = false
}
}
const result = new CompilerAbstract('soljson', data, source, input)
if (data.error) checkIfFatalError(data.error)
if (data.errors) data.errors.forEach((err) => checkIfFatalError(err))
const allErrors = []
if (data.errors) {
for (const error of data.errors) {
console.log('ERROR POS', error)
let pos = helper.getPositionDetails(error.formattedMessage)
console.log('ERROR POS', pos)
const sources = result.getSourceCode().sources
const source = sources[pos.file]
const lineColumn = await this.call('offsetToLineColumnConverter', 'offsetToLineColumn',
{
start: error.sourceLocation.start,
length: error.sourceLocation.end - error.sourceLocation.start
},
0,
sources,
null)
console.log('lineColumn', lineColumn)
allErrors.push({ error, lineColumn })
}
await this.call('editor', 'addErrorMarker', allErrors)
} else {
await this.call('editor', 'clearErrorMarkers', result.getSourceCode().sources)
}
if (!data.sources) return
if (data.sources && Object.keys(data.sources).length === 0) return
this.lastCompilationResult = new CompilerAbstract('soljson', data, source, input)
this._index = {
Declarations: {},
FlatReferences: {}
}
this._buildIndex(data, source)
this.emit('astFinished')
}
this.compiler = new Compiler((url, cb) => this.call('contentImport', 'resolveAndSave', url, undefined, false).then((result) => cb(null, result)).catch((error) => cb(error.message))) this.compiler = new Compiler((url, cb) => this.call('contentImport', 'resolveAndSave', url, undefined, false).then((result) => cb(null, result)).catch((error) => cb(error.message)))
this.compiler.event.register('astFinished', this.onAstFinished)
} }
// COMPILER // COMPILER
/**
*
* @returns
*/
async compile() { async compile() {
try { try {
const state = await this.call('solidity', 'getCompilerState') const state = await this.call('solidity', 'getCompilerState')
@ -52,6 +139,7 @@ export class CodeParser extends Plugin {
this.compiler.set('runs', state.runs) this.compiler.set('runs', state.runs)
this.compiler.set('useFileConfiguration', state.useFileConfiguration) this.compiler.set('useFileConfiguration', state.useFileConfiguration)
this.currentFile = await this.call('fileManager', 'file') this.currentFile = await this.call('fileManager', 'file')
console.log(this.currentFile)
if (!this.currentFile) return if (!this.currentFile) return
const content = await this.call('fileManager', 'readFile', this.currentFile) const content = await this.call('fileManager', 'readFile', this.currentFile)
const sources = { [this.currentFile]: { content } } const sources = { [this.currentFile]: { content } }
@ -61,12 +149,23 @@ export class CodeParser extends Plugin {
} }
} }
/**
*
* @returns
*/
async getLastCompilationResult() {
return this.lastCompilationResult
}
/* /*
* simple parsing is used to quickly parse the current file or a text source without using the compiler or having to resolve imports * simple parsing is used to quickly parse the current file or a text source without using the compiler or having to resolve imports
*/ */
async parseSolidity(text: string) { async parseSolidity(text: string) {
const t0 = performance.now();
const ast = (SolidityParser as any).parse(text, { loc: true, range: true, tolerant: true }) const ast = (SolidityParser as any).parse(text, { loc: true, range: true, tolerant: true })
const t1 = performance.now();
console.log(`Call to doSomething took ${t1 - t0} milliseconds.`);
console.log('AST PARSE SUCCESS', ast) console.log('AST PARSE SUCCESS', ast)
return ast return ast
} }
@ -77,12 +176,13 @@ export class CodeParser extends Plugin {
* @param text * @param text
* @returns * @returns
*/ */
async getCurrentFileAST(text: string = null) { async getCurrentFileAST(text: string | null = null) {
this.currentFile = await this.call('fileManager', 'file') this.currentFile = await this.call('fileManager', 'file')
if (!this.currentFile) return if (!this.currentFile) return
const fileContent = text || await this.call('fileManager', 'readFile', this.currentFile) const fileContent = text || await this.call('fileManager', 'readFile', this.currentFile)
try { try {
const ast = await this.parseSolidity(fileContent) const ast = await this.parseSolidity(fileContent)
this.currentFileAST = ast this.currentFileAST = ast
console.log('AST PARSE SUCCESS', ast) console.log('AST PARSE SUCCESS', ast)
} catch (e) { } catch (e) {
@ -92,6 +192,31 @@ export class CodeParser extends Plugin {
return this.currentFileAST return this.currentFileAST
} }
/**
* Builds a flat index and declarations of all the nodes in the compilation result
* @param compilationResult
* @param source
*/
_buildIndex(compilationResult, source) {
if (compilationResult && compilationResult.sources) {
const callback = (node) => {
if (node && node.referencedDeclaration) {
if (!this._index.Declarations[node.referencedDeclaration]) {
this._index.Declarations[node.referencedDeclaration] = []
}
this._index.Declarations[node.referencedDeclaration].push(node)
}
this._index.FlatReferences[node.id] = node
}
for (const s in compilationResult.sources) {
this.astWalker.walkFull(compilationResult.sources[s].ast, callback)
}
console.log("INDEX", this._index)
}
}
// NODE HELPERS
/** /**
* Returns the block surrounding the given position * Returns the block surrounding the given position
* For example if the position is in the middle of a function, it will return the function * For example if the position is in the middle of a function, it will return the function
@ -100,6 +225,7 @@ export class CodeParser extends Plugin {
* @return {any} * @return {any}
* */ * */
async getBlockAtPosition(position: any, text: string = null) { async getBlockAtPosition(position: any, text: string = null) {
console.log('GET BLOCK AT ', position)
await this.getCurrentFileAST(text) await this.getCurrentFileAST(text)
const allowedTypes = ['SourceUnit', 'ContractDefinition', 'FunctionDefinition'] const allowedTypes = ['SourceUnit', 'ContractDefinition', 'FunctionDefinition']
@ -121,5 +247,370 @@ export class CodeParser extends Plugin {
return walkAst(this.currentFileAST) return walkAst(this.currentFileAST)
} }
/**
* Lists the AST nodes from the current file parser
* These nodes need to be changed to match the node types returned by the compiler
* @returns
*/
async listAstNodes() {
await this.getCurrentFileAST();
let nodes = [];
(SolidityParser as any).visit(this.currentFileAST, {
StateVariableDeclaration: (node) => {
if (node.variables) {
for (const variable of node.variables) {
nodes.push({ ...variable, nodeType: 'VariableDeclaration' })
}
}
},
UserDefinedTypeName: (node) => {
nodes.push({ ...node, nodeType: node.type })
},
FunctionDefinition: (node) => {
nodes.push({ ...node, nodeType: node.type })
},
ContractDefinition: (node) => {
nodes.push({ ...node, nodeType: node.type })
},
MemberAccess: function (node) {
nodes.push({ ...node, nodeType: node.type })
},
Identifier: function (node) {
nodes.push({ ...node, nodeType: node.type })
},
InvalidNode: function (node) {
nodes.push({ ...node, nodeType: node.type })
}
})
console.log("LIST NODES", nodes)
return nodes
}
/**
* Nodes at position where position is a number, offset
* @param position
* @param type
* @returns
*/
async nodesAtPosition(position: number, type = '') {
const lastCompilationResult = this.lastCompilationResult
if (!lastCompilationResult) return false
const urlFromPath = await this.call('fileManager', 'getUrlFromPath', this.currentFile)
if (lastCompilationResult && lastCompilationResult.languageversion.indexOf('soljson') === 0 && lastCompilationResult.data) {
const nodes = sourceMappingDecoder.nodesAtPosition(type, position, lastCompilationResult.data.sources[this.currentFile] || lastCompilationResult.data.sources[urlFromPath.file])
return nodes
}
return []
}
/**
*
* @param id
* @returns
*/
async getNodeById(id: any) {
for (const key in this._index.FlatReferences) {
if (this._index.FlatReferences[key].id === id) {
return this._index.FlatReferences[key]
}
}
}
/**
*
* @param id
* @returns
*/
async getDeclaration(id: any) {
if(this._index.Declarations && this._index.Declarations[id]) return this._index.Declarations[id]
}
/**
*
* @param scope
* @returns
*/
async getNodesWithScope(scope: number) {
const nodes = []
for (const node of Object.values(this._index.FlatReferences) as any[]) {
if (node.scope === scope) nodes.push(node)
}
return nodes
}
/**
*
* @param name
* @returns
*/
async getNodesWithName(name: string) {
const nodes = []
for (const node of Object.values(this._index.FlatReferences) as any[]) {
if (node.name === name) nodes.push(node)
}
return nodes
}
/**
*
* @param node
* @returns
*/
declarationOf(node: AstNode) {
if (node && node.referencedDeclaration) {
return this._index.FlatReferences[node.referencedDeclaration]
} else {
// console.log(this._index.FlatReferences)
}
return null
}
/**
*
* @param position
* @returns
*/
async definitionAtPosition(position: number) {
const nodes = await this.nodesAtPosition(position)
console.log('nodes at position', nodes, position)
console.log(this._index.FlatReferences)
let nodeDefinition: any
let node: any
if (nodes && nodes.length) {
node = nodes[nodes.length - 1]
nodeDefinition = node
if (!isNodeDefinition(node)) {
nodeDefinition = await this.declarationOf(node) || node
}
if (node.nodeType === 'ImportDirective') {
for (const key in this._index.FlatReferences) {
if (this._index.FlatReferences[key].id === node.sourceUnit) {
nodeDefinition = this._index.FlatReferences[key]
}
}
}
return nodeDefinition
} else {
let astNodes = await this.listAstNodes()
for (const node of astNodes) {
if (node.range[0] <= position && node.range[1] >= position) {
if (nodeDefinition && nodeDefinition.range[0] < node.range[0]) {
nodeDefinition = node
}
if (!nodeDefinition) nodeDefinition = node
}
}
return nodeDefinition
}
}
/**
*
* @param node
* @returns
*/
async positionOfDefinition(node: any): Promise<any | null> {
if (node) {
if (node.src) {
const position = sourceMappingDecoder.decode(node.src)
if (position) {
return position
}
}
}
return null
}
/**
*
* @param node
* @param imported
* @returns
*/
async resolveImports(node, imported = {}) {
if (node.nodeType === 'ImportDirective' && !imported[node.sourceUnit]) {
console.log('IMPORTING', node)
const importNode = await this.getNodeById(node.sourceUnit)
imported[importNode.id] = importNode
if (importNode.nodes) {
for (const child of importNode.nodes) {
imported = await this.resolveImports(child, imported)
}
}
}
console.log(imported)
return imported
}
/**
*
* @param ast
* @returns
*/
async getLastNodeInLine(ast: string) {
let lastNode
const checkLastNode = (node) => {
if (lastNode && lastNode.range && lastNode.range[1]) {
if (node.range[1] > lastNode.range[1]) {
lastNode = node
}
} else {
lastNode = node
}
}
(SolidityParser as any).visit(ast, {
MemberAccess: function (node) {
checkLastNode(node)
},
Identifier: function (node) {
checkLastNode(node)
}
})
if (lastNode && lastNode.expression && lastNode.expression.expression) {
console.log('lastNode with expression', lastNode, lastNode.expression)
return lastNode.expression.expression
}
if (lastNode && lastNode.expression) {
console.log('lastNode with expression', lastNode, lastNode.expression)
return lastNode.expression
}
console.log('lastNode', lastNode)
return lastNode
}
/**
*
* @param node
* @returns
*/
referencesOf(node: any) {
const results = []
const highlights = (id) => {
if (this._index.Declarations && this._index.Declarations[id]) {
const refs = this._index.Declarations[id]
for (const ref in refs) {
const node = refs[ref]
results.push(node)
}
}
}
if (node && node.referencedDeclaration) {
highlights(node.referencedDeclaration)
const current = this._index.FlatReferences[node.referencedDeclaration]
results.push(current)
} else {
highlights(node.id)
}
return results
}
/**
*
* @param position
* @returns
*/
async referrencesAtPosition(position: any) {
const nodes = await this.nodesAtPosition(position)
if (nodes && nodes.length) {
const node = nodes[nodes.length - 1]
if (node) {
return this.referencesOf(node)
}
}
}
/**
*
* @returns
*/
async getNodes() {
return this._index.FlatReferences
}
/**
*
* @param node
* @returns
*/
async getNodeLink(node: any) {
const position = await this.positionOfDefinition(node)
if (position) {
const filename = this.lastCompilationResult.getSourceName(position.file)
const lineColumn = await this.call('offsetToLineColumnConverter', 'offsetToLineColumn',
position,
position.file,
this.lastCompilationResult.getSourceCode().sources,
this.lastCompilationResult.getAsts())
return `${filename} ${lineColumn.start.line}:${lineColumn.start.column}`
}
}
/**
*
* @param node
* @returns
*/
async getNodeDocumentation(node: any) {
if (node.documentation && node.documentation.text) {
let text = ''
node.documentation.text.split('\n').forEach(line => {
text += `${line.trim()}\n`
})
return text
}
}
/**
*
* @param node
* @returns
*/
async getVariableDeclaration(node: any) {
if (node.typeDescriptions && node.typeDescriptions.typeString) {
return `${node.typeDescriptions.typeString}${node.name && node.name.length ? ` ${node.name}` : ''}`
} else
if (node.typeName && node.typeName.name) {
return `${node.typeName.name}${node.name && node.name.length ? ` ${node.name}` : ''}`
} else {
return `${node.name && node.name.length ? ` ${node.name}` : ''}`
}
}
/**
*
* @param node
* @returns
*/
async getFunctionParamaters(node: any) {
let localParam = (node.parameters && node.parameters.parameters) || (node.parameters)
if (localParam) {
const params = []
for (const param of localParam) {
params.push(await this.getVariableDeclaration(param))
}
return `(${params.join(', ')})`
}
}
/**
*
* @param node
* @returns
*/
async getFunctionReturnParameters(node: any) {
let localParam = (node.returnParameters && node.returnParameters.parameters)
if (localParam) {
const params = []
for (const param of localParam) {
params.push(await this.getVariableDeclaration(param))
}
return `(${params.join(', ')})`
}
}
} }

@ -1,36 +1,18 @@
'use strict' 'use strict'
import { Plugin } from '@remixproject/engine' import { Plugin } from '@remixproject/engine'
import { sourceMappingDecoder } from '@remix-project/remix-debug' import { sourceMappingDecoder } from '@remix-project/remix-debug'
import { CompilerAbstract } from '@remix-project/remix-solidity'
import { Compiler } from '@remix-project/remix-solidity'
import { CompilationError, CompilationResult, CompilationSource, helper } from '@remix-project/remix-solidity-ts'
const profile = { const profile = {
name: 'contextualListener', name: 'contextualListener',
methods: ['getBlockName', 'getLastNodeInLine', 'resolveImports', 'parseSource', 'getAST', 'nodesWithScope', 'nodesWithName', 'getNodes', 'compile', 'getNodeById', 'getLastCompilationResult', 'positionOfDefinition', 'definitionAtPosition', 'jumpToDefinition', 'referrencesAtPosition', 'nodesAtEditorPosition', 'referencesOf', 'getActiveHighlights', 'gasEstimation', 'declarationOf', 'jumpToPosition'], methods: ['getActiveHighlights', 'gasEstimation', 'jumpToPosition', 'jumpToDefinition'],
events: [], events: [],
version: '0.0.1' version: '0.0.1'
} }
export function isDefinition(node: any) {
return node.nodeType === 'ContractDefinition' ||
node.nodeType === 'FunctionDefinition' ||
node.nodeType === 'ModifierDefinition' ||
node.nodeType === 'VariableDeclaration' ||
node.nodeType === 'StructDefinition' ||
node.nodeType === 'EventDefinition'
}
const SolidityParser = (window as any).SolidityParser = (window as any).SolidityParser || []
/* /*
trigger contextChanged(nodes) trigger contextChanged(nodes)
*/ */
export class EditorContextListener extends Plugin { export class EditorContextListener extends Plugin {
_index: any
_activeHighlights: Array<any> _activeHighlights: Array<any>
astWalker: any astWalker: any
currentPosition: any currentPosition: any
@ -42,18 +24,11 @@ export class EditorContextListener extends Plugin {
codeDepositCost: any codeDepositCost: any
contract: any contract: any
activated: boolean activated: boolean
lastCompilationResult: any
lastAST: any
compiler: any
onAstFinished: (success: any, data: any, source: any, input: any, version: any) => Promise<void>
constructor(astWalker) { constructor(astWalker) {
super(profile) super(profile)
this.activated = false this.activated = false
this._index = {
Declarations: {},
FlatReferences: {}
}
this._activeHighlights = [] this._activeHighlights = []
this.astWalker = astWalker this.astWalker = astWalker
@ -62,97 +37,15 @@ export class EditorContextListener extends Plugin {
async onActivation() { async onActivation() {
this.on('editor', 'contentChanged', async () => { this.on('editor', 'contentChanged', async () => {
console.log('contentChanged') console.log('contentChanged')
await this.getAST()
await this.compile()
this._stopHighlighting() this._stopHighlighting()
}) })
this.on('fileManager', 'currentFileChanged', async () => { this.on('fileManager', 'currentFileChanged', async () => {
await this.getAST()
await this.compile()
this._stopHighlighting() this._stopHighlighting()
}) })
this.on('solidity', 'loadingCompiler', async (url) => {
console.log('loading compiler', url)
this.compiler.loadVersion(true, url)
this.compiler.event.register('compilerLoaded', async () => {
console.log('compiler loaded')
})
})
this.compiler = new Compiler((url, cb) => this.call('contentImport', 'resolveAndSave', url, undefined, false).then((result) => cb(null, result)).catch((error) => cb(error.message)))
this.onAstFinished = async (success, data: CompilationResult, source: CompilationSource, input: any, version) => {
console.log('compile success', success, data)
this.call('editor', 'clearAnnotations')
let noFatalErrors = true // ie warnings are ok
const checkIfFatalError = (error: CompilationError) => {
// Ignore warnings and the 'Deferred import' error as those are generated by us as a workaround
const isValidError = (error.message && error.message.includes('Deferred import')) ? false : error.severity !== 'warning'
if (isValidError) {
console.log(error)
noFatalErrors = false
}
}
const result = new CompilerAbstract('soljson', data, source, input)
if (data.error) checkIfFatalError(data.error)
if (data.errors) data.errors.forEach((err) => checkIfFatalError(err))
const allErrors = []
if (data.errors) {
for (const error of data.errors) {
console.log('ERROR POS', error)
let pos = helper.getPositionDetails(error.formattedMessage)
console.log('ERROR POS', pos)
const sources = result.getSourceCode().sources
const source = sources[pos.file]
const lineColumn = await this.call('offsetToLineColumnConverter', 'offsetToLineColumn',
{
start: error.sourceLocation.start,
length: error.sourceLocation.end - error.sourceLocation.start
},
0,
sources,
null)
console.log('lineColumn', lineColumn)
allErrors.push({ error, lineColumn })
}
await this.call('editor', 'addErrorMarker', allErrors)
} else {
await this.call('editor', 'clearErrorMarkers', result.getSourceCode().sources)
}
if (!data.sources) return
if (data.sources && Object.keys(data.sources).length === 0) return
this.lastCompilationResult = new CompilerAbstract('soljson', data, source, input)
this._stopHighlighting()
this._index = {
Declarations: {},
FlatReferences: {}
}
this._buildIndex(data, source)
this.emit('astFinished')
}
this.compiler.event.register('astFinished', this.onAstFinished)
setInterval(async () => {
//await this.compile()
}, 1000)
setInterval(async () => { setInterval(async () => {
return const compilationResult = await this.call('codeParser', 'getLastCompilationResult')
const compilationResult = this.lastCompilationResult // await this.call('compilerArtefacts', 'getLastCompilationResult')
if (compilationResult && compilationResult.languageversion.indexOf('soljson') === 0) { if (compilationResult && compilationResult.languageversion.indexOf('soljson') === 0) {
let currentFile let currentFile
@ -170,245 +63,20 @@ export class EditorContextListener extends Plugin {
}, 1000) }, 1000)
} }
async getLastCompilationResult() {
return this.lastCompilationResult
}
async compile() {
console.log('compile')
try {
const state = await this.call('solidity', 'getCompilerState')
this.compiler.set('optimize', state.optimize)
this.compiler.set('evmVersion', state.evmVersion)
this.compiler.set('language', state.language)
this.compiler.set('runs', state.runs)
this.compiler.set('useFileConfiguration', state.useFileConfiguration)
this.currentFile = await this.call('fileManager', 'file')
if (!this.currentFile) return
const content = await this.call('fileManager', 'readFile', this.currentFile)
// console.log('compile', this.currentFile, content)
const sources = { [this.currentFile]: { content } }
this.compiler.compile(sources, this.currentFile)
} catch (e) {
console.log(e)
}
}
async resolveImports(node, imported = {}) {
if (node.nodeType === 'ImportDirective' && !imported[node.sourceUnit]) {
console.log('IMPORTING', node)
const importNode = await this.getNodeById(node.sourceUnit)
imported[importNode.id] = importNode
if (importNode.nodes) {
for (const child of importNode.nodes) {
imported = await this.resolveImports(child, imported)
}
}
}
console.log(imported)
return imported
}
async getBlockName(position: any, text: string = null) {
await this.getAST(text)
const allowedTypes = ['SourceUnit', 'ContractDefinition', 'FunctionDefinition']
const walkAst = (node) => {
console.log(node)
if (node.loc.start.line <= position.lineNumber && node.loc.end.line >= position.lineNumber) {
const children = node.children || node.subNodes
if (children && allowedTypes.indexOf(node.type) !== -1) {
for (const child of children) {
const result = walkAst(child)
if (result) return result
}
}
return node
}
return null
}
if (!this.lastAST) return
return walkAst(this.lastAST)
}
async getAST(text: string = null) {
this.currentFile = await this.call('fileManager', 'file')
if (!this.currentFile) return
const fileContent = text || await this.call('fileManager', 'readFile', this.currentFile)
try {
const ast = await this.parseSource(fileContent)
this.lastAST = ast
console.log('AST PARSE SUCCESS', ast)
} catch (e) {
console.log(e)
}
console.log('LAST PARSER AST', this.lastAST)
return this.lastAST
}
async parseSource(text: string) {
//console.log('PARSING', text)
const ast = (SolidityParser as any).parse(text, { loc: true, range: true, tolerant: true })
console.log('AST PARSE SUCCESS', ast)
return ast
}
async getLastNodeInLine(ast: string) {
let lastNode
const checkLastNode = (node) => {
if (lastNode && lastNode.range && lastNode.range[1]) {
if (node.range[1] > lastNode.range[1]) {
lastNode = node
}
} else {
lastNode = node
}
}
(SolidityParser as any).visit(ast, {
MemberAccess: function (node) {
checkLastNode(node)
},
Identifier: function (node) {
checkLastNode(node)
}
})
if (lastNode && lastNode.expression) {
console.log('lastNode', lastNode.expression)
return lastNode.expression
}
console.log('lastNode', lastNode)
return lastNode
}
getActiveHighlights() { getActiveHighlights() {
return [...this._activeHighlights] return [...this._activeHighlights]
} }
declarationOf(node) {
if (node && node.referencedDeclaration) {
return this._index.FlatReferences[node.referencedDeclaration]
} else {
// console.log(this._index.FlatReferences)
}
return null
}
referencesOf(node: any) {
const results = []
const highlights = (id) => {
if (this._index.Declarations && this._index.Declarations[id]) {
const refs = this._index.Declarations[id]
for (const ref in refs) {
const node = refs[ref]
results.push(node)
}
}
}
if (node && node.referencedDeclaration) {
highlights(node.referencedDeclaration)
const current = this._index.FlatReferences[node.referencedDeclaration]
results.push(current)
} else {
highlights(node.id)
}
return results
}
async nodesAtEditorPosition(position: any, type = '') {
const lastCompilationResult = this.lastCompilationResult // await this.call('compilerArtefacts', 'getLastCompilationResult')
if (!lastCompilationResult) return false
const urlFromPath = await this.call('fileManager', 'getUrlFromPath', this.currentFile)
if (lastCompilationResult && lastCompilationResult.languageversion.indexOf('soljson') === 0 && lastCompilationResult.data) {
const nodes = sourceMappingDecoder.nodesAtPosition(type, position, lastCompilationResult.data.sources[this.currentFile] || lastCompilationResult.data.sources[urlFromPath.file])
return nodes
}
return []
}
async referrencesAtPosition(position: any) {
const nodes = await this.nodesAtEditorPosition(position)
if (nodes && nodes.length) {
const node = nodes[nodes.length - 1]
if (node) {
return this.referencesOf(node)
}
}
}
async getNodeById(id: any) {
for (const key in this._index.FlatReferences) {
if (this._index.FlatReferences[key].id === id) {
return this._index.FlatReferences[key]
}
}
}
async nodesWithScope(scope: any) {
const nodes = []
for (const node of Object.values(this._index.FlatReferences) as any[]) {
if (node.scope === scope) nodes.push(node)
}
return nodes
}
async nodesWithName(name: string) {
const nodes = []
for (const node of Object.values(this._index.FlatReferences) as any[]) {
if (node.name === name) nodes.push(node)
}
return nodes
}
async definitionAtPosition(position: any) {
const nodes = await this.nodesAtEditorPosition(position)
console.log('nodes at position', nodes)
console.log(this._index.FlatReferences)
let nodeDefinition: any
let node: any
if (nodes && nodes.length) {
node = nodes[nodes.length - 1]
nodeDefinition = node
if (!isDefinition(node)) {
nodeDefinition = await this.declarationOf(node) || node
}
if (node.nodeType === 'ImportDirective') {
for (const key in this._index.FlatReferences) {
if (this._index.FlatReferences[key].id === node.sourceUnit) {
nodeDefinition = this._index.FlatReferences[key]
}
}
}
return nodeDefinition
} else {
return false
}
}
async positionOfDefinition(node: any) {
if (node) {
if (node.src) {
const position = sourceMappingDecoder.decode(node.src)
if (position) {
return position
}
}
}
return null
}
async jumpToDefinition(position: any) { async jumpToDefinition(position: any) {
const node = await this.definitionAtPosition(position) const node = await this.call('codeParser', 'definitionAtPosition', position)
const sourcePosition = await this.positionOfDefinition(node) const sourcePosition = await this.call('codeParser', 'positionOfDefinition', node)
console.log("JUMP", sourcePosition)
if (sourcePosition) { if (sourcePosition) {
await this.jumpToPosition(sourcePosition) await this.jumpToPosition(sourcePosition)
} }
} }
async getNodes() {
return this._index.FlatReferences
}
/* /*
* onClick jump to position of ast node in the editor * onClick jump to position of ast node in the editor
@ -424,7 +92,7 @@ export class EditorContextListener extends Plugin {
this.call('editor', 'gotoLine', lineColumn.start.line, lineColumn.end.column + 1) this.call('editor', 'gotoLine', lineColumn.start.line, lineColumn.end.column + 1)
} }
} }
const lastCompilationResult = this.lastCompilationResult // await this.call('compilerArtefacts', 'getLastCompilationResult') const lastCompilationResult = await this.call('codeParser', 'getLastCompilationResult') // await this.call('compilerArtefacts', 'getLastCompilationResult')
console.log(lastCompilationResult.getSourceCode().sources) console.log(lastCompilationResult.getSourceCode().sources)
console.log(position) console.log(position)
if (lastCompilationResult && lastCompilationResult.languageversion.indexOf('soljson') === 0 && lastCompilationResult.data) { if (lastCompilationResult && lastCompilationResult.languageversion.indexOf('soljson') === 0 && lastCompilationResult.data) {
@ -456,23 +124,6 @@ export class EditorContextListener extends Plugin {
} }
} }
_buildIndex(compilationResult, source) {
if (compilationResult && compilationResult.sources) {
const callback = (node) => {
if (node && node.referencedDeclaration) {
if (!this._index.Declarations[node.referencedDeclaration]) {
this._index.Declarations[node.referencedDeclaration] = []
}
this._index.Declarations[node.referencedDeclaration].push(node)
}
this._index.FlatReferences[node.id] = node
}
for (const s in compilationResult.sources) {
this.astWalker.walkFull(compilationResult.sources[s].ast, callback)
}
}
}
async _highlight(node, compilationResult) { async _highlight(node, compilationResult) {
if (!node) return if (!node) return
const position = sourceMappingDecoder.decode(node.src) const position = sourceMappingDecoder.decode(node.src)
@ -512,9 +163,10 @@ export class EditorContextListener extends Plugin {
} }
async _highlightExpressions(node, compilationResult) { async _highlightExpressions(node, compilationResult) {
const highlights = async (id) => { const highlights = async (id) => {
if (this._index.Declarations && this._index.Declarations[id]) { let refs = await this.call('codeParser', 'getDeclaration', id)
const refs = this._index.Declarations[id] if (refs) {
for (const ref in refs) { for (const ref in refs) {
const node = refs[ref] const node = refs[ref]
await this._highlight(node, compilationResult) await this._highlight(node, compilationResult)
@ -523,7 +175,7 @@ export class EditorContextListener extends Plugin {
} }
if (node && node.referencedDeclaration) { if (node && node.referencedDeclaration) {
await highlights(node.referencedDeclaration) await highlights(node.referencedDeclaration)
const current = this._index.FlatReferences[node.referencedDeclaration] const current = await this.call('codeParser', 'getNodeById', node.referencedDeclaration) // this._index.FlatReferences[node.referencedDeclaration]
await this._highlight(current, compilationResult) await this._highlight(current, compilationResult)
} else { } else {
await highlights(node.id) await highlights(node.id)
@ -531,6 +183,7 @@ export class EditorContextListener extends Plugin {
} }
this.results = compilationResult this.results = compilationResult
} }
_stopHighlighting() { _stopHighlighting() {
@ -563,6 +216,7 @@ export class EditorContextListener extends Plugin {
} }
_loadContractInfos(node) { _loadContractInfos(node) {
console.log(this.results)
const path = (this.nodes.length && this.nodes[0].absolutePath) || this.results.source.target const path = (this.nodes.length && this.nodes[0].absolutePath) || this.results.source.target
for (const i in this.nodes) { for (const i in this.nodes) {
if (this.nodes[i].id === node.scope) { if (this.nodes[i].id === node.scope) {

@ -1,3 +1,4 @@
import { isArray } from "lodash"
import { editor, languages, Position } from "monaco-editor" import { editor, languages, Position } from "monaco-editor"
import monaco from "../../types/monaco" import monaco from "../../types/monaco"
import { EditorUIProps } from "../remix-ui-editor" import { EditorUIProps } from "../remix-ui-editor"
@ -39,114 +40,53 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
if (context.triggerCharacter === '.') { if (context.triggerCharacter === '.') {
console.clear() console.clear()
console.log('TEXT', line) console.log('TEXT', line)
const textBeforeCursor = line.substring(0, position.column - 1) const lineTextBeforeCursor = line.substring(0, position.column - 1)
const textAfterCursor = line.substring(position.column - 1) const lastNodeInExpression = await this.getLastNodeInExpression(lineTextBeforeCursor)
// parse the line witout changing the line console.log('lastNode found', lastNodeInExpression)
console.log(lineTextBeforeCursor)
const expressionElements = lineTextBeforeCursor.split('.')
const wrapLineInFunction = (text: string) => { console.log('expression elements', expressionElements)
return `function() {
${text}
}`
}
let lastNode
const checkLastNode = (node) => {
if (!node) return
if (lastNode && lastNode.range && lastNode.range[1]) {
if (node.range[1] > lastNode.range[1]) {
lastNode = node
}
} else {
lastNode = node
}
}
const linesToCheck =
[
textBeforeCursor.substring(0, textBeforeCursor.lastIndexOf('.')) + ".lastnode;",
textBeforeCursor.substring(0, textBeforeCursor.lastIndexOf('.')) + ".lastnode;}",
textBeforeCursor.substring(0, textBeforeCursor.lastIndexOf('.')) + ".lastnode);",
wrapLineInFunction(textBeforeCursor.substring(0, textBeforeCursor.lastIndexOf('.')) + ".lastnode;"),
wrapLineInFunction(textBeforeCursor.substring(0, textBeforeCursor.lastIndexOf('.')) + ".lastnode;}"),
wrapLineInFunction(textBeforeCursor.substring(0, textBeforeCursor.lastIndexOf('.')) + ".lastnode;)"),
]
for (const line of linesToCheck) {
try {
const lineAst = await this.props.plugin.call('contextualListener', 'parseSource', line)
const lastNode = await this.props.plugin.call('contextualListener', 'getLastNodeInLine', lineAst)
checkLastNode(lastNode)
} catch (e) {
}
}
console.log('lastNode found', lastNode)
console.log(textBeforeCursor, textAfterCursor)
const splits = textBeforeCursor.split('.')
console.log('splits', splits)
let dotCompleted = false let dotCompleted = false
if (splits.length === 2) { if (expressionElements.length === 2) {
let globalCompletion = getContextualAutoCompleteByGlobalVariable(lastNode.name, range, this.monaco) let globalCompletion = getContextualAutoCompleteByGlobalVariable(lastNodeInExpression.name, range, this.monaco)
if (globalCompletion) { if (globalCompletion) {
dotCompleted = true dotCompleted = true
suggestions = [...suggestions, ...globalCompletion] suggestions = [...suggestions, ...globalCompletion]
} }
if (lastNode.name === 'this') { if (lastNodeInExpression.name === 'this') {
dotCompleted = true dotCompleted = true
nodes = [...nodes, ...await this.getContractCompletions(nodes, position)] nodes = [...nodes, ...await this.getContractCompletions(nodes, position)]
} }
} }
if (splits.length > 1 && !dotCompleted) { if (expressionElements.length > 1 && !dotCompleted) {
let last = splits[splits.length - 2].trim()
const lastParentheses = last.lastIndexOf('(')
const lastClosingParentheses = last.lastIndexOf(')')
const lastBracket = last.lastIndexOf('{')
const lastSemiColon = last.lastIndexOf(';')
let textBefore = null
let lineWithoutEdits = null
// get word before last closing parentheses
if (lastParentheses > -1 && lastClosingParentheses > -1) {
//textBefore = last.substring(0, lastParentheses)
}
// find largest
const lastIndex = Math.max(lastParentheses, lastBracket, lastSemiColon)
if (lastIndex > -1) {
textBefore = last.substring(0, lastIndex + 1)
console.log('textBefore', textBefore)
console.log('text without edits', textBefore, textAfterCursor)
lineWithoutEdits = `${textBefore}${textAfterCursor}`
}
last = lastNode.name || lastNode.memberName
console.log('last', last)
const lines = model.getLinesContent() const last = lastNodeInExpression.name || lastNodeInExpression.memberName
lines[position.lineNumber - 1] = lineWithoutEdits console.log('last', last)
const textWithoutEdits = lines.join('\n')
console.log('textWithoutEdits', textWithoutEdits)
let nodesAtPosition = await this.props.plugin.call('contextualListener', 'nodesAtEditorPosition', cursorPosition) let nodesAtPosition;
console.log('NODES AT POSITION', nodesAtPosition) const block = await this.props.plugin.call('codeParser', 'getBlockAtPosition', position, null)
const block = await this.props.plugin.call('contextualListener', 'getBlockName', position, textWithoutEdits)
console.log('BLOCK', block) console.log('BLOCK', block)
//if (!nodesAtPosition.length) {
if (block) { if (block) {
nodesAtPosition = await this.props.plugin.call('contextualListener', 'nodesAtEditorPosition', block.body ? block.body.range[0] : block.range[0]) nodesAtPosition = await this.props.plugin.call('codeParser', 'nodesAtPosition', block.body ? block.body.range[0] : block.range[0])
console.log('NODES AT POSITION WITH BLOCK', nodesAtPosition) console.log('NODES AT POSITION WITH BLOCK', nodesAtPosition)
} else{
nodesAtPosition = await this.props.plugin.call('codeParser', 'nodesAtPosition', cursorPosition)
console.log('NODES AT POSITION', nodesAtPosition)
} }
//}
// explore nodes at the BLOCK // explore nodes at the BLOCK
if (nodesAtPosition) { if (nodesAtPosition) {
for (const node of nodesAtPosition) { for (const node of nodesAtPosition) {
const nodesOfScope = await this.props.plugin.call('contextualListener', 'nodesWithScope', node.id) const nodesOfScope = await this.props.plugin.call('codeParser', 'getNodesWithScope', node.id)
console.log('NODES OF SCOPE ', node.name, node.id, nodesOfScope) console.log('NODES OF SCOPE ', node.name, node.id, nodesOfScope)
for (const nodeOfScope of nodesOfScope) { for (const nodeOfScope of nodesOfScope) {
if (nodeOfScope.name === last) { if (nodeOfScope.name === last) {
console.log('FOUND NODE', nodeOfScope) console.log('FOUND NODE', nodeOfScope)
if (nodeOfScope.typeName && nodeOfScope.typeName.nodeType === 'UserDefinedTypeName') { if (nodeOfScope.typeName && nodeOfScope.typeName.nodeType === 'UserDefinedTypeName') {
const declarationOf = await this.props.plugin.call('contextualListener', 'declarationOf', nodeOfScope.typeName) const declarationOf = await this.props.plugin.call('codeParser', 'declarationOf', nodeOfScope.typeName)
console.log('HAS DECLARATION OF', declarationOf) console.log('HAS DECLARATION OF', declarationOf)
nodes = [...nodes, ...declarationOf.nodes || declarationOf.members] nodes = [...nodes, ...declarationOf.nodes || declarationOf.members]
const baseContracts = await this.getlinearizedBaseContracts(declarationOf) const baseContracts = await this.getlinearizedBaseContracts(declarationOf)
@ -163,9 +103,9 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
if (node.statements) { if (node.statements) {
for (const statement of node.statements) { for (const statement of node.statements) {
if (statement.expression && statement.expression.memberName === last) { if (statement.expression && statement.expression.memberName === last) {
const declarationOf = await this.props.plugin.call('contextualListener', 'declarationOf', statement.expression) const declarationOf = await this.props.plugin.call('codeParser', 'declarationOf', statement.expression)
if (declarationOf.typeName && declarationOf.typeName.nodeType === 'UserDefinedTypeName') { if (declarationOf.typeName && declarationOf.typeName.nodeType === 'UserDefinedTypeName') {
const baseDeclaration = await this.props.plugin.call('contextualListener', 'declarationOf', declarationOf.typeName) const baseDeclaration = await this.props.plugin.call('codeParser', 'declarationOf', declarationOf.typeName)
console.log('HAS BASE DECLARATION OF', baseDeclaration) console.log('HAS BASE DECLARATION OF', baseDeclaration)
nodes = [...nodes, ...baseDeclaration.nodes || baseDeclaration.members] nodes = [...nodes, ...baseDeclaration.nodes || baseDeclaration.members]
} }
@ -178,13 +118,13 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
// brute force search in all nodes with the name // brute force search in all nodes with the name
if (!nodes.length) { if (!nodes.length) {
const nodesOfScope = await this.props.plugin.call('contextualListener', 'nodesWithName', last) const nodesOfScope = await this.props.plugin.call('codeParser', 'getNodesWithName', last)
console.log('NODES WITHE NAME ', last, nodesOfScope) console.log('NODES WITHE NAME ', last, nodesOfScope)
for (const nodeOfScope of nodesOfScope) { for (const nodeOfScope of nodesOfScope) {
if (nodeOfScope.name === last) { if (nodeOfScope.name === last) {
console.log('FOUND NODE', nodeOfScope) console.log('FOUND NODE', nodeOfScope)
if (nodeOfScope.typeName && nodeOfScope.typeName.nodeType === 'UserDefinedTypeName') { if (nodeOfScope.typeName && nodeOfScope.typeName.nodeType === 'UserDefinedTypeName') {
const declarationOf = await this.props.plugin.call('contextualListener', 'declarationOf', nodeOfScope.typeName) const declarationOf = await this.props.plugin.call('codeParser', 'declarationOf', nodeOfScope.typeName)
console.log('HAS DECLARATION OF', declarationOf) console.log('HAS DECLARATION OF', declarationOf)
// nodes = [...nodes, ...declarationOf.nodes || declarationOf.members] // nodes = [...nodes, ...declarationOf.nodes || declarationOf.members]
const baseContracts = await this.getlinearizedBaseContracts(declarationOf) const baseContracts = await this.getlinearizedBaseContracts(declarationOf)
@ -213,43 +153,24 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
console.log('WORD', word, wordAt) console.log('WORD', word, wordAt)
console.log('NODES', nodes) console.log('NODES', nodes)
const getLinks = async (node: any) => { const getNodeLink = async (node: any) => {
const position = await this.props.plugin.call('contextualListener', 'positionOfDefinition', node) return await this.props.plugin.call('codeParser', 'getNodeLink', node)
const lastCompilationResult = await this.props.plugin.call('contextualListener', 'getLastCompilationResult')
const filename = lastCompilationResult.getSourceName(position.file)
const lineColumn = await this.props.plugin.call('offsetToLineColumnConverter', 'offsetToLineColumn',
position,
position.file,
lastCompilationResult.getSourceCode().sources,
lastCompilationResult.getAsts())
return `${filename} ${lineColumn.start.line}:${lineColumn.start.column}`
} }
const getDocs = async (node: any) => { const getDocs = async (node: any) => {
if (node.documentation && node.documentation.text) { return await this.props.plugin.call('codeParser', 'getNodeDocumentation', node)
let text = ''
node.documentation.text.split('\n').forEach(line => {
text += `${line.trim()}\n`
})
return text
}
} }
const getParamaters = async (parameters: any) => { const getParamaters = async (node: any) => {
if (parameters && parameters.parameters) { return await this.props.plugin.call('codeParser', 'getFunctionParamaters', node)
const params = []
for (const param of parameters.parameters) {
params.push(await getVariableDeclaration(param))
}
return `(${params.join(', ')})`
}
} }
const completeParameters = async (parameters: any) => { const completeParameters = async (parameters: any) => {
if (parameters && parameters.parameters) { let localParam = ( parameters && parameters.parameters ) || (parameters)
if (localParam) {
const params = [] const params = []
for (const key in parameters.parameters) { for (const key in localParam) {
params.push('${' + (key + 1) + ':' + parameters.parameters[key].name + '}') params.push('${' + (key + 1) + ':' + localParam[key].name + '}')
} }
return `(${params.join(', ')})` return `(${params.join(', ')})`
} }
@ -257,14 +178,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
const getVariableDeclaration = async (node: any) => { const getVariableDeclaration = async (node: any) => {
if (node.typeDescriptions && node.typeDescriptions.typeString) { return await this.props.plugin.call('codeParser', 'getVariableDeclaration', node)
return `${node.typeDescriptions.typeString}${node.name && node.name.length ? ` ${node.name}` : ''}`
} else
if (node.typeName && node.typeName.name) {
return `${node.typeName.name}${node.name && node.name.length ? ` ${node.name}` : ''}`
} else {
return `${node.name && node.name.length ? ` ${node.name}` : ''}`
}
} }
@ -272,7 +186,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
if (!node.name) continue if (!node.name) continue
if (node.nodeType === 'VariableDeclaration') { if (node.nodeType === 'VariableDeclaration') {
const completion = { const completion = {
label: { label: `"${node.name}"`, description: await getLinks(node), detail: ` ${await getVariableDeclaration(node)}` }, label: { label: `"${node.name}"`, description: await getNodeLink(node), detail: ` ${await getVariableDeclaration(node)}` },
kind: this.monaco.languages.CompletionItemKind.Variable, kind: this.monaco.languages.CompletionItemKind.Variable,
insertText: node.name, insertText: node.name,
range: range, range: range,
@ -282,7 +196,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
} else if (node.nodeType === 'FunctionDefinition') { } else if (node.nodeType === 'FunctionDefinition') {
const completion = { const completion = {
label: { label: `"${node.name}"`, description: await getLinks(node), detail: ` -> ${node.name} ${await getParamaters(node.parameters)}` }, label: { label: `"${node.name}"`, description: await getNodeLink(node), detail: ` -> ${node.name} ${await getParamaters(node)}` },
kind: this.monaco.languages.CompletionItemKind.Function, kind: this.monaco.languages.CompletionItemKind.Function,
insertText: `${node.name}${await completeParameters(node.parameters)};`, insertText: `${node.name}${await completeParameters(node.parameters)};`,
insertTextRules: this.monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet, insertTextRules: this.monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
@ -293,7 +207,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
} else if } else if
(node.nodeType === 'ContractDefinition') { (node.nodeType === 'ContractDefinition') {
const completion = { const completion = {
label: { label: `"${node.name}"`, description: await getLinks(node), detail: ` ${node.name}` }, label: { label: `"${node.name}"`, description: await getNodeLink(node), detail: ` ${node.name}` },
kind: this.monaco.languages.CompletionItemKind.Interface, kind: this.monaco.languages.CompletionItemKind.Interface,
insertText: node.name, insertText: node.name,
range: range, range: range,
@ -303,7 +217,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
} else if } else if
(node.nodeType === 'StructDefinition') { (node.nodeType === 'StructDefinition') {
const completion = { const completion = {
label: { label: `"${node.name}"`, description: await getLinks(node), detail: ` ${node.name}` }, label: { label: `"${node.name}"`, description: await getNodeLink(node), detail: ` ${node.name}` },
kind: this.monaco.languages.CompletionItemKind.Struct, kind: this.monaco.languages.CompletionItemKind.Struct,
insertText: node.name, insertText: node.name,
range: range, range: range,
@ -313,7 +227,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
} else if } else if
(node.nodeType === 'EnumDefinition') { (node.nodeType === 'EnumDefinition') {
const completion = { const completion = {
label: { label: `"${node.name}"`, description: await getLinks(node), detail: ` ${node.name}` }, label: { label: `"${node.name}"`, description: await getNodeLink(node), detail: ` ${node.name}` },
kind: this.monaco.languages.CompletionItemKind.Enum, kind: this.monaco.languages.CompletionItemKind.Enum,
insertText: node.name, insertText: node.name,
range: range, range: range,
@ -323,7 +237,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
} else if } else if
(node.nodeType === 'EventDefinition') { (node.nodeType === 'EventDefinition') {
const completion = { const completion = {
label: { label: `"${node.name}"`, description: await getLinks(node), detail: ` ${node.name}` }, label: { label: `"${node.name}"`, description: await getNodeLink(node), detail: ` ${node.name}` },
kind: this.monaco.languages.CompletionItemKind.Event, kind: this.monaco.languages.CompletionItemKind.Event,
insertText: node.name, insertText: node.name,
range: range, range: range,
@ -333,7 +247,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
} else if } else if
(node.nodeType === 'ModifierDefinition') { (node.nodeType === 'ModifierDefinition') {
const completion = { const completion = {
label: { label: `"${node.name}"`, description: await getLinks(node), detail: ` ${node.name}` }, label: { label: `"${node.name}"`, description: await getNodeLink(node), detail: ` ${node.name}` },
kind: this.monaco.languages.CompletionItemKind.Method, kind: this.monaco.languages.CompletionItemKind.Method,
insertText: node.name, insertText: node.name,
range: range, range: range,
@ -345,18 +259,6 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
} }
} }
suggestions = [...suggestions,
/* ...GetGlobalVariable(range, this.monaco),
...getCompletionSnippets(range, this.monaco),
...getBlockCompletionItems(range, this.monaco),
...GetCompletionTypes(range,this.monaco),
...GetCompletionKeywords(range,this.monaco),
...GetGlobalFunctions(range,this.monaco),
...GeCompletionUnits(range,this.monaco),
...getMsgCompletionItems(range,this.monaco),
...getTxCompletionItems(range,this.monaco), */
]
console.log(suggestions) console.log(suggestions)
return { return {
suggestions suggestions
@ -368,7 +270,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
if (node.linearizedBaseContracts) { if (node.linearizedBaseContracts) {
for (const id of node.linearizedBaseContracts) { for (const id of node.linearizedBaseContracts) {
if (id !== node.id) { if (id !== node.id) {
const baseContract = await this.props.plugin.call('contextualListener', 'getNodeById', id) const baseContract = await this.props.plugin.call('codeParser', 'getNodeById', id)
params = [...params, ...[baseContract]] params = [...params, ...[baseContract]]
} }
} }
@ -378,21 +280,22 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
private getContractCompletions = async (nodes: any[], position: Position) => { private getContractCompletions = async (nodes: any[], position: Position) => {
const cursorPosition = this.props.editorAPI.getCursorPosition() const cursorPosition = this.props.editorAPI.getCursorPosition()
let nodesAtPosition = await this.props.plugin.call('contextualListener', 'nodesAtEditorPosition', cursorPosition) let nodesAtPosition = await this.props.plugin.call('codeParser', 'nodesAtPosition', cursorPosition)
// if no nodes exits at position, try to get the block of which the position is in // if no nodes exits at position, try to get the block of which the position is in
if (!nodesAtPosition.length) { if (!nodesAtPosition.length) {
const block = await this.props.plugin.call('contextualListener', 'getBlockName', position, null) const block = await this.props.plugin.call('codeParser', 'getBlockAtPosition', position, null)
if (block) { if (block) {
nodesAtPosition = await this.props.plugin.call('contextualListener', 'nodesAtEditorPosition', block.range[0]) nodesAtPosition = await this.props.plugin.call('codeParser', 'nodesAtPosition', block.range[0])
} }
} }
// get all children of all nodes at position // get all children of all nodes at position
if (isArray(nodesAtPosition)) {
for (const node of nodesAtPosition) { for (const node of nodesAtPosition) {
const nodesOfScope = await this.props.plugin.call('contextualListener', 'nodesWithScope', node.id) const nodesOfScope = await this.props.plugin.call('codeParser', 'getNodesWithScope', node.id)
for (const nodeOfScope of nodesOfScope) { for (const nodeOfScope of nodesOfScope) {
const imports = await this.props.plugin.call('contextualListener', 'resolveImports', nodeOfScope) const imports = await this.props.plugin.call('codeParser', 'resolveImports', nodeOfScope)
if (imports) { if (imports) {
for (const key in imports) { for (const key in imports) {
if (imports[key].nodes) if (imports[key].nodes)
@ -409,6 +312,54 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
nodes = [...nodes, ...baseContract.nodes] nodes = [...nodes, ...baseContract.nodes]
} }
} }
} else {
// get all the nodes from a simple code parser which only parses the current file
nodes = [...nodes, ...await this.props.plugin.call('codeParser', 'listAstNodes')]
}
return nodes return nodes
} }
/**
*
* @param lineTextBeforeCursor
* @returns
*/
private async getLastNodeInExpression(lineTextBeforeCursor: string) {
const wrapLineInFunction = async(text: string) => {
return `function() {
${text}
}`
}
let lastNodeInExpression
const linesToCheck =
[
lineTextBeforeCursor.substring(0, lineTextBeforeCursor.lastIndexOf('.')) + ".lastnode;",
lineTextBeforeCursor.substring(0, lineTextBeforeCursor.lastIndexOf('.')) + ".lastnode;}",
lineTextBeforeCursor.substring(0, lineTextBeforeCursor.lastIndexOf('.')) + ".lastnode);",
await wrapLineInFunction(lineTextBeforeCursor.substring(0, lineTextBeforeCursor.lastIndexOf('.')) + ".lastnode;"),
await wrapLineInFunction(lineTextBeforeCursor.substring(0, lineTextBeforeCursor.lastIndexOf('.')) + ".lastnode;}"),
await wrapLineInFunction(lineTextBeforeCursor.substring(0, lineTextBeforeCursor.lastIndexOf('.')) + ".lastnode;)"),
await wrapLineInFunction(lineTextBeforeCursor.substring(0, lineTextBeforeCursor.lastIndexOf('.')) + ".lastnode)"),
await wrapLineInFunction(lineTextBeforeCursor.substring(0, lineTextBeforeCursor.lastIndexOf('.')) + ".lastnode);"),
]
for (const line of linesToCheck) {
try {
const lineAst = await this.props.plugin.call('codeParser', 'parseSolidity', line)
const lastNode = await this.props.plugin.call('codeParser', 'getLastNodeInLine', lineAst)
if(lastNode) {
lastNodeInExpression = lastNode
break
}
} catch (e) {
}
}
return lastNodeInExpression
}
} }

@ -16,22 +16,15 @@ export class RemixHoverProvider implements languages.HoverProvider {
const cursorPosition = this.props.editorAPI.getHoverPosition(position) const cursorPosition = this.props.editorAPI.getHoverPosition(position)
const nodeAtPosition = await this.props.plugin.call('contextualListener', 'definitionAtPosition', cursorPosition) const nodeAtPosition = await this.props.plugin.call('codeParser', 'definitionAtPosition', cursorPosition)
console.log(nodeAtPosition) console.log(nodeAtPosition)
const contents = [] const contents = []
const getDocs = async (node: any) => { const getDocs = async (node: any) => {
if (node.documentation && node.documentation.text) {
let text = ''
node.documentation.text.split('\n').forEach(line => {
text += `${line.trim()}\n`
})
contents.push({ contents.push({
value: await this.props.plugin.call('codeParser', 'getNodeDocumentation', node)
value: text
}) })
} }
}
const getScope = async (node: any) => { const getScope = async (node: any) => {
if (node.id) { if (node.id) {
@ -48,42 +41,25 @@ export class RemixHoverProvider implements languages.HoverProvider {
} }
const getLinks = async (node: any) => { const getLinks = async (node: any) => {
const position = await this.props.plugin.call('contextualListener', 'positionOfDefinition', node)
const lastCompilationResult = await this.props.plugin.call('contextualListener', 'getLastCompilationResult')
const filename = lastCompilationResult.getSourceName(position.file)
console.log(filename, position)
const lineColumn = await this.props.plugin.call('offsetToLineColumnConverter', 'offsetToLineColumn',
position,
position.file,
lastCompilationResult.getSourceCode().sources,
lastCompilationResult.getAsts())
contents.push({ contents.push({
value: `${filename} ${lineColumn.start.line}:${lineColumn.start.column}` value: await this.props.plugin.call('codeParser', 'getNodeLink', node)
}) })
} }
const getVariableDeclaration = async (node: any) => { const getVariableDeclaration = async (node: any) => {
if (node.typeDescriptions && node.typeDescriptions.typeString) { return await this.props.plugin.call('codeParser', 'getVariableDeclaration', node)
return `${node.typeDescriptions.typeString}${node.name && node.name.length ? ` ${node.name}` : ''}`
} else
if (node.typeName && node.typeName.name) {
return `${node.typeName.name}${node.name && node.name.length ? ` ${node.name}` : ''}`
} else {
return `${node.name && node.name.length ? ` ${node.name}` : ''}`
}
} }
const getParamaters = async (parameters: any) => { const getParamaters = async (node: any) => {
if (parameters && parameters.parameters) { return await this.props.plugin.call('codeParser', 'getFunctionParamaters', node)
let params = []
for (const param of parameters.parameters) {
params.push(await getVariableDeclaration(param))
}
return `(${params.join(', ')})`
} }
const getReturnParameters = async (node: any) => {
return await this.props.plugin.call('codeParser', 'getFunctionReturnParameters', node)
} }
const getOverrides = async (node: any) => { const getOverrides = async (node: any) => {
if (node.overrides) { if (node.overrides) {
let overrides = [] let overrides = []
@ -99,7 +75,7 @@ export class RemixHoverProvider implements languages.HoverProvider {
const getlinearizedBaseContracts = async (node: any) => { const getlinearizedBaseContracts = async (node: any) => {
let params = [] let params = []
for (const id of node.linearizedBaseContracts) { for (const id of node.linearizedBaseContracts) {
const baseContract = await this.props.plugin.call('contextualListener', 'getNodeById', id) const baseContract = await this.props.plugin.call('codeParser', 'getNodeById', id)
params.push( params.push(
baseContract.name baseContract.name
) )
@ -112,6 +88,8 @@ export class RemixHoverProvider implements languages.HoverProvider {
if (!nodeAtPosition) { if (!nodeAtPosition) {
contents.push({ contents.push({
value: 'Loading...' value: 'Loading...'
}, {
value: 'Compilation errors'
}) })
} }
@ -140,7 +118,7 @@ export class RemixHoverProvider implements languages.HoverProvider {
} else if (nodeAtPosition.nodeType === 'FunctionDefinition') { } else if (nodeAtPosition.nodeType === 'FunctionDefinition') {
contents.push({ contents.push({
value: `function ${nodeAtPosition.name} ${await getParamaters(nodeAtPosition.parameters)} ${nodeAtPosition.visibility} ${nodeAtPosition.stateMutability}${await getOverrides(nodeAtPosition)} returns ${await getParamaters(nodeAtPosition.returnParameters)}` value: `function ${nodeAtPosition.name} ${await getParamaters(nodeAtPosition)} ${nodeAtPosition.visibility} ${nodeAtPosition.stateMutability}${await getOverrides(nodeAtPosition)} returns ${await getReturnParameters(nodeAtPosition)}`
}) })
@ -149,7 +127,10 @@ export class RemixHoverProvider implements languages.HoverProvider {
value: `${nodeAtPosition.contractKind} ${nodeAtPosition.name} ${await getlinearizedBaseContracts(nodeAtPosition)}` value: `${nodeAtPosition.contractKind} ${nodeAtPosition.name} ${await getlinearizedBaseContracts(nodeAtPosition)}`
}) })
} else if (nodeAtPosition.nodeType === 'InvalidNode') {
contents.push({
value: `Parsing error found!`
})
} else { } else {
contents.push({ contents.push({
value: `${nodeAtPosition.nodeType}` value: `${nodeAtPosition.nodeType}`

@ -11,10 +11,10 @@ export class RemixReferenceProvider {
async provideReferences(model: any, position: any, context: any, token: any) { async provideReferences(model: any, position: any, context: any, token: any) {
const cursorPosition = this.props.editorAPI.getCursorPosition() const cursorPosition = this.props.editorAPI.getCursorPosition()
const nodes = await this.props.plugin.call('contextualListener', 'referrencesAtPosition', cursorPosition) const nodes = await this.props.plugin.call('codeParser', 'referrencesAtPosition', cursorPosition)
const references = [] const references = []
if (nodes && nodes.length) { if (nodes && nodes.length) {
const compilationResult = await this.props.plugin.call('contextualListener', 'getLastCompilationResult') const compilationResult = await this.props.plugin.call('codeParser', 'getLastCompilationResult')
const file = await this.props.plugin.call('fileManager', 'file') const file = await this.props.plugin.call('fileManager', 'file')
if (compilationResult && compilationResult.data && compilationResult.data.sources[file]) { if (compilationResult && compilationResult.data && compilationResult.data.sources[file]) {
for (const node of nodes) { for (const node of nodes) {

@ -74,7 +74,7 @@ export interface EditorUIProps {
findMatches: (uri: string, value: string) => any findMatches: (uri: string, value: string) => any
getFontSize: () => number, getFontSize: () => number,
getValue: (uri: string) => string getValue: (uri: string) => string
getCursorPosition: () => cursorPosition getCursorPosition: () => number
getHoverPosition: (position: IPosition) => number getHoverPosition: (position: IPosition) => number
addDecoration: (marker: sourceMarker, filePath: string, typeOfDecoration: string) => DecorationsReturn addDecoration: (marker: sourceMarker, filePath: string, typeOfDecoration: string) => DecorationsReturn
addErrorMarker: (errors: []) => void addErrorMarker: (errors: []) => void
@ -541,7 +541,7 @@ export const EditorUI = (props: EditorUIProps) => {
onCurrentFileChanged={(listener) => { props.plugin.on('fileManager', 'currentFileChanged', listener) }} onCurrentFileChanged={(listener) => { props.plugin.on('fileManager', 'currentFileChanged', listener) }}
getActiveHighlights={() => { return props.plugin.call('contextualListener', 'getActiveHighlights') }} getActiveHighlights={() => { return props.plugin.call('contextualListener', 'getActiveHighlights') }}
gasEstimation={(node: astNode) => { return props.plugin.call('contextualListener', 'gasEstimation', node) }} gasEstimation={(node: astNode) => { return props.plugin.call('contextualListener', 'gasEstimation', node) }}
declarationOf={(node: astNode) => { return props.plugin.call('contextualListener', 'declarationOf', node) }} declarationOf={(node: astNode) => { return props.plugin.call('codeParser', 'declarationOf', node) }}
/> />
</div> </div>
</div> </div>

@ -7249,15 +7249,10 @@ caniuse-api@^3.0.0:
lodash.memoize "^4.1.2" lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0" lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30001030, caniuse-lite@^1.0.30001264: caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30001030, caniuse-lite@^1.0.30001264, caniuse-lite@^1.0.30001272, caniuse-lite@^1.0.30001286:
version "1.0.30001265" version "1.0.30001356"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz#0613c9e6c922e422792e6fcefdf9a3afeee4f8c3" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001356.tgz"
integrity sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw== integrity sha512-/30854bktMLhxtjieIxsrJBfs2gTM1pel6MXKF3K+RdIVJZcsn2A2QdhsuR4/p9+R204fZw0zCBBhktX8xWuyQ==
caniuse-lite@^1.0.30001272, caniuse-lite@^1.0.30001286:
version "1.0.30001287"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001287.tgz#5fab6a46ab9e47146d5dd35abfe47beaf8073c71"
integrity sha512-4udbs9bc0hfNrcje++AxBuc6PfLNHwh3PO9kbwnfCQWyqtlzg3py0YgFu8jyRTTo85VAz4U+VLxSlID09vNtWA==
capital-case@^1.0.4: capital-case@^1.0.4:
version "1.0.4" version "1.0.4"
@ -9550,7 +9545,7 @@ ent@~2.2.0:
resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d"
integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0=
entities@^2.0.0: entities@^2.0.0, entities@^2.0.3:
version "2.2.0" version "2.2.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
@ -14921,7 +14916,7 @@ loader-utils@^1.0.0, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2
emojis-list "^3.0.0" emojis-list "^3.0.0"
json5 "^1.0.1" json5 "^1.0.1"
loader-utils@^2.0.0, loader-utils@^2.0.2: loader-utils@^2.0.0:
version "2.0.2" version "2.0.2"
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129"
integrity sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A== integrity sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==
@ -16142,13 +16137,6 @@ mold-source-map@~0.4.0:
convert-source-map "^1.1.0" convert-source-map "^1.1.0"
through "~2.2.7" through "~2.2.7"
monaco-editor-webpack-plugin@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-7.0.1.tgz#ba19c60aba990184e36ad8722b1ed6a564527c7c"
integrity sha512-M8qIqizltrPlIbrb73cZdTWfU9sIsUVFvAZkL3KGjAHmVWEJ0hZKa/uad14JuOckc0GwnCaoGHvMoYtJjVyCzw==
dependencies:
loader-utils "^2.0.2"
monaco-editor@^0.30.1: monaco-editor@^0.30.1:
version "0.30.1" version "0.30.1"
resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.30.1.tgz#47f8d18a0aa2264fc5654581741ab8d7bec01689" resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.30.1.tgz#47f8d18a0aa2264fc5654581741ab8d7bec01689"
@ -18230,6 +18218,11 @@ pbkdf2@^3.0.17, pbkdf2@^3.0.3:
safe-buffer "^5.0.1" safe-buffer "^5.0.1"
sha.js "^2.4.8" sha.js "^2.4.8"
pegjs@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/pegjs/-/pegjs-0.10.0.tgz#cf8bafae6eddff4b5a7efb185269eaaf4610ddbd"
integrity sha512-qI5+oFNEGi3L5HAxDwN2LA4Gg7irF70Zs25edhjld9QemOgp0CbvMtbFcMvFtEo1OityPrcCzkQFB8JP/hxgow==
pend@~1.2.0: pend@~1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
@ -20209,6 +20202,14 @@ rollup@1.31.1:
"@types/node" "*" "@types/node" "*"
acorn "^7.1.0" acorn "^7.1.0"
rss-parser@^3.12.0:
version "3.12.0"
resolved "https://registry.yarnpkg.com/rss-parser/-/rss-parser-3.12.0.tgz#b8888699ea46304a74363fbd8144671b2997984c"
integrity sha512-aqD3E8iavcCdkhVxNDIdg1nkBI17jgqF+9OqPS1orwNaOgySdpvq6B+DoONLhzjzwV8mWg37sb60e4bmLK117A==
dependencies:
entities "^2.0.3"
xml2js "^0.4.19"
rsvp@^4.8.4: rsvp@^4.8.4:
version "4.8.5" version "4.8.5"
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
@ -20339,7 +20340,7 @@ sax@0.5.x:
resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1" resolved "https://registry.yarnpkg.com/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1"
integrity sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE= integrity sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=
sax@~1.2.4: sax@>=0.6.0, sax@~1.2.4:
version "1.2.4" version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
@ -20931,6 +20932,14 @@ solc@0.7.4:
semver "^5.5.0" semver "^5.5.0"
tmp "0.0.33" tmp "0.0.33"
solparse-exp-jb@^2.2.23:
version "2.2.23"
resolved "https://registry.yarnpkg.com/solparse-exp-jb/-/solparse-exp-jb-2.2.23.tgz#a46facb5546bc37ef64de4f1ce17b6ccb56d7ed4"
integrity sha512-LCU3C6IKrXu+C8ORBuNGD0JHyxhwNsSqF65YqnqGXrCi8KjfOQcrA4gliGZp/E0jtQl43O19as/ay1NnzLvOpQ==
dependencies:
pegjs "^0.10.0"
yargs "^10.0.3"
sort-keys@^1.0.0: sort-keys@^1.0.0:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
@ -24093,6 +24102,19 @@ xml-name-validator@^3.0.0:
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==
xml2js@^0.4.19:
version "0.4.23"
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66"
integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==
dependencies:
sax ">=0.6.0"
xmlbuilder "~11.0.0"
xmlbuilder@~11.0.0:
version "11.0.1"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3"
integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==
xmlchars@^2.2.0: xmlchars@^2.2.0:
version "2.2.0" version "2.2.0"
resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"

Loading…
Cancel
Save