Skip to content

Commit

Permalink
Playground improvements (#169)
Browse files Browse the repository at this point in the history
* Playground improvements
- Add performance
- Write URL to clipboard
- Remove lz-string
- Fix for lots of text in playground
- Not default button style
- And fix issue with getting the text
- Add comparison document (with generation)
- Use latest node
  • Loading branch information
kaleidawave authored Aug 29, 2024
1 parent ff46373 commit cd8e961
Show file tree
Hide file tree
Showing 13 changed files with 5,006 additions and 44 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/deploy-playground.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Publish playground to GitHub pages
name: Publish playground (and comparison) to GitHub pages

on:
workflow_dispatch
Expand All @@ -12,7 +12,7 @@ jobs:

- uses: actions/setup-node@v4
with:
node-version: 18
node-version: '20.11.1'

- name: build
run: |
Expand Down
14 changes: 14 additions & 0 deletions src/playground/assets/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ hr {
margin: 40px 0;
}

button {
margin: 20px 0;
padding: 6px 20px;
font-family: inherit;
background: none;
color: inherit;
border: 3px solid white;
border-radius: 6px;
}

button:hover {
cursor: pointer;
}

@media (max-width: 700px) {
header {
flex-direction: column;
Expand Down
82 changes: 82 additions & 0 deletions src/playground/comparison/assets/comparison.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
body {
margin: 0;
background: black;
color: white;
font-family: 'Inter', sans-serif;
padding: 32px;
}

header {
display: flex;
align-items: center;
gap: 20px;
}

main>h2 {
margin: 10px 0px;
}

.comparison>li>div {
display: grid;
gap: 18px;
}

.comparison h2,
.comparison h3 {
cursor: pointer;
scroll-margin: 40px;
margin-top: 40px;
}

@media screen and (min-width: 1080px) {
.comparison>li>div {
grid-template-columns: 2fr 3fr;
}
}

.comparison>li>div>pre {
overflow-x: auto;
border-radius: 6px;
font-size: 16px;
padding: 16px;
margin: 0;
}

.comparison>li>div>div>pre {
margin: 0;
padding: 16px;
border-radius: 6px;
}

.tsc-diagnostics {
margin-top: 24px;
}

.ezno-diagnostics>ul,
.tsc-diagnostics>ul {
font-family: 'JetBrains mono', monospace;
font-size: 16px;
padding-left: 20px;
line-height: 28px;
}

.checker-name {
display: flex;
gap: 10px;
}

.checker-name>a {
color: #979797;
text-transform: lowercase;
font-family: monospace;
}

ul.comparison {
list-style: none;
padding-left: 0;
margin-top: 0;
}

ul.comparison>li {
margin-top: 20px;
}
6 changes: 6 additions & 0 deletions src/playground/comparison/assets/ezno.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/playground/comparison/assets/typescript.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
183 changes: 183 additions & 0 deletions src/playground/comparison/comparison_generator.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import { lexer, marked } from "marked";
import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
import { join } from "node:path";
import lz from "lz-string";
import shiki from "shiki";
import ts from "./typescript_wrapper.mjs"

const { compressToEncodedURIComponent } = lz;

const dirname = import.meta.dirname;

function getSpecificationSections() {
const content = readFileSync(join(dirname, "../../../checker/specification/specification.md")).toString();
const output = lexer(content);

const defaultEntry = () => ({ title: null, files: null, expectations: null });

const sections = [];
let currentSection = null;
let current = defaultEntry();
for (const item of output) {
if (item.type === "heading") {
if (item.depth === 3) {
const newSection = { heading: item.text, rows: [] };
if (currentSection) {
currentSection.rows.push(current);
current = defaultEntry();
sections.push(currentSection);
}
currentSection = newSection;
} else if (item.depth === 4) {
if (current.title !== null) {
currentSection.rows.push(current);
current = defaultEntry();
}
current.title = item.text;
}
} else if (item.type === "code") {
const chunks = [];
let currentContent = "", currentFile = "main.ts";
for (const line of item.text.split("\n")) {
const marker = "// in ";
if (line.startsWith(marker)) {
if (currentContent.length) {
chunks.push([currentFile, currentContent]);
currentContent = ""
}
currentFile = line.substring(marker.length)
} else {
currentContent += line + "\n";
}
}
if (currentContent.length) {
chunks.push([currentFile, currentContent]);
}
current.files = chunks;
} else if (item.type === "list") {
current.expectations = item.items.map(item => item.text.replaceAll("\\", ""));
}
}

currentSection.rows.push(current)
sections.push(currentSection)

return sections
}

async function renderDifferences(sections) {
const highlighter = await shiki.getHighlighter({ theme: 'material-theme-darker', langs: ['ts'], });
let acc = "";
for (const section of sections) {
const title = section.heading;
const href = title.toLowerCase().replaceAll(/[ \(\)'\*]+/g, "");
acc += `<h2 id="#${href}">${title}</h2>`;
acc += `<ul class="comparison">`;
for (const row of section.rows) {
const code = row.files[0][1];
const highlightedCode = highlighter.codeToHtml(code, { lang: 'ts' });
const title = marked(row.title).slice(3, -5);
const href = row.title.toLowerCase().replaceAll(/[ \(\)'\*]+/g, "");
const codeCompressed = compressToEncodedURIComponent(code);

const eznoPlaygroundURL = "https://kaleidawave.github.io/ezno/playground/";
const eznoPlaygroundLink = `${eznoPlaygroundURL}?raw=${encodeURIComponent(code)}`;
const tscPlaygroundLink = `https://www.typescriptlang.org/play?#code/${codeCompressed}`;

acc += `<li>
<h3 id="${href}">${title}</h3>
<div>
${highlightedCode}
<div>
<div class="ezno-diagnostics">
<div class="checker-name">
<img src="./assets/ezno.svg" alt="ezno" height="14px">
<a href="${eznoPlaygroundLink}">(Playground)</a>
</div>
<ul>${row.ezno.map(msg => `<li>${msg}</li>`).join("")}</ul>
</div>
<div class="tsc-diagnostics">
<div class="checker-name">
<img src="./assets/typescript.svg" alt="typescript" height="20px">
<a href="${tscPlaygroundLink}">(Playground)</a>
</div>
<ul>${row.tsc.map(msg => `<li>${msg}</li>`).join("")}</ul>
</div>
</div>
</div>
</li>`;
}
acc += "</ul>";
}
return acc
}

const specification = getSpecificationSections().map((section) => {
// , "declare"
section.rows = section.rows.filter((row) => !["export", "import"].some(banned => row.files[0][1].includes(banned)));
return section;
});

// console.dir(specification, { depth: 3 })

function generateTSCDifferences(specification) {
console.time("Getting TSC differences");
for (const section of specification) {
section.rows = section.rows.map((row) => {
const tsc = ts(row.files);
return { ...row, ezno: row.expectations, tsc }
});
}
console.timeEnd("Getting TSC differences");
return specification
}

{
// TODO temp
let i = 0;
for (const item of specification) {
for (const row of item.rows) {
i += row.expectations.length;
}
}
console.log(`Found ${specification.length} specification sections with a total ${i} expectations`)
}

// writeFileSync("./specification2.json", JSON.stringify(specification, 0, 4))

generateComparisonDocument(specification)

async function generateComparisonDocument(specification) {
const differences = generateTSCDifferences(specification);
const description = "WIP: comparison between Ezno's and TSC's diagnostics. This is meant to highlight differences in diagnostics emitted. <strong>Bear in mind</strong> this has bias towards what Ezno supports and does not show any of the items that don't work under ezno-checker. This covers most of what Ezno implements as of August 2024.";

const header = `<header>
<img src="./assets/ezno.svg" alt="" height="40px">
<p>${description}</p>
</header>`;

const inner = await renderDifferences(differences);

const out = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Type checker comparison</title>
<link rel="stylesheet" href="./assets/comparison.css">
</head>
<body>
${header}
<main>
${inner}
</main>
</body>`;

const place = join(dirname, "../dist/comparison");
// `recursive: true` prevents errors when exists
mkdirSync(place, { recursive: true });
mkdirSync(join(place, "assets"), { recursive: true });
writeFileSync(join(place, "index.html"), out);
console.log("Wrote differences out")
}
Loading

0 comments on commit cd8e961

Please sign in to comment.