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

Support dialects #53

Merged
merged 2 commits into from
Jun 4, 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
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,16 @@ const editor = new FeelEditor({
});
```

Optionally, you can provide a starting document and listen for changes:
Configure the FEEL dialect (expression or unary tests):

```JavaScript
const editor = new FeelEditor({
container,
dialect: 'unaryTests' // defaults to 'expression'
});
```

You can provide a starting document and listen for changes:

```JavaScript
const editor = new FeelEditor({
Expand Down
6 changes: 5 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const placeholderConf = new Compartment();
* @param {Object} config
* @param {DOMNode} config.container
* @param {Extension[]} [config.extensions]
* @param {'expression' | 'unaryTests'} [config.dialect='expression']
* @param {DOMNode|String} [config.tooltipContainer]
* @param {Function} [config.onChange]
* @param {Function} [config.onKeyDown]
Expand All @@ -44,6 +45,7 @@ const placeholderConf = new Compartment();
*/
export default function FeelEditor({
extensions: editorExtensions = [],
dialect = 'expression',
container,
contentAttributes = {},
tooltipContainer,
Expand Down Expand Up @@ -104,7 +106,9 @@ export default function FeelEditor({
keymap.of([
...defaultKeymap,
]),
language(),
language({
dialect
}),
linter,
lintHandler,
placeholderConf.of(placeholderExt(placeholder)),
Expand Down
12 changes: 8 additions & 4 deletions src/language/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { LanguageSupport } from '@codemirror/language';
import { feelLanguage } from 'lang-feel';
import { feel } from 'lang-feel';

export function language() {
return new LanguageSupport(feelLanguage, [ ]);
/**
* @param {'expression' | 'unaryTests'} dialect
*
* @return {LanguageSupport}
*/
export function language(dialect) {
return feel(dialect);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@barmac @marstamm I was not aware why we'd not use the built-in utilities to configure the language support (which already supports the two dialects).

Do you know? Doing manual testing I did not find anything broken.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My wild guess is that this part predates the support in the language. I wasn't involved in the development at the stage it was created though.

}
170 changes: 103 additions & 67 deletions test/spec/CodeEditor.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,22 @@ return
});


it('should configure <unaryTests> dialect', async function() {

// when
const initialValue = '"Hello", "World"';
const editor = new FeelEditor({
container,
value: initialValue,
dialect: 'unaryTests'
});

// then
expect(editor).to.exist;
expect(editor._cmEditor.state.doc.toString()).to.equal('"Hello", "World"');
});


it('should allow for extensions', async function() {

// when
Expand Down Expand Up @@ -497,129 +513,124 @@ return

describe('lint', function() {

it('should not highlight empty document', function(done) {
it('should not highlight empty document', async function() {
const initalValue = '';

const editor = new FeelEditor({
container,
value: initalValue
});

const cm = getCm(editor);

// when
forceLinting(cm);
const diagnostics = await lint(editor);

// then
// update done async
setTimeout(() => {
expect(diagnosticCount(cm.state)).to.eql(0);
done();
}, 0);
expect(diagnostics).to.eql(0);
});


describe('should not highlight valid', function() {

[
{ dialect: 'expression', value: 'Mike < 10' },
{ dialect: 'unaryTests', value: '12, now(), "STRING"' }
].forEach(({ dialect, value }) => {

it(`<${dialect}>`, async function() {

// given
const editor = new FeelEditor({
container,
value,
dialect
});

// when
const diagnostics = await lint(editor);

// then
expect(diagnostics).to.eql(0);
});

});

});


it('should highlight unexpected operations', function(done) {
it('should highlight unexpected operations', async function() {
const initalValue = '= 15';

const editor = new FeelEditor({
container,
value: initalValue
});

const cm = getCm(editor);

// when
forceLinting(cm);
const diagnostics = await lint(editor);

// then
// update done async
setTimeout(() => {
expect(diagnosticCount(cm.state)).to.eql(1);
done();
}, 0);

expect(diagnostics).to.eql(1);
});


it('should highlight missing operations', function(done) {
it('should highlight missing operations', async function() {
const initalValue = '15 == 15';

const editor = new FeelEditor({
container,
value: initalValue
});

const cm = getCm(editor);

// when
forceLinting(cm);
const diagnostics = await lint(editor);

// then
// update done async
setTimeout(() => {
expect(diagnosticCount(cm.state)).to.eql(1);
done();
}, 0);

expect(diagnostics).to.eql(1);
});


it('should call onLint with errors', function(done) {
const initalValue = '= 15';
const onLint = sinon.spy();
describe('should call onLint', function() {

const editor = new FeelEditor({
container,
value: initalValue,
onLint
});
it('with errors', async function() {

const cm = getCm(editor);
const initalValue = '= 15';
const onLint = sinon.spy();

// when
forceLinting(cm);
const editor = new FeelEditor({
container,
value: initalValue,
onLint
});

// then
// update done async
setTimeout(() => {
// when
await lint(editor);

// then
expect(onLint).to.have.been.calledOnce;
expect(onLint).to.have.been.calledWith(sinon.match.array);
expect(onLint.args[0][0]).to.have.length(1);

done();
}, 0);

});


it('should call onLint without errors', function(done) {
const initalValue = '15';
const onLint = sinon.spy();

const editor = new FeelEditor({
container,
value: initalValue,
onLint
});

const cm = getCm(editor);

// when
forceLinting(cm);
it('without errors', async function() {
const initalValue = '15';
const onLint = sinon.spy();

// then
// update done async
setTimeout(() => {
const editor = new FeelEditor({
container,
value: initalValue,
onLint
});

// when
await lint(editor);

// then
// update done async
expect(onLint).to.have.been.calledOnce;
expect(onLint).to.have.been.calledWith(sinon.match.array);
expect(onLint.args[0][0]).to.have.length(0);

done();
}, 0);
});

});

Expand Down Expand Up @@ -884,6 +895,11 @@ function select(editor, anchor, head = anchor) {
});
}

/**
* @param {FeelEditor} editor
*
* @return {import('@codemirror/view').EditorView}
*/
function getCm(editor) {
return editor._cmEditor || editor;
}
Expand All @@ -906,3 +922,23 @@ async function expectEventually(fn) {

throw e;
}

function wait(ms = 0) {
return new Promise(resolve => setTimeout(resolve, ms));
}

/**
* @param {FeelEditor} editor
*
* @return {Promise<number>}
*/
async function lint(editor) {
const cm = getCm(editor);

// when
forceLinting(cm);

await wait();

return diagnosticCount(cm.state);
}
Loading