Skip to content

Commit

Permalink
Add demo for the UI that uses Kotlin/JS- and Kotlin/WASM-based CQL pa…
Browse files Browse the repository at this point in the history
…rser
  • Loading branch information
antvaset committed Nov 8, 2024
1 parent 31a19dc commit 3522f23
Show file tree
Hide file tree
Showing 15 changed files with 5,485 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,16 @@ kotlin {
generateTypeScriptDefinitions()
}

// Add Kotlin/WASM compilation target.
// The output is in the JS packages directory.
wasmJs {
browser { }
binaries.executable()
generateTypeScriptDefinitions()
}

sourceSets {
commonMain{
commonMain {
dependencies {
implementation(kotlin("stdlib-common"))
}
Expand Down
16 changes: 16 additions & 0 deletions Src/java/cql/src/commonMain/kotlin/main.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import org.antlr.v4.kotlinruntime.CharStream
import org.antlr.v4.kotlinruntime.CharStreams
import org.antlr.v4.kotlinruntime.CommonTokenStream
import org.cqframework.cql.gen.cqlLexer
import org.cqframework.cql.gen.cqlParser
import kotlin.js.JsExport

@JsExport
fun parseToTree(logic: String): String {
val input: CharStream = CharStreams.fromString(logic)
val tokens = CommonTokenStream(cqlLexer(input))
val parser = cqlParser(tokens)
parser.buildParseTree = true
val library = parser.library()
return library.toStringTree(parser)
}
42 changes: 0 additions & 42 deletions Src/java/cql/src/jsMain/kotlin/Main.kt

This file was deleted.

3 changes: 3 additions & 0 deletions Src/js/cql-ui/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": ["next/core-web-vitals", "next/typescript"]
}
40 changes: 40 additions & 0 deletions Src/js/cql-ui/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# env files (can opt-in for commiting if needed)
.env*

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
14 changes: 14 additions & 0 deletions Src/js/cql-ui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# CQL Kotlin UI

A front end for the CQL parser written in Kotlin.

## Local development

The Kotlin/JS-based CQL parser is in development, so you'll need to build it locally by running the `cql:build` task in
the `../../java` project. This will output the cql-all-cql package to the `../../java/build/js/packages/cql-all-cql`
directory.

To then run this project locally:

npm install
npm run dev
95 changes: 95 additions & 0 deletions Src/js/cql-ui/app/cql-playground.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"use client";

import { useState } from "react";
import * as cqlJs from "cql-all-cql";
import * as cqlWasm from "cql-all-cql-wasm-js";

export function CqlPlayground() {
const [state, setState] = useState({
cql: `library Test
define x: 5`,
useWasm: false,
});

const cqlLib = state.useWasm ? cqlWasm : cqlJs;

const parseResult = (() => {
try {
const tree = cqlLib.parseToTree(state.cql);
return {
ok: true,
tree,
} as const;
} catch (e) {
return {
ok: false,
error: String(e),
} as const;
}
})();

return (
<div style={{ padding: 20 }}>
<h1>CQL Kotlin Playground</h1>
<label style={{ display: "block", margin: "0 0 20px 0" }}>
<div style={{ fontWeight: 700, margin: "0 0 5px 0" }}>CQL library</div>
<textarea
value={state.cql}
onChange={(event) => {
const nextCql = event.target.value;
setState((prevState) => ({
...prevState,
cql: nextCql,
}));
}}
style={{
width: "100%",
fieldSizing: "content",
padding: "8px 10px",
}}
/>
</label>

<label style={{ display: "block", margin: "0 0 20px 0" }}>
<input
type={"checkbox"}
checked={state.useWasm}
onChange={(event) => {
const nextUseWasm = event.target.checked;
setState((prevState) => ({
...prevState,
useWasm: nextUseWasm,
}));
}}
/>
Use WebAssembly
</label>

<div style={{ fontWeight: 700, margin: "0 0 5px 0" }}>Parse result</div>

{parseResult.ok ? (
<div>
<pre
style={{
margin: 0,
whiteSpace: "pre-wrap",
}}
>
{parseResult.tree}
</pre>
</div>
) : (
<div>
<pre
style={{
margin: 0,
whiteSpace: "pre-wrap",
}}
>
Error: {parseResult.error}
</pre>
</div>
)}
</div>
);
}
9 changes: 9 additions & 0 deletions Src/js/cql-ui/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
* {
box-sizing: border-box;
}

body {
padding: 0;
margin: 0;
font-family: sans-serif;
}
19 changes: 19 additions & 0 deletions Src/js/cql-ui/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { Metadata } from "next";
import "./globals.css";

export const metadata: Metadata = {
title: "CQL Kotlin UI",
description: "CQL Kotlin UI",
};

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang={"en"}>
<body>{children}</body>
</html>
);
}
5 changes: 5 additions & 0 deletions Src/js/cql-ui/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { CqlPlayground } from "@/app/cql-playground";

export default function Home() {
return <CqlPlayground />;
}
32 changes: 32 additions & 0 deletions Src/js/cql-ui/next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { NextConfig } from "next";
import { DefinePlugin } from "webpack";

const nextConfig: NextConfig = {
reactStrictMode: false,
transpilePackages: ["cql-all-cql-wasm-js"],
webpack: (config, { isServer }) => {
config.ignoreWarnings = [
/Accessing import\.meta directly is unsupported \(only property access or destructuring is supported\)/,
/The generated code contains 'async\/await' because this module is using "topLevelAwait"/,
];

if (isServer) {
config.plugins.push(
new DefinePlugin({
"import.meta":
"{ url: __filename, resolve: (_) => url.pathToFileURL('node_modules/cql-all-cql-wasm-js/kotlin/' + _) }",
}),
);
} else {
config.plugins.push(
new DefinePlugin({
"process.release.name": "'browser'",
}),
);
}

return config;
},
};

export default nextConfig;
Loading

0 comments on commit 3522f23

Please sign in to comment.