Skip to content

Commit

Permalink
Add missing TypeScript types and general cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
MadsHL committed Feb 20, 2024
1 parent 5945a75 commit 3b89c6b
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 12 deletions.
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dasmaql-svelte",
"version": "0.2.1",
"version": "0.2.2",
"description": "A Svelte component providing an example of how DasmaQL can be utilized. DasmaQL is a lightweight query language used for data retrieval.",
"scripts": {
"dev": "vite dev",
Expand Down Expand Up @@ -29,7 +29,7 @@
"svelte": "^4.0.0"
},
"dependencies": {
"dasmaql": "^0.2.1"
"dasmaql": "^0.2.17"
},
"devDependencies": {
"@sveltejs/adapter-auto": "^3.0.0",
Expand Down
20 changes: 20 additions & 0 deletions src/lib/DasmaAutocomplete.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import type { MouseEventHandler } from 'svelte/elements';
import { onMount } from 'svelte';
export let suggestions: string[] = [];
export let position = { x: 0, y: 0 };
Expand All @@ -15,6 +16,8 @@
const selectedIndex = Array.from(menuElement.children).indexOf(<Element>event.target);
if (selectedIndex !== -1 && selectedIndex < suggestions.length) {
selectedSuggestion = getKey(suggestions[selectedIndex]);
} else {
visible = false;
}
};
export const handleKeyEvent = (event: KeyboardEvent) => {
Expand Down Expand Up @@ -49,6 +52,22 @@
}
return '';
};
onMount(() => {
document.addEventListener('click', (event: MouseEvent) => {
const targetElement = event.target;
if (
targetElement instanceof HTMLElement &&
!targetElement.classList.contains('dasma-suggestion')
) {
selectedIndex = -1;
suggestions = [];
selectedSuggestion = '';
visible = false;
}
});
});
</script>

{#if visible}
Expand All @@ -65,6 +84,7 @@
tabindex={index}
class:selected={index === selectedIndex}
on:click={handleMouseClick}
class="dasma-suggestion"
>
{getLabel(suggestion)}
</li>
Expand Down
25 changes: 22 additions & 3 deletions src/lib/DasmaQl.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@
import { onMount } from 'svelte';
import DasmaAutocomplete from '$lib/DasmaAutocomplete.svelte';
import type { FormEventHandler, KeyboardEventHandler, MouseEventHandler } from 'svelte/elements';
import { dasmaQlAutocomplete, dasmaQlHighlighter } from 'dasmaql';
import {
dasmaQlAutocomplete,
type QlAutocomplete
} from 'dasmaql/src/modules/dasmaQlAutocomplete';
import { dasmaQlHighlighter, type QlHighlighter } from 'dasmaql/src/modules/dasmaQlHighlighter';
import { dasmaQlSyntax, type QlSyntax, type QlModel } from 'dasmaql/src/modules/dasmaQlSyntax';
export let fields: string[] = [];
export let callbackSearch: (
Expand All @@ -14,8 +19,9 @@
return [];
};
let autocomplete: dasmaQlAutocomplete;
let highlighter: dasmaQlHighlighter;
let autocomplete: QlAutocomplete;
let highlighter: QlHighlighter;
let syntaxModel: QlSyntax;
const debounceHighlighter = debouncer(200);
const debounceAutocomplete = debouncer(400);
Expand All @@ -33,6 +39,16 @@
let currentPosition = 0;
let selectedIndex = -1;
export const generateModel: () => QlModel = () => {
const input = outputContainer.innerText.trim();
const model: QlModel = syntaxModel.parse(input);
if (model.validation?.error?.location.start) {
CaretHandler.setCaretPosition(outputContainer, model.validation.error.location.start.offset);
}
return model;
};
const handleInputChange: FormEventHandler<HTMLDivElement> = (event) => {
const input = getInputTextContent(event);
if (input !== lastQl) {
Expand Down Expand Up @@ -149,6 +165,9 @@
fields: fields,
callbackSearchParameter: callbackSearch
});
syntaxModel = dasmaQlSyntax({
fields: fields
});
});
</script>

Expand Down
101 changes: 100 additions & 1 deletion src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import { DasmaQl } from '$lib';
import { levenshteinSearchSort } from 'dasmaql/src/modules/levenshteinDistance';
import { type QlModel } from 'dasmaql/src/modules/dasmaQlSyntax';
interface DummyData {
[key: string]: { key: string; label: string }[];
Expand Down Expand Up @@ -140,13 +141,111 @@
]
};
function syntaxHighlight(jsonObject: QlModel) {
try {
return JSON.stringify(jsonObject, null, 2)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(
/("(\\u[a-zA-Z0-9]{4}|\\[^\\]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g,
(match) => {
let cls = 'json-number';
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = 'json-key';
} else {
cls = 'json-string';
}
} else if (/true|false/.test(match)) {
cls = 'json-boolean';
} else if (/null/.test(match)) {
cls = 'json-null';
}
return '<span class="' + cls + '">' + match + '</span>';
}
);
} catch (error) {
console.error('Invalid JSON:', error);
return '';
}
}
const fields = Object.keys(dummyData);
let qlModel: QlModel;
let generateModel: () => QlModel;
const callbackSearch = (field: string, search: string): (string | { label: string })[] => {
const values = dummyData[field.toLowerCase()];
return levenshteinSearchSort(values, search).slice(0, 10);
};
let outputModel = () => {
qlModel = generateModel();
};
</script>

<DasmaQl {fields} {callbackSearch} />
<DasmaQl {fields} {callbackSearch} bind:generateModel />
<button on:click={outputModel}>Try me out!</button>
<br />
<div class="json-output">
<pre>
{@html qlModel ? syntaxHighlight(qlModel) : ''}
</pre>
</div>

<style>
button {
background-color: #4caf50;
color: white;
padding: 20px 40px;
border: none;
cursor: pointer;
border-radius: 10px;
font-size: 20px;
display: block;
margin: 20px auto;
}
button:hover {
background-color: #45a049;
}
.json-output {
overflow: auto;
font-family: monospace;
width: calc(100% - 40px);
padding: 12px;
margin: 12px;
border: 1px solid #ccc;
border-radius: 4px;
resize: vertical;
font-size: 14px;
height: calc(100vh - 250px);
background-color: #f8f8f8;
}
:global(.json-string) {
color: green;
}
:global(.json-number) {
color: blue;
}
:global(.json-boolean) {
color: orange;
}
:global(.json-null) {
color: grey;
}
:global(.json-key) {
color: brown;
}
</style>
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
Expand Down

0 comments on commit 3b89c6b

Please sign in to comment.