Skip to content

Commit f372e7a

Browse files
committed
working on initial linting plugin
1 parent 89a769b commit f372e7a

File tree

6 files changed

+57
-3
lines changed

6 files changed

+57
-3
lines changed

packages/components/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"@codemirror/lang-yaml": "^6.1.2",
4040
"@codemirror/language": "^6.10.3",
4141
"@codemirror/legacy-modes": "^6.4.2",
42+
"@codemirror/lint": "^6.8.4",
4243
"@codemirror/state": "^6.5.0",
4344
"@codemirror/view": "^6.36.2",
4445
"@ember/render-modifiers": "^2.1.0",

packages/components/src/components/hds/code-editor/index.hbs

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
ariaLabel=@ariaLabel
5757
ariaLabelledBy=this.ariaLabelledBy
5858
hasLineWrapping=@hasLineWrapping
59+
isLintingEnabled=@isLintingEnabled
5960
language=@language
6061
value=@value
6162
onBlur=@onBlur

packages/components/src/modifiers/hds-code-editor.ts

+45-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import type {
2121
StreamLanguage as StreamLanguageType,
2222
StreamParser as StreamParserType,
2323
} from '@codemirror/language';
24+
import type { Diagnostic } from '@codemirror/lint';
2425
import type { Extension } from '@codemirror/state';
2526
import type {
2627
EditorView as EditorViewType,
@@ -40,6 +41,7 @@ export interface HdsCodeEditorSignature {
4041
ariaLabel?: string;
4142
ariaLabelledBy?: string;
4243
hasLineWrapping?: boolean;
44+
isLintingEnabled?: boolean;
4345
language?: HdsCodeEditorLanguages;
4446
value?: string;
4547
onInput?: (newVal: string) => void;
@@ -273,7 +275,7 @@ export default class HdsCodeEditorModifier extends Modifier<HdsCodeEditorSignatu
273275

274276
private _buildExtensionsTask = task(
275277
{ drop: true },
276-
async ({ language, hasLineWrapping }) => {
278+
async ({ language, hasLineWrapping, isLintingEnabled }) => {
277279
const [
278280
{
279281
keymap,
@@ -314,6 +316,35 @@ export default class HdsCodeEditorModifier extends Modifier<HdsCodeEditorSignatu
314316
hasLineWrapping ? EditorView.lineWrapping : []
315317
);
316318

319+
let lintingExtensions: Extension[] = [];
320+
321+
if (isLintingEnabled && language === 'json') {
322+
const [{ linter, lintGutter }, { syntaxTree }] = await Promise.all([
323+
import('@codemirror/lint'),
324+
import('@codemirror/language'),
325+
]);
326+
327+
lintingExtensions = [
328+
linter((view): Diagnostic[] => {
329+
const diagnostics: Diagnostic[] = [];
330+
try {
331+
JSON.parse(view.state.doc.toString());
332+
} catch (error: any) {
333+
const message = error.message;
334+
const pos = error.position || 0;
335+
diagnostics.push({
336+
from: pos,
337+
to: pos + 1,
338+
severity: 'error',
339+
message,
340+
});
341+
}
342+
return diagnostics;
343+
}),
344+
lintGutter(),
345+
];
346+
}
347+
317348
let extensions = [
318349
lineWrappingExtension,
319350
bracketMatching(),
@@ -334,6 +365,10 @@ export default class HdsCodeEditorModifier extends Modifier<HdsCodeEditorSignatu
334365
extensions = [languageExtension, ...extensions];
335366
}
336367

368+
if (lintingExtensions.length !== 0) {
369+
extensions = [...extensions, ...lintingExtensions];
370+
}
371+
337372
return extensions;
338373
}
339374
);
@@ -343,18 +378,20 @@ export default class HdsCodeEditorModifier extends Modifier<HdsCodeEditorSignatu
343378
async (
344379
element: HTMLElement,
345380
{
381+
isLintingEnabled,
346382
language,
347383
value,
348384
hasLineWrapping,
349385
}: Pick<
350386
HdsCodeEditorSignature['Args']['Named'],
351-
'language' | 'value' | 'hasLineWrapping'
387+
'language' | 'value' | 'hasLineWrapping' | 'isLintingEnabled'
352388
>
353389
) => {
354390
try {
355391
const { EditorState } = await import('@codemirror/state');
356392

357393
const extensions = await this._buildExtensionsTask.perform({
394+
isLintingEnabled,
358395
language,
359396
hasLineWrapping: hasLineWrapping ?? false,
360397
});
@@ -393,6 +430,7 @@ export default class HdsCodeEditorModifier extends Modifier<HdsCodeEditorSignatu
393430
ariaLabel,
394431
ariaLabelledBy,
395432
hasLineWrapping,
433+
isLintingEnabled,
396434
language,
397435
value,
398436
} = named;
@@ -403,6 +441,7 @@ export default class HdsCodeEditorModifier extends Modifier<HdsCodeEditorSignatu
403441
this.element = element;
404442

405443
const editor = await this._createEditorTask.perform(element, {
444+
isLintingEnabled,
406445
language,
407446
value,
408447
hasLineWrapping,
@@ -424,6 +463,10 @@ export default class HdsCodeEditorModifier extends Modifier<HdsCodeEditorSignatu
424463
ariaLabelledBy,
425464
});
426465

466+
this.editor.dispatch({
467+
changes: { from: 0, to: 0, insert: ' ' },
468+
});
469+
427470
onSetup?.(this.editor);
428471
}
429472
);

pnpm-lock.yaml

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

showcase/app/controllers/components/code-editor.js

+1
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ sayMessage();
9696
{
9797
value: 'json',
9898
label: 'JSON',
99+
isLintingEnabled: true,
99100
code: `{
100101
"message": "Hello, world!",
101102
"status": "success",

showcase/app/templates/components/code-editor.hbs

+6-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,12 @@
121121
<Shw::Flex @direction="column" as |SF|>
122122
{{#each this.languages as |lang|}}
123123
<SF.Item @label={{lang.label}}>
124-
<Hds::CodeEditor @language={{lang.value}} @value={{lang.code}} as |CE|>
124+
<Hds::CodeEditor
125+
@language={{lang.value}}
126+
@value={{lang.code}}
127+
@isLintingEnabled={{lang.isLintingEnabled}}
128+
as |CE|
129+
>
125130
<CE.Title>{{lang.label}}</CE.Title>
126131
</Hds::CodeEditor>
127132
</SF.Item>

0 commit comments

Comments
 (0)