docs: move assets to correct path
This commit is contained in:
parent
694d636322
commit
dda45cfbb6
11 changed files with 8 additions and 208 deletions
375
docs/src/assets/css/playground.css
Normal file
375
docs/src/assets/css/playground.css
Normal file
|
|
@ -0,0 +1,375 @@
|
|||
/* Base Variables */
|
||||
:root {
|
||||
--light-bg: #f9f9f9;
|
||||
--light-border: #e0e0e0;
|
||||
--light-text: #333;
|
||||
--light-hover-border: #c1c1c1;
|
||||
--light-scrollbar-track: #f1f1f1;
|
||||
--light-scrollbar-thumb: #c1c1c1;
|
||||
--light-scrollbar-thumb-hover: #a8a8a8;
|
||||
|
||||
--dark-bg: #1d1f21;
|
||||
--dark-border: #2d2d2d;
|
||||
--dark-text: #c5c8c6;
|
||||
--dark-scrollbar-track: #25282c;
|
||||
--dark-scrollbar-thumb: #4a4d51;
|
||||
--dark-scrollbar-thumb-hover: #5a5d61;
|
||||
|
||||
--primary-color: #0550ae;
|
||||
--primary-color-alpha: rgba(5, 80, 174, 0.1);
|
||||
--primary-color-alpha-dark: rgba(121, 192, 255, 0.1);
|
||||
--selection-color: rgba(39, 95, 255, 0.3);
|
||||
}
|
||||
|
||||
/* Common Scrollbar Styles */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* Base Light Theme Scrollbars */
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--light-scrollbar-track);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--light-scrollbar-thumb);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--light-scrollbar-thumb-hover);
|
||||
}
|
||||
|
||||
/* Dropdown Styling */
|
||||
.custom-select {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#language-select {
|
||||
background-color: var(--light-bg);
|
||||
border: 1px solid var(--light-border);
|
||||
border-radius: 4px;
|
||||
padding: 4px 24px 4px 8px;
|
||||
font-size: 14px;
|
||||
color: var(--light-text);
|
||||
cursor: pointer;
|
||||
min-width: 120px;
|
||||
appearance: none;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 8px center;
|
||||
}
|
||||
|
||||
.select-button {
|
||||
background-color: var(--light-bg);
|
||||
border: 1px solid var(--light-border);
|
||||
border-radius: 4px;
|
||||
padding: 4px 8px;
|
||||
font-size: 14px;
|
||||
color: var(--light-text);
|
||||
cursor: pointer;
|
||||
min-width: 120px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#language-select:hover,
|
||||
.select-button:hover {
|
||||
border-color: var(--light-hover-border);
|
||||
}
|
||||
|
||||
#language-select:focus,
|
||||
.select-button:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 0 2px var(--primary-color-alpha);
|
||||
}
|
||||
|
||||
/* Custom Checkbox Styling */
|
||||
input[type="checkbox"] {
|
||||
appearance: none;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 1px solid var(--light-border);
|
||||
border-radius: 3px;
|
||||
margin-right: 6px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked {
|
||||
background-color: var(--primary-color);
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
input[type="checkbox"]:checked::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
top: 2px;
|
||||
width: 4px;
|
||||
height: 8px;
|
||||
border: solid white;
|
||||
border-width: 0 2px 2px 0;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
input[type="checkbox"]:hover {
|
||||
border-color: var(--light-hover-border);
|
||||
}
|
||||
|
||||
input[type="checkbox"]:focus {
|
||||
outline: none;
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 0 2px var(--primary-color-alpha);
|
||||
}
|
||||
|
||||
/* Select Dropdown */
|
||||
.select-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: var(--light-bg);
|
||||
border: 1px solid var(--light-border);
|
||||
border-radius: 4px;
|
||||
margin-top: 4px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
display: none;
|
||||
z-index: 1000;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.select-dropdown.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.option {
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.option:hover {
|
||||
background-color: var(--primary-color-alpha);
|
||||
}
|
||||
|
||||
.option.selected {
|
||||
background-color: var(--primary-color-alpha);
|
||||
}
|
||||
|
||||
/* CodeMirror Base Styles */
|
||||
.ts-playground .CodeMirror {
|
||||
border-radius: 6px;
|
||||
background-color: var(--light-bg) !important;
|
||||
color: #080808 !important;
|
||||
}
|
||||
|
||||
.ts-playground .CodeMirror-scroll {
|
||||
padding: 8px;
|
||||
border: 1px solid var(--light-border);
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.ayu .ts-playground .CodeMirror-scroll,
|
||||
.coal .ts-playground .CodeMirror-scroll,
|
||||
.navy .ts-playground .CodeMirror-scroll {
|
||||
border-color: var(--dark-border);
|
||||
}
|
||||
|
||||
.ts-playground .CodeMirror-gutters {
|
||||
background: #ebebeb !important;
|
||||
border-right: 1px solid #e8e8e8 !important;
|
||||
}
|
||||
|
||||
.ts-playground .CodeMirror-cursor {
|
||||
border-left: 2px solid #000 !important;
|
||||
}
|
||||
|
||||
.ts-playground .CodeMirror-selected {
|
||||
background: var(--selection-color) !important;
|
||||
}
|
||||
|
||||
.ts-playground .CodeMirror-activeline-background {
|
||||
background: rgba(36, 99, 180, 0.12) !important;
|
||||
}
|
||||
|
||||
/* Output Container Styles */
|
||||
#output-container {
|
||||
color: #080808;
|
||||
background-color: var(--light-bg);
|
||||
margin: 0;
|
||||
white-space: pre;
|
||||
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
|
||||
}
|
||||
|
||||
#output-container-scroll {
|
||||
max-height: 400px;
|
||||
overflow: auto;
|
||||
padding: 8px;
|
||||
border: 1px solid var(--light-border);
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
background-color: var(--light-bg);
|
||||
}
|
||||
|
||||
#output-container a {
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#output-container a.node-link.anonymous {
|
||||
color: #116329;
|
||||
}
|
||||
|
||||
#output-container a.node-link.anonymous:before {
|
||||
content: '"';
|
||||
}
|
||||
|
||||
#output-container a.node-link.anonymous:after {
|
||||
content: '"';
|
||||
}
|
||||
|
||||
#output-container a.node-link.error {
|
||||
color: #cf222e;
|
||||
}
|
||||
|
||||
#output-container a.highlighted {
|
||||
background-color: var(--selection-color);
|
||||
}
|
||||
|
||||
/* Dark Theme Overrides */
|
||||
.ayu,
|
||||
.coal,
|
||||
.navy {
|
||||
|
||||
& #language-select,
|
||||
& .select-button {
|
||||
background-color: var(--dark-bg);
|
||||
border-color: var(--dark-border);
|
||||
color: var(--dark-text);
|
||||
}
|
||||
|
||||
& input[type="checkbox"] {
|
||||
border-color: var(--dark-border);
|
||||
background-color: var(--dark-bg);
|
||||
}
|
||||
|
||||
& input[type="checkbox"]:checked {
|
||||
background-color: #79c0ff;
|
||||
border-color: #79c0ff;
|
||||
}
|
||||
|
||||
& label {
|
||||
color: var(--dark-text);
|
||||
}
|
||||
|
||||
& .select-dropdown {
|
||||
background-color: var(--dark-bg);
|
||||
border-color: var(--dark-border);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
& .option:hover {
|
||||
background-color: var(--primary-color-alpha-dark);
|
||||
}
|
||||
|
||||
& .option.selected {
|
||||
background-color: var(--primary-color-alpha-dark);
|
||||
}
|
||||
|
||||
& .ts-playground .CodeMirror {
|
||||
background-color: var(--dark-bg) !important;
|
||||
color: var(--dark-text) !important;
|
||||
}
|
||||
|
||||
& .ts-playground .CodeMirror-gutters {
|
||||
background: var(--dark-scrollbar-track) !important;
|
||||
border-right-color: var(--dark-border) !important;
|
||||
}
|
||||
|
||||
& .ts-playground .CodeMirror-cursor {
|
||||
border-left-color: #aeafad !important;
|
||||
}
|
||||
|
||||
& .ts-playground .CodeMirror-selected {
|
||||
background: #373b41 !important;
|
||||
}
|
||||
|
||||
& .ts-playground .CodeMirror-activeline-background {
|
||||
background: #282a2e !important;
|
||||
}
|
||||
|
||||
& #output-container {
|
||||
color: var(--dark-text);
|
||||
background-color: var(--dark-bg);
|
||||
}
|
||||
|
||||
& #output-container-scroll {
|
||||
background-color: var(--dark-bg);
|
||||
border-color: var(--dark-border);
|
||||
}
|
||||
|
||||
& #output-container a {
|
||||
color: #79c0ff;
|
||||
}
|
||||
|
||||
& #output-container a.node-link.anonymous {
|
||||
color: #7ee787;
|
||||
}
|
||||
|
||||
& #output-container a.node-link.error {
|
||||
color: #ff7b72;
|
||||
}
|
||||
|
||||
& #output-container a.highlighted {
|
||||
background-color: #373b41;
|
||||
}
|
||||
|
||||
/* Dark Theme Scrollbars */
|
||||
& ::-webkit-scrollbar-track {
|
||||
background: var(--dark-scrollbar-track) !important;
|
||||
}
|
||||
|
||||
& ::-webkit-scrollbar-thumb {
|
||||
background: var(--dark-scrollbar-thumb) !important;
|
||||
}
|
||||
|
||||
& ::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--dark-scrollbar-thumb-hover) !important;
|
||||
}
|
||||
|
||||
& * {
|
||||
scrollbar-width: thin !important;
|
||||
scrollbar-color: var(--dark-scrollbar-thumb) var(--dark-scrollbar-track) !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Spacing Utilities */
|
||||
#language-select,
|
||||
input[type="checkbox"],
|
||||
label {
|
||||
margin: 0 4px;
|
||||
}
|
||||
|
||||
#language-select {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
margin-right: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
BIN
docs/src/assets/images/favicon-16x16.png
Normal file
BIN
docs/src/assets/images/favicon-16x16.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 887 B |
BIN
docs/src/assets/images/favicon-32x32.png
Normal file
BIN
docs/src/assets/images/favicon-32x32.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
BIN
docs/src/assets/images/tree-sitter-small.png
Normal file
BIN
docs/src/assets/images/tree-sitter-small.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 112 KiB |
577
docs/src/assets/js/playground.js
Normal file
577
docs/src/assets/js/playground.js
Normal file
|
|
@ -0,0 +1,577 @@
|
|||
function initializeCustomSelect() {
|
||||
const button = document.getElementById('language-button');
|
||||
const select = document.getElementById('language-select');
|
||||
if (!button || !select) return;
|
||||
|
||||
const dropdown = button.nextElementSibling;
|
||||
const selectedValue = button.querySelector('.selected-value');
|
||||
|
||||
selectedValue.textContent = select.options[select.selectedIndex].text;
|
||||
|
||||
button.addEventListener('click', (e) => {
|
||||
e.preventDefault(); // Prevent form submission
|
||||
dropdown.classList.toggle('show');
|
||||
});
|
||||
|
||||
document.addEventListener('click', (e) => {
|
||||
if (!button.contains(e.target)) {
|
||||
dropdown.classList.remove('show');
|
||||
}
|
||||
});
|
||||
|
||||
dropdown.querySelectorAll('.option').forEach(option => {
|
||||
option.addEventListener('click', () => {
|
||||
selectedValue.textContent = option.textContent;
|
||||
select.value = option.dataset.value;
|
||||
dropdown.classList.remove('show');
|
||||
|
||||
const event = new Event('change');
|
||||
select.dispatchEvent(event);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
window.initializePlayground = async function initializePlayground() {
|
||||
initializeCustomSelect();
|
||||
|
||||
let tree;
|
||||
|
||||
const CAPTURE_REGEX = /@\s*([\w\._-]+)/g;
|
||||
const LIGHT_COLORS = [
|
||||
"#0550ae", // blue
|
||||
"#ab5000", // rust brown
|
||||
"#116329", // forest green
|
||||
"#844708", // warm brown
|
||||
"#6639ba", // purple
|
||||
"#7d4e00", // orange brown
|
||||
"#0969da", // bright blue
|
||||
"#1a7f37", // green
|
||||
"#cf222e", // red
|
||||
"#8250df", // violet
|
||||
"#6e7781", // gray
|
||||
"#953800", // dark orange
|
||||
"#1b7c83" // teal
|
||||
];
|
||||
|
||||
const DARK_COLORS = [
|
||||
"#79c0ff", // light blue
|
||||
"#ffa657", // orange
|
||||
"#7ee787", // light green
|
||||
"#ff7b72", // salmon
|
||||
"#d2a8ff", // light purple
|
||||
"#ffa198", // pink
|
||||
"#a5d6ff", // pale blue
|
||||
"#56d364", // bright green
|
||||
"#ff9492", // light red
|
||||
"#e0b8ff", // pale purple
|
||||
"#9ca3af", // gray
|
||||
"#ffb757", // yellow orange
|
||||
"#80cbc4" // light teal
|
||||
];
|
||||
|
||||
const codeInput = document.getElementById("code-input");
|
||||
const languageSelect = document.getElementById("language-select");
|
||||
const loggingCheckbox = document.getElementById("logging-checkbox");
|
||||
const anonymousNodes = document.getElementById('anonymous-nodes-checkbox');
|
||||
const outputContainer = document.getElementById("output-container");
|
||||
const outputContainerScroll = document.getElementById(
|
||||
"output-container-scroll",
|
||||
);
|
||||
const playgroundContainer = document.getElementById("playground-container");
|
||||
const queryCheckbox = document.getElementById("query-checkbox");
|
||||
const queryContainer = document.getElementById("query-container");
|
||||
const queryInput = document.getElementById("query-input");
|
||||
const updateTimeSpan = document.getElementById("update-time");
|
||||
const languagesByName = {};
|
||||
|
||||
loadState();
|
||||
|
||||
await TreeSitter.init();
|
||||
|
||||
const parser = new TreeSitter();
|
||||
|
||||
console.log(parser, codeInput, queryInput);
|
||||
|
||||
const codeEditor = CodeMirror.fromTextArea(codeInput, {
|
||||
lineNumbers: true,
|
||||
showCursorWhenSelecting: true
|
||||
});
|
||||
|
||||
codeEditor.on('keydown', (_, event) => {
|
||||
if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
|
||||
event.stopPropagation(); // Prevent mdBook from going back/forward
|
||||
}
|
||||
});
|
||||
|
||||
const queryEditor = CodeMirror.fromTextArea(queryInput, {
|
||||
lineNumbers: true,
|
||||
showCursorWhenSelecting: true,
|
||||
});
|
||||
|
||||
queryEditor.on('keydown', (_, event) => {
|
||||
if (event.key === 'ArrowLeft' || event.key === 'ArrowRight') {
|
||||
event.stopPropagation(); // Prevent mdBook from going back/forward
|
||||
}
|
||||
});
|
||||
|
||||
const cluster = new Clusterize({
|
||||
rows: [],
|
||||
noDataText: null,
|
||||
contentElem: outputContainer,
|
||||
scrollElem: outputContainerScroll,
|
||||
});
|
||||
const renderTreeOnCodeChange = debounce(renderTree, 50);
|
||||
const saveStateOnChange = debounce(saveState, 2000);
|
||||
const runTreeQueryOnChange = debounce(runTreeQuery, 50);
|
||||
|
||||
let languageName = languageSelect.value;
|
||||
let treeRows = null;
|
||||
let treeRowHighlightedIndex = -1;
|
||||
let parseCount = 0;
|
||||
let isRendering = 0;
|
||||
let query;
|
||||
|
||||
codeEditor.on("changes", handleCodeChange);
|
||||
codeEditor.on("viewportChange", runTreeQueryOnChange);
|
||||
codeEditor.on("cursorActivity", debounce(handleCursorMovement, 150));
|
||||
queryEditor.on("changes", debounce(handleQueryChange, 150));
|
||||
|
||||
loggingCheckbox.addEventListener("change", handleLoggingChange);
|
||||
anonymousNodes.addEventListener('change', renderTree);
|
||||
queryCheckbox.addEventListener("change", handleQueryEnableChange);
|
||||
languageSelect.addEventListener("change", handleLanguageChange);
|
||||
outputContainer.addEventListener("click", handleTreeClick);
|
||||
|
||||
handleQueryEnableChange();
|
||||
await handleLanguageChange();
|
||||
|
||||
playgroundContainer.style.visibility = "visible";
|
||||
|
||||
async function handleLanguageChange() {
|
||||
const newLanguageName = languageSelect.value;
|
||||
if (!languagesByName[newLanguageName]) {
|
||||
const url = `${LANGUAGE_BASE_URL}/tree-sitter-${newLanguageName}.wasm`;
|
||||
languageSelect.disabled = true;
|
||||
try {
|
||||
languagesByName[newLanguageName] = await TreeSitter.Language.load(url);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
languageSelect.value = languageName;
|
||||
return;
|
||||
} finally {
|
||||
languageSelect.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
tree = null;
|
||||
languageName = newLanguageName;
|
||||
parser.setLanguage(languagesByName[newLanguageName]);
|
||||
handleCodeChange();
|
||||
handleQueryChange();
|
||||
}
|
||||
|
||||
async function handleCodeChange(editor, changes) {
|
||||
const newText = codeEditor.getValue() + "\n";
|
||||
const edits = tree && changes && changes.map(treeEditForEditorChange);
|
||||
|
||||
const start = performance.now();
|
||||
if (edits) {
|
||||
for (const edit of edits) {
|
||||
tree.edit(edit);
|
||||
}
|
||||
}
|
||||
const newTree = parser.parse(newText, tree);
|
||||
const duration = (performance.now() - start).toFixed(1);
|
||||
|
||||
updateTimeSpan.innerText = `${duration} ms`;
|
||||
if (tree) tree.delete();
|
||||
tree = newTree;
|
||||
parseCount++;
|
||||
renderTreeOnCodeChange();
|
||||
runTreeQueryOnChange();
|
||||
saveStateOnChange();
|
||||
}
|
||||
|
||||
async function renderTree() {
|
||||
isRendering++;
|
||||
const cursor = tree.walk();
|
||||
|
||||
let currentRenderCount = parseCount;
|
||||
let row = "";
|
||||
let rows = [];
|
||||
let finishedRow = false;
|
||||
let visitedChildren = false;
|
||||
let indentLevel = 0;
|
||||
|
||||
for (let i = 0; ; i++) {
|
||||
if (i > 0 && i % 10000 === 0) {
|
||||
await new Promise((r) => setTimeout(r, 0));
|
||||
if (parseCount !== currentRenderCount) {
|
||||
cursor.delete();
|
||||
isRendering--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let displayName;
|
||||
let displayClass = 'plain';
|
||||
if (cursor.nodeIsMissing) {
|
||||
const nodeTypeText = cursor.nodeIsNamed ? cursor.nodeType : `"${cursor.nodeType}"`;
|
||||
displayName = `MISSING ${nodeTypeText}`;
|
||||
} else if (cursor.nodeIsNamed) {
|
||||
displayName = cursor.nodeType;
|
||||
} else if (anonymousNodes.checked) {
|
||||
displayName = cursor.nodeType
|
||||
}
|
||||
|
||||
if (visitedChildren) {
|
||||
if (displayName) {
|
||||
finishedRow = true;
|
||||
}
|
||||
|
||||
if (cursor.gotoNextSibling()) {
|
||||
visitedChildren = false;
|
||||
} else if (cursor.gotoParent()) {
|
||||
visitedChildren = true;
|
||||
indentLevel--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (displayName) {
|
||||
if (finishedRow) {
|
||||
row += "</div>";
|
||||
rows.push(row);
|
||||
finishedRow = false;
|
||||
}
|
||||
const start = cursor.startPosition;
|
||||
const end = cursor.endPosition;
|
||||
const id = cursor.nodeId;
|
||||
let fieldName = cursor.currentFieldName;
|
||||
if (fieldName) {
|
||||
fieldName += ": ";
|
||||
} else {
|
||||
fieldName = "";
|
||||
}
|
||||
|
||||
const nodeClass =
|
||||
displayName === 'ERROR' || displayName.startsWith('MISSING')
|
||||
? 'node-link error'
|
||||
: cursor.nodeIsNamed
|
||||
? 'node-link named'
|
||||
: 'node-link anonymous';
|
||||
|
||||
row = `<div class="tree-row">${" ".repeat(indentLevel)}${fieldName}` +
|
||||
`<a class='${nodeClass}' href="#" data-id=${id} ` +
|
||||
`data-range="${start.row},${start.column},${end.row},${end.column}">` +
|
||||
`${displayName}</a> <span class="position-info">` +
|
||||
`[${start.row}, ${start.column}] - [${end.row}, ${end.column}]</span>`;
|
||||
finishedRow = true;
|
||||
}
|
||||
|
||||
if (cursor.gotoFirstChild()) {
|
||||
visitedChildren = false;
|
||||
indentLevel++;
|
||||
} else {
|
||||
visitedChildren = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (finishedRow) {
|
||||
row += "</div>";
|
||||
rows.push(row);
|
||||
}
|
||||
|
||||
cursor.delete();
|
||||
cluster.update(rows);
|
||||
treeRows = rows;
|
||||
isRendering--;
|
||||
handleCursorMovement();
|
||||
}
|
||||
|
||||
function runTreeQuery(_, startRow, endRow) {
|
||||
if (endRow == null) {
|
||||
const viewport = codeEditor.getViewport();
|
||||
startRow = viewport.from;
|
||||
endRow = viewport.to;
|
||||
}
|
||||
|
||||
codeEditor.operation(() => {
|
||||
const marks = codeEditor.getAllMarks();
|
||||
marks.forEach((m) => m.clear());
|
||||
|
||||
if (tree && query) {
|
||||
const captures = query.captures(
|
||||
tree.rootNode,
|
||||
{ row: startRow, column: 0 },
|
||||
{ row: endRow, column: 0 },
|
||||
);
|
||||
let lastNodeId;
|
||||
for (const { name, node } of captures) {
|
||||
if (node.id === lastNodeId) continue;
|
||||
lastNodeId = node.id;
|
||||
const { startPosition, endPosition } = node;
|
||||
codeEditor.markText(
|
||||
{ line: startPosition.row, ch: startPosition.column },
|
||||
{ line: endPosition.row, ch: endPosition.column },
|
||||
{
|
||||
inclusiveLeft: true,
|
||||
inclusiveRight: true,
|
||||
css: `color: ${colorForCaptureName(name)}`,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// When we change from a dark theme to a light theme (and vice versa), the colors of the
|
||||
// captures need to be updated.
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
if (mutation.attributeName === 'class') {
|
||||
handleQueryChange();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
observer.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['class']
|
||||
});
|
||||
|
||||
function handleQueryChange() {
|
||||
if (query) {
|
||||
query.delete();
|
||||
query.deleted = true;
|
||||
query = null;
|
||||
}
|
||||
|
||||
queryEditor.operation(() => {
|
||||
queryEditor.getAllMarks().forEach((m) => m.clear());
|
||||
if (!queryCheckbox.checked) return;
|
||||
|
||||
const queryText = queryEditor.getValue();
|
||||
|
||||
try {
|
||||
query = parser.getLanguage().query(queryText);
|
||||
let match;
|
||||
|
||||
let row = 0;
|
||||
queryEditor.eachLine((line) => {
|
||||
while ((match = CAPTURE_REGEX.exec(line.text))) {
|
||||
queryEditor.markText(
|
||||
{ line: row, ch: match.index },
|
||||
{ line: row, ch: match.index + match[0].length },
|
||||
{
|
||||
inclusiveLeft: true,
|
||||
inclusiveRight: true,
|
||||
css: `color: ${colorForCaptureName(match[1])}`,
|
||||
},
|
||||
);
|
||||
}
|
||||
row++;
|
||||
});
|
||||
} catch (error) {
|
||||
const startPosition = queryEditor.posFromIndex(error.index);
|
||||
const endPosition = {
|
||||
line: startPosition.line,
|
||||
ch: startPosition.ch + (error.length || Infinity),
|
||||
};
|
||||
|
||||
if (error.index === queryText.length) {
|
||||
if (startPosition.ch > 0) {
|
||||
startPosition.ch--;
|
||||
} else if (startPosition.row > 0) {
|
||||
startPosition.row--;
|
||||
startPosition.column = Infinity;
|
||||
}
|
||||
}
|
||||
|
||||
queryEditor.markText(startPosition, endPosition, {
|
||||
className: "query-error",
|
||||
inclusiveLeft: true,
|
||||
inclusiveRight: true,
|
||||
attributes: { title: error.message },
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
runTreeQuery();
|
||||
saveQueryState();
|
||||
}
|
||||
|
||||
function handleCursorMovement() {
|
||||
if (isRendering) return;
|
||||
|
||||
const selection = codeEditor.getDoc().listSelections()[0];
|
||||
let start = { row: selection.anchor.line, column: selection.anchor.ch };
|
||||
let end = { row: selection.head.line, column: selection.head.ch };
|
||||
if (
|
||||
start.row > end.row ||
|
||||
(start.row === end.row && start.column > end.column)
|
||||
) {
|
||||
let swap = end;
|
||||
end = start;
|
||||
start = swap;
|
||||
}
|
||||
const node = tree.rootNode.namedDescendantForPosition(start, end);
|
||||
if (treeRows) {
|
||||
if (treeRowHighlightedIndex !== -1) {
|
||||
const row = treeRows[treeRowHighlightedIndex];
|
||||
if (row)
|
||||
treeRows[treeRowHighlightedIndex] = row.replace(
|
||||
"highlighted",
|
||||
"plain",
|
||||
);
|
||||
}
|
||||
treeRowHighlightedIndex = treeRows.findIndex((row) =>
|
||||
row.includes(`data-id=${node.id}`),
|
||||
);
|
||||
if (treeRowHighlightedIndex !== -1) {
|
||||
const row = treeRows[treeRowHighlightedIndex];
|
||||
if (row)
|
||||
treeRows[treeRowHighlightedIndex] = row.replace(
|
||||
"plain",
|
||||
"highlighted",
|
||||
);
|
||||
}
|
||||
cluster.update(treeRows);
|
||||
const lineHeight = cluster.options.item_height;
|
||||
const scrollTop = outputContainerScroll.scrollTop;
|
||||
const containerHeight = outputContainerScroll.clientHeight;
|
||||
const offset = treeRowHighlightedIndex * lineHeight;
|
||||
if (scrollTop > offset - 20) {
|
||||
$(outputContainerScroll).animate({ scrollTop: offset - 20 }, 150);
|
||||
} else if (scrollTop < offset + lineHeight + 40 - containerHeight) {
|
||||
$(outputContainerScroll).animate(
|
||||
{ scrollTop: offset - containerHeight + 40 },
|
||||
150,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleTreeClick(event) {
|
||||
if (event.target.tagName === "A") {
|
||||
event.preventDefault();
|
||||
const [startRow, startColumn, endRow, endColumn] =
|
||||
event.target.dataset.range.split(",").map((n) => parseInt(n));
|
||||
codeEditor.focus();
|
||||
codeEditor.setSelection(
|
||||
{ line: startRow, ch: startColumn },
|
||||
{ line: endRow, ch: endColumn },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function handleLoggingChange() {
|
||||
if (loggingCheckbox.checked) {
|
||||
parser.setLogger((message, lexing) => {
|
||||
if (lexing) {
|
||||
console.log(" ", message);
|
||||
} else {
|
||||
console.log(message);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
parser.setLogger(null);
|
||||
}
|
||||
}
|
||||
|
||||
function handleQueryEnableChange() {
|
||||
if (queryCheckbox.checked) {
|
||||
queryContainer.style.visibility = "";
|
||||
queryContainer.style.position = "";
|
||||
} else {
|
||||
queryContainer.style.visibility = "hidden";
|
||||
queryContainer.style.position = "absolute";
|
||||
}
|
||||
handleQueryChange();
|
||||
}
|
||||
|
||||
function treeEditForEditorChange(change) {
|
||||
const oldLineCount = change.removed.length;
|
||||
const newLineCount = change.text.length;
|
||||
const lastLineLength = change.text[newLineCount - 1].length;
|
||||
|
||||
const startPosition = { row: change.from.line, column: change.from.ch };
|
||||
const oldEndPosition = { row: change.to.line, column: change.to.ch };
|
||||
const newEndPosition = {
|
||||
row: startPosition.row + newLineCount - 1,
|
||||
column:
|
||||
newLineCount === 1
|
||||
? startPosition.column + lastLineLength
|
||||
: lastLineLength,
|
||||
};
|
||||
|
||||
const startIndex = codeEditor.indexFromPos(change.from);
|
||||
let newEndIndex = startIndex + newLineCount - 1;
|
||||
let oldEndIndex = startIndex + oldLineCount - 1;
|
||||
for (let i = 0; i < newLineCount; i++) newEndIndex += change.text[i].length;
|
||||
for (let i = 0; i < oldLineCount; i++)
|
||||
oldEndIndex += change.removed[i].length;
|
||||
|
||||
return {
|
||||
startIndex,
|
||||
oldEndIndex,
|
||||
newEndIndex,
|
||||
startPosition,
|
||||
oldEndPosition,
|
||||
newEndPosition,
|
||||
};
|
||||
}
|
||||
|
||||
function colorForCaptureName(capture) {
|
||||
const id = query.captureNames.indexOf(capture);
|
||||
const isDark = document.querySelector('html').classList.contains('ayu') ||
|
||||
document.querySelector('html').classList.contains('coal') ||
|
||||
document.querySelector('html').classList.contains('navy');
|
||||
|
||||
const colors = isDark ? DARK_COLORS : LIGHT_COLORS;
|
||||
return colors[id % colors.length];
|
||||
}
|
||||
|
||||
function loadState() {
|
||||
const language = localStorage.getItem("language");
|
||||
const sourceCode = localStorage.getItem("sourceCode");
|
||||
const anonNodes = localStorage.getItem("anonymousNodes");
|
||||
const query = localStorage.getItem("query");
|
||||
const queryEnabled = localStorage.getItem("queryEnabled");
|
||||
if (language != null && sourceCode != null && query != null) {
|
||||
queryInput.value = query;
|
||||
codeInput.value = sourceCode;
|
||||
languageSelect.value = language;
|
||||
anonymousNodes.checked = anonNodes === "true";
|
||||
queryCheckbox.checked = queryEnabled === "true";
|
||||
}
|
||||
}
|
||||
|
||||
function saveState() {
|
||||
localStorage.setItem("language", languageSelect.value);
|
||||
localStorage.setItem("sourceCode", codeEditor.getValue());
|
||||
localStorage.setItem("anonymousNodes", anonymousNodes.checked);
|
||||
saveQueryState();
|
||||
}
|
||||
|
||||
function saveQueryState() {
|
||||
localStorage.setItem("queryEnabled", queryCheckbox.checked);
|
||||
localStorage.setItem("query", queryEditor.getValue());
|
||||
}
|
||||
|
||||
function debounce(func, wait, immediate) {
|
||||
var timeout;
|
||||
return function () {
|
||||
var context = this,
|
||||
args = arguments;
|
||||
var later = function () {
|
||||
timeout = null;
|
||||
if (!immediate) func.apply(context, args);
|
||||
};
|
||||
var callNow = immediate && !timeout;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
if (callNow) func.apply(context, args);
|
||||
};
|
||||
}
|
||||
};
|
||||
275
docs/src/assets/schemas/config.schema.json
Normal file
275
docs/src/assets/schemas/config.schema.json
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"$schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"grammars": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "The name of the grammar.",
|
||||
"pattern": "^[a-z0-9_]+$"
|
||||
},
|
||||
"camelcase": {
|
||||
"type": "string",
|
||||
"description": "The name converted to CamelCase.",
|
||||
"pattern": "^\\w+$",
|
||||
"examples": [
|
||||
"Rust",
|
||||
"HTML"
|
||||
],
|
||||
"$comment": "This is used in the description and the class names."
|
||||
},
|
||||
"scope": {
|
||||
"type": "string",
|
||||
"description": "The TextMate scope that represents this language.",
|
||||
"pattern": "^(source|text)(\\.\\w+)+$",
|
||||
"examples": [
|
||||
"source.rust",
|
||||
"text.html"
|
||||
]
|
||||
},
|
||||
"path": {
|
||||
"type": "string",
|
||||
"default": ".",
|
||||
"description": "The relative path to the directory containing the grammar."
|
||||
},
|
||||
"external-files": {
|
||||
"type": "array",
|
||||
"description": "The relative paths to files that should be checked for modifications during recompilation.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"file-types": {
|
||||
"type": "array",
|
||||
"description": "An array of filename suffix strings.",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"highlights": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": 1
|
||||
}
|
||||
],
|
||||
"default": "queries/highlights.scm",
|
||||
"description": "The path(s) to the grammar's highlight queries."
|
||||
},
|
||||
"injections": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": 1
|
||||
}
|
||||
],
|
||||
"default": "queries/injections.scm",
|
||||
"description": "The path(s) to the grammar's injection queries."
|
||||
},
|
||||
"locals": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": 1
|
||||
}
|
||||
],
|
||||
"default": "queries/locals.scm",
|
||||
"description": "The path(s) to the grammar's local variable queries."
|
||||
},
|
||||
"tags": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": 1
|
||||
}
|
||||
],
|
||||
"default": "queries/tags.scm",
|
||||
"description": "The path(s) to the grammar's code navigation queries."
|
||||
},
|
||||
"injection-regex": {
|
||||
"type": "string",
|
||||
"format": "regex",
|
||||
"description": "A regex pattern that will be tested against a language name in order to determine whether this language should be used for a potential language injection site."
|
||||
},
|
||||
"first-line-regex": {
|
||||
"type": "string",
|
||||
"format": "regex",
|
||||
"description": "A regex pattern that will be tested against the first line of a file in order to determine whether this language applies to the file."
|
||||
},
|
||||
"content-regex": {
|
||||
"type": "string",
|
||||
"format": "regex",
|
||||
"description": "A regex pattern that will be tested against the contents of the file in order to break ties in cases where multiple grammars matched the file."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"name",
|
||||
"scope"
|
||||
]
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"version": {
|
||||
"type": "string",
|
||||
"description": "The current version of the project.",
|
||||
"pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$",
|
||||
"$comment": "The CLI will use this version to update package.json, Cargo.toml, pyproject.toml, Makefile."
|
||||
},
|
||||
"license": {
|
||||
"type": "string",
|
||||
"default": "MIT",
|
||||
"description": "The project's license."
|
||||
},
|
||||
"description": {
|
||||
"type": "string",
|
||||
"description": "The project's description.",
|
||||
"examples": [
|
||||
"Rust grammar for tree-sitter"
|
||||
]
|
||||
},
|
||||
"links": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"repository": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "The project's repository."
|
||||
},
|
||||
"homepage": {
|
||||
"type": "string",
|
||||
"format": "uri",
|
||||
"description": "The project's homepage."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"repository"
|
||||
]
|
||||
},
|
||||
"authors": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "The project's author(s).",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"name"
|
||||
]
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"namespace": {
|
||||
"type": "string",
|
||||
"description": "The namespace for the Java & Kotlin packages.",
|
||||
"default": "io.github.tree-sitter",
|
||||
"$comment": "Used as is in the Maven/Gradle group name and transformed accordingly for the package names and directories (e.g. io.github.treesitter.jtreesitter.html - src/main/java/io/github/treesitter/jtreesitter/html)."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"version",
|
||||
"links"
|
||||
]
|
||||
},
|
||||
"bindings": {
|
||||
"type": "object",
|
||||
"description": "The language bindings that will be generated.",
|
||||
"properties": {
|
||||
"c": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"const": true,
|
||||
"$comment": "Always generated"
|
||||
},
|
||||
"go": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"java": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"kotlin": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"node": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"const": true,
|
||||
"$comment": "Always generated (for now)"
|
||||
},
|
||||
"python": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"rust": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"const": true,
|
||||
"$comment": "Always generated"
|
||||
},
|
||||
"swift": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"grammars",
|
||||
"metadata"
|
||||
]
|
||||
}
|
||||
322
docs/src/assets/schemas/grammar.schema.json
Normal file
322
docs/src/assets/schemas/grammar.schema.json
Normal file
|
|
@ -0,0 +1,322 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Tree-sitter grammar specification",
|
||||
"type": "object",
|
||||
|
||||
"required": ["name", "rules"],
|
||||
|
||||
"additionalProperties": false,
|
||||
|
||||
"properties": {
|
||||
"$schema": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
"name": {
|
||||
"description": "The name of the grammar",
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z_]\\w*"
|
||||
},
|
||||
|
||||
"inherits": {
|
||||
"description": "The name of the parent grammar",
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z_]\\w*"
|
||||
},
|
||||
|
||||
"rules": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z_]\\w*$": {
|
||||
"$ref": "#/definitions/rule"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"extras": {
|
||||
"type": "array",
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"$ref": "#/definitions/rule"
|
||||
}
|
||||
},
|
||||
|
||||
"precedences": {
|
||||
"type": "array",
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"type": "array",
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{ "type": "string" },
|
||||
{ "$ref": "#/definitions/symbol-rule" }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"reserved": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-zA-Z_]\\w*$": {
|
||||
"type": "array",
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"$ref": "#/definitions/rule"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
|
||||
"externals": {
|
||||
"type": "array",
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"$ref": "#/definitions/rule"
|
||||
}
|
||||
},
|
||||
|
||||
"inline": {
|
||||
"type": "array",
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z_]\\w*$"
|
||||
}
|
||||
},
|
||||
|
||||
"conflicts": {
|
||||
"type": "array",
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"type": "array",
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z_]\\w*$"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"word": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-zA-Z_]\\w*"
|
||||
},
|
||||
|
||||
"supertypes": {
|
||||
"description": "A list of hidden rule names that should be considered supertypes in the generated node types file. See https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types.",
|
||||
"type": "array",
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"description": "The name of a rule in `rules` or `extras`",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"definitions": {
|
||||
"blank-rule": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "BLANK"
|
||||
}
|
||||
},
|
||||
"required": ["type"]
|
||||
},
|
||||
|
||||
"string-rule": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "STRING"
|
||||
},
|
||||
"value": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["type", "value"]
|
||||
},
|
||||
|
||||
"pattern-rule": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "PATTERN"
|
||||
},
|
||||
"value": { "type": "string" },
|
||||
"flags": { "type": "string" }
|
||||
},
|
||||
"required": ["type", "value"]
|
||||
},
|
||||
|
||||
"symbol-rule": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "SYMBOL"
|
||||
},
|
||||
"name": { "type": "string" }
|
||||
},
|
||||
"required": ["type", "name"]
|
||||
},
|
||||
|
||||
"seq-rule": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "SEQ"
|
||||
},
|
||||
"members": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/rule"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["type", "members"]
|
||||
},
|
||||
|
||||
"choice-rule": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "CHOICE"
|
||||
},
|
||||
"members": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/rule"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["type", "members"]
|
||||
},
|
||||
|
||||
"alias-rule": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "ALIAS"
|
||||
},
|
||||
"value": { "type": "string" },
|
||||
"named": { "type": "boolean" },
|
||||
"content": {
|
||||
"$ref": "#/definitions/rule"
|
||||
}
|
||||
},
|
||||
"required": ["type", "named", "content", "value"]
|
||||
},
|
||||
|
||||
"repeat-rule": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "REPEAT"
|
||||
},
|
||||
"content": {
|
||||
"$ref": "#/definitions/rule"
|
||||
}
|
||||
},
|
||||
"required": ["type", "content"]
|
||||
},
|
||||
|
||||
"repeat1-rule": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "REPEAT1"
|
||||
},
|
||||
"content": {
|
||||
"$ref": "#/definitions/rule"
|
||||
}
|
||||
},
|
||||
"required": ["type", "content"]
|
||||
},
|
||||
|
||||
"token-rule": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"TOKEN",
|
||||
"IMMEDIATE_TOKEN"
|
||||
]
|
||||
},
|
||||
"content": {
|
||||
"$ref": "#/definitions/rule"
|
||||
}
|
||||
},
|
||||
"required": ["type", "content"]
|
||||
},
|
||||
|
||||
"field-rule": {
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "FIELD"
|
||||
},
|
||||
"content": {
|
||||
"$ref": "#/definitions/rule"
|
||||
}
|
||||
},
|
||||
"required": ["name", "type", "content"]
|
||||
},
|
||||
|
||||
"prec-rule": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"PREC",
|
||||
"PREC_LEFT",
|
||||
"PREC_RIGHT",
|
||||
"PREC_DYNAMIC"
|
||||
]
|
||||
},
|
||||
"value": {
|
||||
"oneof": [
|
||||
{ "type": "integer" },
|
||||
{ "type": "string" }
|
||||
]
|
||||
},
|
||||
"content": {
|
||||
"$ref": "#/definitions/rule"
|
||||
}
|
||||
},
|
||||
"required": ["type", "content", "value"]
|
||||
},
|
||||
|
||||
"rule": {
|
||||
"oneOf": [
|
||||
{ "$ref": "#/definitions/alias-rule" },
|
||||
{ "$ref": "#/definitions/blank-rule" },
|
||||
{ "$ref": "#/definitions/string-rule" },
|
||||
{ "$ref": "#/definitions/pattern-rule" },
|
||||
{ "$ref": "#/definitions/symbol-rule" },
|
||||
{ "$ref": "#/definitions/seq-rule" },
|
||||
{ "$ref": "#/definitions/choice-rule" },
|
||||
{ "$ref": "#/definitions/repeat1-rule" },
|
||||
{ "$ref": "#/definitions/repeat-rule" },
|
||||
{ "$ref": "#/definitions/token-rule" },
|
||||
{ "$ref": "#/definitions/field-rule" },
|
||||
{ "$ref": "#/definitions/prec-rule" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue