Skip to content

Commit

Permalink
fix $ex $fn schema
Browse files Browse the repository at this point in the history
  • Loading branch information
dbuezas committed Oct 13, 2024
1 parent 8b24284 commit 09d0926
Show file tree
Hide file tree
Showing 6 changed files with 4,227 additions and 22,582 deletions.
5 changes: 1 addition & 4 deletions src/jsonschema.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
import { InputConfig } from "./types";

type Whitespace = " " | "\t" | "\n" | "\r";

type With$fn<T> = {
[K in keyof T]:
| (T[K] extends (infer U)[]
? With$fn<U>[] // handle arrays recursively
: T[K] extends object
? With$fn<T[K]> // handle objects recursively
: T[K]) // retain original type
| `${Whitespace | ""}$ex${Whitespace}${string}`
| `${Whitespace | ""}$fn${Whitespace}${string}`; // allow string starting with $ex or $fn with optional whitespace
| `${string}$ex$fn_REPLACER`;
};

export type JsonSchemaRoot = With$fn<InputConfig>;
14 changes: 14 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,21 @@ export type YValue = number | string | null;

export type InputConfig = {
type: "custom:plotly-graph";
/**
* The time to show on load.
* It can be the number of hour (e.g 12),
* a duration string, e.g 100ms, 10s, 30.5m, 2h, 7d, 2w, 1M, 1y,
* or relative time, i.e:
* * current_minute
* * current_hour
* * current_day
* * current_week
* * current_month
* * current_quarter
* * current_year
*/
hours_to_show?: number | TimeDurationStr | RelativeTimeStr;
/** Either a number (seconds), or "auto" */
refresh_interval?: number | "auto"; // in seconds
color_scheme?: ColorSchemeNames | ColorSchemeArray | number;
title?: string;
Expand Down
4 changes: 3 additions & 1 deletion yaml-editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
"scripts": {
"start": "npm run schema && webpack serve --open --mode development",
"build": "npm run schema &&rm -rf dist && webpack --mode production",
"schema": "cd .. && typescript-json-schema --required tsconfig.json JsonSchemaRoot > yaml-editor/src/schema.json",
"schema-1": "cd .. && typescript-json-schema --required tsconfig.json JsonSchemaRoot > yaml-editor/src/schema.json",
"schema-2": "node patch-schema.js",
"schema": "npm run schema-1 && npm run schema-2",
"deploy": "pnpm run build && gh-pages -d dist"
},
"dependencies": {
Expand Down
18 changes: 18 additions & 0 deletions yaml-editor/patch-schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const file = path.join(__dirname, "src/schema.json"); // Create relative path for reading

const patched = fs
.readFileSync(file)
.toString()
.replaceAll(
"^.*\\\\$ex\\\\$fn_REPLACER$",
"^[\\\\s]*\\\\$(ex|fn)\\\\s[\\\\s\\\\S]+$",
);

fs.writeFileSync(file, patched);

console.log("Patch completed.");
196 changes: 110 additions & 86 deletions yaml-editor/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,74 +1,89 @@
import { type JSONSchemaForSchemaStoreOrgCatalogFiles } from '@schemastore/schema-catalog'
import { editor, languages, MarkerSeverity, type Position, Range, Uri } from 'monaco-editor'
import * as monaco from 'monaco-editor'
import { ILanguageFeaturesService } from 'monaco-editor/esm/vs/editor/common/services/languageFeatures.js'
import { OutlineModel } from 'monaco-editor/esm/vs/editor/contrib/documentSymbols/browser/outlineModel.js'
import { StandaloneServices } from 'monaco-editor/esm/vs/editor/standalone/browser/standaloneServices.js'
import { configureMonacoYaml, type SchemasSettings } from 'monaco-yaml'
import { type JSONSchemaForSchemaStoreOrgCatalogFiles } from "@schemastore/schema-catalog";
import {
editor,
languages,
MarkerSeverity,
type Position,
Range,
Uri,
} from "monaco-editor";
import * as monaco from "monaco-editor";
import { ILanguageFeaturesService } from "monaco-editor/esm/vs/editor/common/services/languageFeatures.js";
import { OutlineModel } from "monaco-editor/esm/vs/editor/contrib/documentSymbols/browser/outlineModel.js";
import { StandaloneServices } from "monaco-editor/esm/vs/editor/standalone/browser/standaloneServices.js";
import { configureMonacoYaml, type SchemasSettings } from "monaco-yaml";

import './index.css'
import schema from './schema.json'
import "./index.css";
import schema from "./schema.json";

window.MonacoEnvironment = {
getWorker(moduleId, label) {
switch (label) {
case 'editorWorkerService':
return new Worker(new URL('monaco-editor/esm/vs/editor/editor.worker', import.meta.url))
case 'yaml':
return new Worker(new URL('monaco-yaml/yaml.worker', import.meta.url))
case "editorWorkerService":
return new Worker(
new URL("monaco-editor/esm/vs/editor/editor.worker", import.meta.url),
);
case "yaml":
return new Worker(new URL("monaco-yaml/yaml.worker", import.meta.url));
default:
throw new Error(`Unknown label ${label}`)
throw new Error(`Unknown label ${label}`);
}
}
}
},
};

const defaultSchema: SchemasSettings = {
uri: window.location.href,
schema,
fileMatch: ['plotly-graph.yaml']
}
fileMatch: ["plotly-graph.yaml"],
};

const monacoYaml = configureMonacoYaml(monaco, {
schemas: [defaultSchema]
})
schemas: [defaultSchema],
completion: true,
format: true,
hover: true,
validate: true,
});

function showToast(message:string) {
const toastContainer = document.getElementById('toast-container')!;
const toast = document.createElement('div');
toast.className = 'toast';
function showToast(message: string) {
const toastContainer = document.getElementById("toast-container")!;
const toast = document.createElement("div");
toast.className = "toast";
toast.innerText = message;
toastContainer.appendChild(toast);
setTimeout(() => {
toast.classList.add('show');
toast.classList.add("show");
}, 100);
setTimeout(() => {
toast.classList.remove('show');
setTimeout(() => toast.remove(), 500); // Remove after animation
toast.classList.remove("show");
setTimeout(() => toast.remove(), 500); // Remove after animation
}, 3000);
}

if (localStorage["plotly-graph"]) showToast("Recovered yaml from local storage")
if (localStorage["plotly-graph"])
showToast("Recovered yaml from local storage");

const value = localStorage["plotly-graph"]||
`type: custom:plotly-graph
const value =
localStorage["plotly-graph"] ||
`type: custom:plotly-graph
entities:
- entity: sensor.x
- entity: sensor.y
`
`;



const ed = editor.create(document.getElementById('editor')!, {
const ed = editor.create(document.getElementById("editor")!, {
automaticLayout: true,
model: editor.createModel(value, 'yaml', Uri.parse('plotly-graph.yaml')),
theme: window.matchMedia('(prefers-color-scheme: dark)').matches ? 'vs-dark' : 'vs-light',
model: editor.createModel(value, "yaml", Uri.parse("plotly-graph.yaml")),
theme: window.matchMedia("(prefers-color-scheme: dark)").matches
? "vs-dark"
: "vs-light",
quickSuggestions: {
other: true,
comments: false,
strings: true
strings: true,
},
formatOnType: true
})
formatOnType: true,
});

/**
* Get the document symbols that contain the given position.
Expand All @@ -82,79 +97,88 @@ const ed = editor.create(document.getElementById('editor')!, {
*/
function* iterateSymbols(
symbols: languages.DocumentSymbol[],
position: Position
position: Position,
): Iterable<languages.DocumentSymbol> {
for (const symbol of symbols) {
if (Range.containsPosition(symbol.range, position)) {
yield symbol
yield symbol;
if (symbol.children) {
yield* iterateSymbols(symbol.children, position)
yield* iterateSymbols(symbol.children, position);
}
}
}
}

ed.onDidChangeModelContent(()=>{
localStorage["plotly-graph"] = ed.getValue()

})
ed.onDidChangeModelContent(() => {
localStorage["plotly-graph"] = ed.getValue();
});

ed.onDidChangeCursorPosition(async (event) => {
const breadcrumbs = document.getElementById('breadcrumbs')!
const { documentSymbolProvider } = StandaloneServices.get(ILanguageFeaturesService)
const outline = await OutlineModel.create(documentSymbolProvider, ed.getModel()!)
const symbols = outline.asListOfDocumentSymbols()
const breadcrumbs = document.getElementById("breadcrumbs")!;
const { documentSymbolProvider } = StandaloneServices.get(
ILanguageFeaturesService,
);
const outline = await OutlineModel.create(
documentSymbolProvider,
ed.getModel()!,
);
const symbols = outline.asListOfDocumentSymbols();
while (breadcrumbs.lastChild) {
breadcrumbs.lastChild.remove()
breadcrumbs.lastChild.remove();
}
for (const symbol of iterateSymbols(symbols, event.position)) {
const breadcrumb = document.createElement('span')
breadcrumb.setAttribute('role', 'button')
breadcrumb.classList.add('breadcrumb')
breadcrumb.textContent = symbol.name
breadcrumb.title = symbol.detail
const breadcrumb = document.createElement("span");
breadcrumb.setAttribute("role", "button");
breadcrumb.classList.add("breadcrumb");
breadcrumb.textContent = symbol.name;
breadcrumb.title = symbol.detail;
if (symbol.kind === languages.SymbolKind.Array) {
breadcrumb.classList.add('array')
breadcrumb.classList.add("array");
} else if (symbol.kind === languages.SymbolKind.Module) {
breadcrumb.classList.add('object')
breadcrumb.classList.add("object");
}
breadcrumb.addEventListener('click', () => {
breadcrumb.addEventListener("click", () => {
ed.setPosition({
lineNumber: symbol.range.startLineNumber,
column: symbol.range.startColumn
})
ed.focus()
})
breadcrumbs.append(breadcrumb)
column: symbol.range.startColumn,
});
ed.focus();
});
breadcrumbs.append(breadcrumb);
}
})
});

editor.onDidChangeMarkers(([resource]) => {
const problems = document.getElementById('problems')!
const markers = editor.getModelMarkers({ resource })
const problems = document.getElementById("problems")!;
const markers = editor.getModelMarkers({ resource });
while (problems.lastChild) {
problems.lastChild.remove()
problems.lastChild.remove();
}
for (const marker of markers) {
if (marker.severity === MarkerSeverity.Hint) {
continue
continue;
}
const wrapper = document.createElement('div')
wrapper.setAttribute('role', 'button')
const codicon = document.createElement('div')
const text = document.createElement('div')
wrapper.classList.add('problem')
const wrapper = document.createElement("div");
wrapper.setAttribute("role", "button");
const codicon = document.createElement("div");
const text = document.createElement("div");
wrapper.classList.add("problem");
codicon.classList.add(
'codicon',
marker.severity === MarkerSeverity.Warning ? 'codicon-warning' : 'codicon-error'
)
text.classList.add('problem-text')
text.textContent = marker.message
wrapper.append(codicon, text)
wrapper.addEventListener('click', () => {
ed.setPosition({ lineNumber: marker.startLineNumber, column: marker.startColumn })
ed.focus()
})
problems.append(wrapper)
"codicon",
marker.severity === MarkerSeverity.Warning
? "codicon-warning"
: "codicon-error",
);
text.classList.add("problem-text");
text.textContent = marker.message;
wrapper.append(codicon, text);
wrapper.addEventListener("click", () => {
ed.setPosition({
lineNumber: marker.startLineNumber,
column: marker.startColumn,
});
ed.focus();
});
problems.append(wrapper);
}
})
});
Loading

0 comments on commit 09d0926

Please sign in to comment.