@pawel-up/jexl
Version:
Javascript Expression Language: Powerful context-based expression parser and evaluator
342 lines (280 loc) • 9.79 kB
Markdown
This document shows how to use the exported JSON schemas with various tools and editors.
This system uses JSON Schema (JSONSchema7) for standardized type definitions:
- **`types.ts`** - Shared type definitions using JSONSchema7
- **`utils.ts`** - Helper functions for creating and validating schemas with JSON Schema
- **`integrations.ts`** - Integration utilities for various editors and tools
- **`[library].schema.ts`** - Individual library schemas (array, string, math, date)
### Available Schema Files
- `array.schema.ts` - Array function schemas (using JSON Schema)
- `string.schema.ts` - String function schemas
- `math.schema.ts` - Math function schemas
- `date.schema.ts` - Date function schemas
### Creating New Schemas
Use the helper utilities to create new function schemas with JSON Schema:
```typescript
import { createFunctionSchema, createParameter, createLibrarySchema } from '@pawel-up/jexl/schemas/utils.js'
const myFunction = createFunctionSchema(
'myFunction',
'Description of my function',
'category',
[
createParameter('param1', 'Description of param1', { type: 'string' }),
createParameter('param2', 'Description of param2', { type: 'number' }, false),
],
{ type: 'boolean', description: 'Description of return value' },
{
examples: ['myFunction("test", 42) // true'],
}
)
const myLibrary = createLibrarySchema(
{ myFunction },
{
category: 'custom',
title: 'My Custom Library',
description: 'Custom functions for my use case',
version: '1.0.0',
}
)
```
Each function schema follows this structure:
```typescript
interface FunctionSchema {
name: string
description: string
category: string
parameters: FunctionParameter[]
returns: FunctionReturn
examples?: string[]
since?: string
deprecated?: boolean
}
interface FunctionParameter {
name: string
description: string
type: string
required: boolean
variadic?: boolean
defaultValue?: unknown
}
```
```typescript
import { arrayLibrarySchema } from '@pawel-up/jexl/schemas/schemas/array.schema.js'
import * as vscode from 'vscode'
// Provide autocompletion
export function provideCompletionItems(document: vscode.TextDocument, position: vscode.Position) {
const completionItems: vscode.CompletionItem[] = []
Object.values(arrayLibrarySchema.functions).forEach((func) => {
const item = new vscode.CompletionItem(func.name, vscode.CompletionItemKind.Function)
item.detail = func.description
item.documentation = new vscode.MarkdownString()
// Add parameters info
const params = func.parameters.map((p) => `${p.name}: ${p.type}`).join(', ')
item.documentation.appendMarkdown(`**${func.name}**(${params}) → ${func.returns.type}\n\n`)
item.documentation.appendMarkdown(`${func.description}\n\n`)
// Add examples
if (func.examples) {
item.documentation.appendMarkdown('**Examples:**\n')
func.examples.forEach((example) => {
item.documentation.appendMarkdown(`\`\`\`typescript\n${example}\n\`\`\`\n`)
})
}
completionItems.push(item)
})
return completionItems
}
```
```typescript
import { arrayLibrarySchema } from '@pawel-up/jexl/schemas/schemas/array.schema.js'
import { CompletionContext, CompletionResult } from '@codemirror/autocomplete'
// CodeMirror autocompletion
export function jexlCompletion(context: CompletionContext): CompletionResult | null {
const word = context.matchBefore(/\w*/)
if (!word) return null
const options = Object.values(arrayLibrarySchema.functions).map((func) => ({
label: func.name,
type: 'function',
info: func.description,
detail: `${func.name}(${func.parameters.map((p) => p.name).join(', ')}) → ${func.returns.type}`,
apply: func.name,
}))
return {
from: word.from,
options,
}
}
```
```typescript
import * as monaco from 'monaco-editor'
import { arrayLibrarySchema } from '@pawel-up/jexl/schemas/schemas/array.schema.js'
// Monaco Editor autocompletion
export function registerJexlLanguage() {
monaco.languages.register({ id: 'jexl' })
monaco.languages.registerCompletionItemProvider('jexl', {
provideCompletionItems: () => {
const suggestions = Object.values(arrayLibrarySchema.functions).map((func) => ({
label: func.name,
kind: monaco.languages.CompletionItemKind.Function,
detail: func.description,
documentation: {
value: [
`**${func.name}**(${func.parameters.map((p) => `${p.name}: ${p.type}`).join(', ')}) → ${func.returns.type}`,
'',
func.description,
'',
...(func.examples ? ['**Examples:**', ...func.examples.map((ex) => `\`${ex}\``)] : []),
].join('\n'),
},
insertText: func.name,
}))
return { suggestions }
},
})
}
```
```typescript
import { arrayLibrarySchema } from '@pawel-up/jexl/schemas/schemas/array.schema.js'
import { CompletionItem, CompletionItemKind } from 'vscode-languageserver'
export function getCompletionItems(): CompletionItem[] {
return Object.values(arrayLibrarySchema.functions).map((func) => ({
label: func.name,
kind: CompletionItemKind.Function,
detail: func.description,
documentation: {
kind: 'markdown',
value: [
`**${func.name}**(${func.parameters.map((p) => `${p.name}: ${p.type}`).join(', ')}) → ${func.returns.type}`,
'',
func.description,
'',
...(func.examples ? ['**Examples:**', ...func.examples.map((ex) => `\`${ex}\``)] : []),
].join('\n'),
},
}))
}
```
```typescript
import { arrayLibrarySchema } from '@pawel-up/jexl/schemas/schemas/array.schema.js'
import Ajv from 'ajv'
// Create JSON Schema for function call validation
export function createFunctionCallSchema(functionName: string) {
const func = arrayLibrarySchema.functions[functionName]
if (!func) throw new Error(`Function ${functionName} not found`)
return {
type: 'object',
properties: {
function: { const: functionName },
arguments: {
type: 'array',
items: func.parameters.map((param) => ({
type: param.type === 'any' ? undefined : param.type,
description: param.description,
})),
minItems: func.parameters.filter((p) => p.required).length,
maxItems: func.parameters.some((p) => p.variadic) ? undefined : func.parameters.length,
},
},
required: ['function', 'arguments'],
}
}
// Validate function calls
export function validateFunctionCall(functionName: string, args: unknown[]) {
const schema = createFunctionCallSchema(functionName)
const ajv = new Ajv()
const validate = ajv.compile(schema)
return validate({ function: functionName, arguments: args })
}
```
```typescript
import { arrayLibrarySchema } from '@pawel-up/jexl/schemas/schemas/array.schema.js'
// Generate markdown documentation
export function generateMarkdownDocs(): string {
const functions = Object.values(arrayLibrarySchema.functions)
return [
`
'',
arrayLibrarySchema.description,
'',
'## Functions',
'',
...functions
.map((func) => [
`
'',
func.description,
'',
'**Parameters:**',
'',
...func.parameters.map((p) => `- \`${p.name}\` (${p.type}${p.required ? '' : '?'}) - ${p.description}`),
'',
`**Returns:** ${func.returns.type} - ${func.returns.description}`,
'',
...(func.examples
? ['**Examples:**', '', ...func.examples.map((ex) => `\`\`\`typescript\n${ex}\n\`\`\``), '']
: []),
])
.flat(),
].join('\n')
}
```
```typescript
import { arrayLibrarySchema } from '@pawel-up/jexl/schemas/schemas/array.schema.js'
import * as arrayFunctions from './array'
// Dynamically register functions based on schema
export function registerFunctionsFromSchema(jexl: any) {
Object.entries(arrayLibrarySchema.functions).forEach(([name, schema]) => {
const func = (arrayFunctions as any)[name]
if (func) {
jexl.addFunction(name, func)
// Add metadata for runtime introspection
func._schema = schema
func._category = schema.category
func._parameters = schema.parameters
func._returns = schema.returns
}
})
}
```
The schemas are available in multiple formats:
```typescript
import { arrayLibrarySchema, arrayFunctionSchemas } from '@pawel-up/jexl/schemas/schemas/array.schema.js'
```
```typescript
import { arrayLibrarySchemaJSON } from '@pawel-up/jexl/schemas/schemas/array.schema.js'
const schema = JSON.parse(arrayLibrarySchemaJSON)
```
```json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://github.com/pawel-up/jexl/schemas/array.schema.json",
"title": "Jexl Array Functions",
"functions": {
"length": {
"name": "length",
"description": "Gets the length of an array",
"parameters": [...]
}
}
}
```
This schema-based approach enables:
- **IDE Integration** - Rich autocompletion and type hints
- **Validation** - Runtime validation of function calls
- **Documentation** - Automatic generation of docs
- **Tooling** - Easy integration with various editors and tools
- **Language Servers** - LSP support for any editor
- **Testing** - Schema-based test generation