Skip to content

Commit cf71058

Browse files
committed
parse code with babel and warn when blacklisted function focused
1 parent 9c4bc52 commit cf71058

File tree

5 files changed

+104
-14
lines changed

5 files changed

+104
-14
lines changed

client/modules/IDE/components/Editor/index.jsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -464,19 +464,31 @@ class Editor extends React.Component {
464464
// JavaScript
465465
CodeMirror.showHint(
466466
_cm,
467-
(cm, options) => contextAwareHinter(cm, { hinter: this.hinter }),
467+
() => {
468+
const c = _cm.getCursor();
469+
const token = _cm.getTokenAt(c);
470+
const hints = contextAwareHinter(_cm, { hinter: this.hinter });
471+
console.log('hints= ', hints);
472+
return {
473+
list: hints,
474+
from: CodeMirror.Pos(c.line, token.start),
475+
to: CodeMirror.Pos(c.line, c.ch)
476+
};
477+
},
468478
hintOptions
469479
);
480+
470481
// CodeMirror.showHint(
471482
// _cm,
472483
// () => {
473484
// const c = _cm.getCursor();
474485
// const token = _cm.getTokenAt(c);
475-
476486
// const hints = this.hinter
477487
// .search(token.string)
478488
// .filter((h) => h.item.text[0] === token.string[0]);
479-
489+
// console.log('c= ', c);
490+
// console.log('token= ', token);
491+
// console.log('hints= ', hints);
480492
// return {
481493
// list: hints,
482494
// from: CodeMirror.Pos(c.line, token.start),

client/modules/IDE/components/parseCode.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
// parseCode.js
2-
// import * as acorn from 'acorn';
3-
// import * as walk from 'acorn-walk';
41
const acorn = require('acorn');
52
const walk = require('acorn-walk');
63

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// parseCodeWithBabel.js
2+
const parser = require('@babel/parser');
3+
const traverse = require('@babel/traverse').default;
4+
5+
export default function parseCode(_cm) {
6+
const code = _cm.getValue();
7+
const cursor = _cm.getCursor();
8+
const offset = _cm.indexFromPos(cursor);
9+
10+
let ast;
11+
try {
12+
ast = parser.parse(code, {
13+
sourceType: 'script',
14+
plugins: ['jsx', 'typescript'] // add plugins as needed
15+
});
16+
} catch (e) {
17+
console.warn('Failed to parse code with Babel:', e.message);
18+
return 'global';
19+
}
20+
21+
let context = 'global';
22+
23+
traverse(ast, {
24+
Function(path) {
25+
const { node } = path;
26+
if (offset >= node.start && offset <= node.end) {
27+
if (node.id && node.id.name) {
28+
context = node.id.name;
29+
} else {
30+
const parent = path.parentPath.node;
31+
if (
32+
parent.type === 'VariableDeclarator' &&
33+
parent.id.type === 'Identifier'
34+
) {
35+
context = parent.id.name;
36+
} else {
37+
context = '(anonymous)';
38+
}
39+
}
40+
path.stop(); // Stop traversal once we found the function context
41+
}
42+
}
43+
});
44+
45+
return context;
46+
}

client/modules/IDE/components/show-hint.js

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
// The second function (inside) contains the actual implementation.
1212
import parseCode from './parseCode';
1313
import CodeMirror from 'codemirror';
14+
import warnIfBlacklisted from './warn';
1415

1516
(function (mod) {
1617
if (typeof exports == 'object' && typeof module == 'object')
@@ -32,7 +33,7 @@ import CodeMirror from 'codemirror';
3233
// This is the old interface, kept around for now to stay
3334
// backwards-compatible.
3435
CodeMirror.showHint = function (cm, getHints, options) {
35-
console.log('showhint was called: ', getHints, options);
36+
console.log('showhint was called: ', cm, getHints, options);
3637
if (!getHints) return cm.showHint(options); // if not getHints function passed, it assumes youre using the newer interface
3738
// restructured options to call the new c.showHint() method
3839
if (options && options.async) getHints.async = true;
@@ -47,6 +48,7 @@ import CodeMirror from 'codemirror';
4748
// this adds a method called showHint to every cm editor instance (editor.showHint())
4849
CodeMirror.defineExtension('showHint', function (options) {
4950
options = parseOptions(this, this.getCursor('start'), options);
51+
console.log('options are: ');
5052
var selections = this.listSelections();
5153
console.log('selections are: ', selections);
5254
if (selections.length > 1) return;
@@ -131,17 +133,27 @@ import CodeMirror from 'codemirror';
131133

132134
pick: function (data, i) {
133135
// selects an item from the suggestion list
136+
console.log('data, i= ', data, i);
134137
var completion = data.list[i],
135138
self = this;
139+
136140
this.cm.operation(function () {
137-
if (completion.hint) completion.hint(self.cm, data, completion);
138-
else
141+
// this is how cm allows custom behavior per suggestion
142+
// if hint is provided on a hint object, it will be called instead of the default replace range
143+
const name = completion.item?.text;
144+
if (name) warnIfBlacklisted(self.cm, name);
145+
146+
if (completion.hint) {
147+
completion.hint(self.cm, data, completion);
148+
} else {
149+
console.log('gettext(C)= ', getText(completion));
139150
self.cm.replaceRange(
140151
getText(completion),
141152
completion.from || data.from,
142153
completion.to || data.to,
143154
'complete'
144155
);
156+
}
145157
// signals that a hint was picked and scrolls to it
146158
CodeMirror.signal(data, 'pick', completion);
147159
self.cm.scrollIntoView();
@@ -232,6 +244,7 @@ import CodeMirror from 'codemirror';
232244
}
233245
// extracts the visible text from a completion entry
234246
function getText(completion) {
247+
console.log('gettext called');
235248
if (typeof completion === 'string') return completion;
236249
else return completion.item.text;
237250
}
@@ -328,8 +341,10 @@ ${
328341
}</p>`;
329342
}
330343

331-
function getInlineHintSuggestion(focus, tokenLength) {
332-
console.log('the focus is: ', focus, tokenLength);
344+
function getInlineHintSuggestion(cm, focus, tokenLength) {
345+
const name = focus.item?.text;
346+
console.log('the focus is: ', focus, name);
347+
if (name) warnIfBlacklisted(cm, name);
333348
const suggestionItem = focus.item;
334349
// builds the remainder of the suggestion excluding what user already typed
335350
const baseCompletion = `<span class="inline-hinter-suggestion">${suggestionItem.text.slice(
@@ -365,6 +380,7 @@ ${
365380

366381
if (token && focus.item) {
367382
const suggestionHTML = getInlineHintSuggestion(
383+
cm,
368384
focus,
369385
token.string.length
370386
);
@@ -380,8 +396,8 @@ ${
380396
}
381397
}
382398

383-
// defines the autocomplete dropdown ui
384-
// completition = the autocomplete context having cm and options
399+
// defines the autocomplete dropdown ui; renders the suggestions
400+
// completion = the autocomplete context having cm and options
385401
// data = object with the list of suggestions
386402
function Widget(completion, data) {
387403
console.log('widget completetition= ', completion);
@@ -409,7 +425,6 @@ ${
409425
changeInlineHint(cm, data.list[this.selectedHint]);
410426

411427
var completions = data.list;
412-
413428
for (var i = 0; i < completions.length; ++i) {
414429
var elt = hints.appendChild(ownerDocument.createElement('li')),
415430
cur = completions[i];
@@ -427,6 +442,7 @@ ${
427442
const name = getText(cur);
428443

429444
if (cur.item && cur.item.type) {
445+
console.log('display hint calllllled');
430446
cur.displayText = displayHint(name, cur.item.type, cur.item.p5);
431447
}
432448

client/modules/IDE/components/warn.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import parseCode from './parseCode';
2+
3+
const scopeMap = require('./finalScopeMap.json');
4+
5+
/**
6+
* Checks if a completion is blacklisted in the current context and logs a warning if so.
7+
* @param {CodeMirror.Editor} cm - The CodeMirror instance
8+
* @param {string} text - The name of the selected function
9+
*/
10+
export default function warnIfBlacklisted(cm, text) {
11+
const context = parseCode(cm);
12+
const blacklist = scopeMap[context]?.blacklist || [];
13+
14+
if (blacklist.includes(text)) {
15+
console.warn(
16+
`⚠️ Function "${text}" is usually not used in "${context}" context. Please be careful.`
17+
);
18+
}
19+
}

0 commit comments

Comments
 (0)