diff --git a/samples/language-service-sample/app.js b/samples/language-service-sample/app.js index 09d0b17..e119bd8 100644 --- a/samples/language-service-sample/app.js +++ b/samples/language-service-sample/app.js @@ -43,6 +43,180 @@ window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) initTheme(); +// Examples data +const exampleCases = [ + { + id: 'math', + title: 'Mathematical Expression', + description: 'Basic math operations with variables', + expression: '(x + y) * multiplier + sqrt(16)', + context: { + x: 10, + y: 5, + multiplier: 3 + } + }, + { + id: 'arrays', + title: 'Working with Arrays', + description: 'Array functions like sum, min, max', + expression: 'sum(numbers) + max(numbers) - min(numbers)', + context: { + numbers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + values: [15, 25, 35] + } + }, + { + id: 'objects', + title: 'Object Manipulation', + description: 'Access nested object properties', + expression: 'user.profile.score * level.multiplier + bonus.points', + context: { + user: { + name: "Alice", + profile: { + score: 85, + rank: "Gold" + } + }, + level: { + current: 5, + multiplier: 1.5 + }, + bonus: { + points: 100, + active: true + } + } + }, + { + id: 'map-filter', + title: 'Map and Filter Functions', + description: 'Transform and filter data with callbacks', + expression: 'sum(map(filter(items, item => item > 3), x => x * 2))', + context: { + items: [1, 2, 3, 4, 5, 6, 7, 8], + threshold: 3 + } + }, + { + id: 'complex', + title: 'Complex Objects', + description: 'Work with deeply nested data structures', + expression: 'company.departments[0].employees.length * company.settings.bonusRate + sum(map(company.departments, d => d.budget))', + context: { + company: { + name: "TechCorp", + departments: [ + { + name: "Engineering", + budget: 500000, + employees: ["John", "Jane", "Bob"] + }, + { + name: "Marketing", + budget: 200000, + employees: ["Alice", "Carol"] + } + ], + settings: { + bonusRate: 0.15, + fiscalYear: 2024 + } + } + } + }, + { + id: 'data-transform', + title: 'Data Transformation', + description: 'Flatten nested objects and transform rows', + expression: "map(f(row) = {_id: row.rowId} + flatten(row.data, ''), $event)", + context: { + "$event": [ + {"rowId": 1, "state": "saved", "data": { "InventoryId": 1256, "Description": "Bal", "Weight": { "Unit": "g", "Amount": 120 } }}, + {"rowId": 2, "state": "new", "data": { "InventoryId": 2344, "Description": "Basket", "Weight": { "Unit": "g", "Amount": 300 } }}, + {"rowId": 3, "state": "unchanged", "data": { "InventoryId": 9362, "Description": "Wood", "Weight": { "Unit": "kg", "Amount": 18 } }} + ] + } + } +]; + +// Render examples sidebar +function renderExamplesSidebar() { + const examplesList = document.getElementById('examplesList'); + if (!examplesList) return; + + examplesList.innerHTML = exampleCases.map(example => ` + + `).join(''); + + // Add click handlers + examplesList.querySelectorAll('.example-item').forEach(button => { + button.addEventListener('click', () => { + const exampleId = button.dataset.exampleId; + const example = exampleCases.find(e => e.id === exampleId); + if (example) { + loadExample(example); + } + }); + }); +} + +// Load example into editors +function loadExample(example) { + if (typeof expressionEditor !== 'undefined' && expressionEditor) { + expressionEditor.getModel().setValue(example.expression); + } + if (typeof contextEditor !== 'undefined' && contextEditor) { + contextEditor.getModel().setValue(JSON.stringify(example.context, null, 2)); + } +} + +// Initialize sidebar +renderExamplesSidebar(); + +// Get example ID from URL query parameter +function getExampleFromUrl() { + const params = new URLSearchParams(window.location.search); + return params.get('example'); +} + +// Load example from URL if present (called after Monaco initializes) +function loadExampleFromUrl() { + const exampleId = getExampleFromUrl(); + if (exampleId) { + const example = exampleCases.find(e => e.id === exampleId); + if (example) { + loadExample(example); + return true; + } + } + return false; +} + // Split pane resizing (function() { const resizer = document.getElementById('resizer'); @@ -281,24 +455,22 @@ require(['vs/editor/editor.main'], function () { }); // Syntax highlighting + let highlightDecorations = []; + function applyHighlighting() { const doc = makeTextDocument(expressionModel); const tokens = ls.getHighlighting(doc); - const rangesByClass = new Map(); - for (const t of tokens) { + const decorations = tokens.map(t => { const start = expressionModel.getPositionAt(t.start); const end = expressionModel.getPositionAt(t.end); - const range = new monaco.Range(start.lineNumber, start.column, end.lineNumber, end.column); - const cls = 'tok-' + t.type; - if (!rangesByClass.has(cls)) rangesByClass.set(cls, []); - rangesByClass.get(cls).push({range, options: {inlineClassName: cls}}); - } - - window.__exprEvalDecos = window.__exprEvalDecos || {}; - for (const [cls, decos] of rangesByClass.entries()) { - const prev = window.__exprEvalDecos[cls] || []; - window.__exprEvalDecos[cls] = expressionEditor.deltaDecorations(prev, decos); - } + return { + range: new monaco.Range(start.lineNumber, start.column, end.lineNumber, end.column), + options: { inlineClassName: 'tok-' + t.type } + }; + }); + + // deltaDecorations replaces old decorations with new ones atomically + highlightDecorations = expressionEditor.deltaDecorations(highlightDecorations, decorations); } // Result display functions @@ -443,6 +615,9 @@ require(['vs/editor/editor.main'], function () { applyHighlighting(); evaluate(); + // Load example from URL query parameter if present + loadExampleFromUrl(); + // Event listeners for changes expressionModel.onDidChangeContent(() => { applyHighlighting(); diff --git a/samples/language-service-sample/index.html b/samples/language-service-sample/index.html index 3599fa1..64a550b 100644 --- a/samples/language-service-sample/index.html +++ b/samples/language-service-sample/index.html @@ -53,8 +53,21 @@