{"_id":"@archlex/language-service","_rev":"2-361ecce510cd236153f10348d6d087b8","name":"@archlex/language-service","dist-tags":{"latest":"0.2.1"},"versions":{"0.2.0":{"name":"@archlex/language-service","version":"0.2.0","keywords":["architecture","diagrams","language-service","lsp"],"author":{"name":"Alexis Sgarbossa"},"license":"MIT","_id":"@archlex/language-service@0.2.0","maintainers":[{"name":"baires","email":"alexis@sgarbossa.com.ar"}],"homepage":"https://github.com/baires/archlex#readme","bugs":{"url":"https://github.com/baires/archlex/issues"},"dist":{"shasum":"7652cce2ce448cfa9065cf17c8afbe4a19e270ae","tarball":"https://registry.npmjs.org/@archlex/language-service/-/language-service-0.2.0.tgz","fileCount":33,"integrity":"sha512-Jnd4kn9F54f3fvgGgRREmkFbXIVp3D24RQfiuwSBaS6v18EF8q4gmcp4oOcf7HL4eI/E9QUjbscSaLY10dGCsw==","signatures":[{"sig":"MEUCICdJvPgVUfAiD2ZzsYVfnl13dDPgM7BHMk52evcSI2YvAiEAr6ZixG+B48TTUoCdI1J0jKVasDn5Km4WwxXUS9spHwM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":127797},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"a50bfdd41b2086c74a14da6f678b7be404ecc31b","scripts":{"test":"vitest run --passWithNoTests","build":"vite build && tsc --emitDeclarationOnly","typecheck":"tsc --noEmit"},"_npmUser":{"name":"baires","email":"alexis@sgarbossa.com.ar"},"repository":{"url":"git+https://github.com/baires/archlex.git","type":"git","directory":"packages/language-service"},"_npmVersion":"10.9.2","description":"Editor-neutral language intelligence for ArchLex source","directories":{},"_nodeVersion":"23.7.0","dependencies":{"@archlex/model":"workspace:^","@archlex/parser":"workspace:^"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vite":"^6.1.0","vitest":"^3.0.5","typescript":"^5.7.3","@archlex/core":"workspace:*"},"_npmOperationalInternal":{"tmp":"tmp/language-service_0.2.0_1786830014824_0.9390854768177368","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@archlex/language-service","version":"0.2.1","description":"Editor-neutral language intelligence for ArchLex source","keywords":["architecture","diagrams","language-service","lsp"],"repository":{"type":"git","url":"git+https://github.com/baires/archlex.git","directory":"packages/language-service"},"license":"MIT","author":{"name":"Alexis Sgarbossa"},"type":"module","main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"}},"publishConfig":{"access":"public"},"dependencies":{"@archlex/model":"^0.6.0","@archlex/parser":"^0.6.1"},"devDependencies":{"typescript":"^5.7.3","vite":"^6.1.0","vitest":"^3.0.5","@archlex/core":"0.5.0"},"scripts":{"build":"vite build && tsc --emitDeclarationOnly","typecheck":"tsc --noEmit","test":"vitest run --passWithNoTests"},"_id":"@archlex/language-service@0.2.1","bugs":{"url":"https://github.com/baires/archlex/issues"},"homepage":"https://github.com/baires/archlex#readme","_integrity":"sha512-6uwdlMX9t4CASlnbh7/znQ5EkVj2CgGCVCTlSaYC3f2wd6DmM4njVPBkfRtJZhK20ERlOxKcCzF6BODwqc7mkQ==","_resolved":"/tmp/7e212001600ac18ba9deb101d1d89ca6/archlex-language-service-0.2.1.tgz","_from":"file:archlex-language-service-0.2.1.tgz","_nodeVersion":"24.19.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-6uwdlMX9t4CASlnbh7/znQ5EkVj2CgGCVCTlSaYC3f2wd6DmM4njVPBkfRtJZhK20ERlOxKcCzF6BODwqc7mkQ==","shasum":"9bd913d2c1cb56702af9f6b1f567b705793f9335","tarball":"https://registry.npmjs.org/@archlex/language-service/-/language-service-0.2.1.tgz","fileCount":33,"unpackedSize":117477,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@archlex%2flanguage-service@0.2.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIG4sVe+cZBM0ZAvGqlLV5zQ7o3awap25ryGhlobo48WZAiA07LeAav+jVPtfU4z7Q5YcWhSfjKNXIo04BQt5jzyNNA=="}]},"_npmUser":{"name":"baires","email":"alexis@sgarbossa.com.ar"},"directories":{},"maintainers":[{"name":"baires","email":"alexis@sgarbossa.com.ar"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/language-service_0.2.1_1787347477492_0.3590316466763295"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-15T21:40:14.666Z","modified":"2026-08-21T21:24:37.984Z","0.2.0":"2026-08-15T21:40:14.975Z","0.2.1":"2026-08-21T21:24:37.645Z"},"bugs":{"url":"https://github.com/baires/archlex/issues"},"author":{"name":"Alexis Sgarbossa"},"license":"MIT","homepage":"https://github.com/baires/archlex#readme","keywords":["architecture","diagrams","language-service","lsp"],"repository":{"type":"git","url":"git+https://github.com/baires/archlex.git","directory":"packages/language-service"},"description":"Editor-neutral language intelligence for ArchLex source","maintainers":[{"name":"baires","email":"alexis@sgarbossa.com.ar"}],"readme":"# @archlex/language-service\n\nEditor-neutral language intelligence for ArchLex source code.\n\n## Overview\n\n`@archlex/language-service` provides context-aware code completion for ArchLex diagrams. It analyzes ArchLex source, understands the current cursor position, and suggests relevant completions based on:\n\n- **Catalog metadata** - Service names, relationships, and containment rules from provider catalogs\n- **Search terms** - Human-readable names and descriptions for fuzzy matching\n- **Document structure** - Current provider, scope hierarchy, and declared symbols\n- **Grammar context** - Directive values, resource kinds, relationship types, and scope keywords\n\nThis package is DOM-neutral and works in both browser and Node.js environments without dependencies on Monaco, VSCode, or any specific editor framework.\n\n## Installation\n\n```bash\npnpm add @archlex/language-service\n```\n\n## Usage\n\n### Basic Example (Non-Monaco)\n\n```typescript\nimport { createCompletionEngine, analyzeLanguageDocument } from \"@archlex/language-service\";\nimport { createArchLex, awsProvider, gcpProvider, k8sProvider } from \"@archlex/core\";\n\n// Create a completion engine with catalog metadata\nconst archlex = createArchLex({ providers: [awsProvider(), gcpProvider(), k8sProvider()] });\nconst catalog = archlex.getCatalog();\nconst engine = createCompletionEngine(catalog);\n\n// Analyze a document\nconst source = \"provider aws\\nservice: elastic kubernetes\";\nconst document = analyzeLanguageDocument(source);\n\n// Get completions at cursor position\nconst offset = source.length; // cursor at end\nconst suggestions = engine.complete(document, offset);\n\n// suggestions = [\n//   {\n//     label: \"Amazon EKS\",\n//     insertText: \"eks\",\n//     kind: \"resource\",\n//     searchTerms: [\"elastic\", \"kubernetes\", \"eks\"],\n//     replacement: { startOffset: 21, endOffset: 41 }\n//   },\n//   ...\n// ]\n```\n\n### Monaco Integration Example\n\n```typescript\nimport * as monaco from \"monaco-editor\";\nimport { createCompletionEngine, analyzeLanguageDocument } from \"@archlex/language-service\";\nimport { createArchLex, awsProvider } from \"@archlex/core\";\n\n// Create engine\nconst archlex = createArchLex({ providers: [awsProvider()] });\nconst catalog = archlex.getCatalog();\nconst engine = createCompletionEngine(catalog);\n\n// Register Monaco provider\nconst disposable = monaco.languages.registerCompletionItemProvider(\"archlex\", {\n  triggerCharacters: [\":\", \".\", \"[\", \"-\"],\n\n  provideCompletionItems(model, position) {\n    const source = model.getValue();\n    const document = analyzeLanguageDocument(source);\n    const offset = model.getOffsetAt(position);\n\n    const completions = engine.complete(document, offset);\n\n    return {\n      suggestions: completions.map(c => ({\n        label: c.label,\n        insertText: c.insertText,\n        kind: monaco.languages.CompletionItemKind.Value,\n        range: {\n          startLineNumber: model.getPositionAt(c.replacement.startOffset).lineNumber,\n          startColumn: model.getPositionAt(c.replacement.startOffset).column,\n          endLineNumber: model.getPositionAt(c.replacement.endOffset).lineNumber,\n          endColumn: model.getPositionAt(c.replacement.endOffset).column,\n        }\n      }))\n    };\n  }\n});\n\n// Clean up when done\ndisposable.dispose();\n```\n\n## API Reference\n\n### `analyzeLanguageDocument(source: string)`\n\nParses ArchLex source and extracts structured metadata for completion.\n\n**Returns:** `LanguageDocument`\n- `source` - Original source text\n- `providerId` - Current provider (`\"aws\"`, `\"gcp\"`, `\"k8s\"`, or `null`)\n- `scopePath` - Current containment hierarchy (e.g., `[\"account\", \"region\", \"vpc\"]`)\n- `symbols` - Array of declared resource symbols with names, kinds, and positions\n- `directives` - Parsed directives (provider, direction, validation)\n\n### `createCompletionEngine(catalog: CatalogMetadata)`\n\nCreates a completion engine backed by catalog metadata.\n\n**Parameters:**\n- `catalog` - Catalog metadata from `archlex.getCatalog()`\n\n**Returns:** `CompletionEngine`\n\n### `CompletionEngine.complete(document: LanguageDocument, offset: number, options?: CompletionOptions)`\n\nGenerates context-aware completions at the given offset.\n\n**Parameters:**\n- `document` - Analyzed language document\n- `offset` - Cursor position (0-based byte offset)\n- `options` - Optional settings\n  - `trigger?: \"manual\" | \"automatic\"` - How completion was invoked\n\n**Returns:** `LanguageCompletion[]`\n\n### `LanguageCompletion`\n\n```typescript\ninterface LanguageCompletion {\n  label: string;           // Display label (e.g., \"Amazon EKS\")\n  insertText: string;      // Text to insert (e.g., \"eks\")\n  kind: CompletionKind;    // \"directive\" | \"resource\" | \"relationship\" | \"scope\"\n  searchTerms: string[];   // Terms for fuzzy matching\n  replacement: {\n    startOffset: number;   // Start of range to replace\n    endOffset: number;     // End of range to replace\n  };\n}\n```\n\n### `getCursorContext(document: LanguageDocument, offset: number)`\n\nDetermines the syntactic position at the cursor for context-aware completions.\n\n**Returns:** `CursorContext`\n- `position` - Grammar position (`\"directive-name\"`, `\"resource-kind\"`, `\"relationship-type\"`, etc.)\n- `providerId` - Current provider\n- `scopePath` - Current scope hierarchy\n- `partialText` - Text being typed at cursor\n\n### `createCatalogIndex(catalog: CatalogMetadata)`\n\nCreates a fast lookup index for catalog resources and relationships.\n\n**Returns:** `CatalogIndex`\n- `resolveResource(provider, kindOrAlias)` - O(1) resource lookup\n- `searchResources(provider, query)` - Fuzzy search by human names\n- `listResources(provider)` - All resources for a provider\n- `getRelationships(provider, sourceKind, targetKind)` - Valid relationships\n\n## Features\n\n### Catalog-Driven Completions\n\nAll service names, relationships, and containment rules come from provider catalogs:\n- **194 AWS services** with relationships and containment\n- **185 GCP services** with relationships and containment\n- **62 Kubernetes resources** with relationships and containment\n\n### Human-Readable Search\n\nCompletions include searchable terms from service descriptions:\n- Typing \"elastic kubernetes\" suggests `eks` (Amazon EKS)\n- Typing \"relational\" suggests `rds` (Amazon RDS) and `aurora` (Amazon Aurora)\n- Typing \"forward\" suggests `forwards` relationship\n\n### Context-Aware Filtering\n\nThe engine filters suggestions based on:\n- **Current provider** - Only shows AWS services when `provider aws` is set\n- **Scope hierarchy** - Only shows resources valid in current containment (e.g., `ecs` inside `cluster`)\n- **Symbol visibility** - Suggests declared resource identifiers for relationships\n- **Grammar position** - Different suggestions after `:`, `[`, or in directive positions\n\n### Semantic Ranking\n\nResults are ranked by:\n1. **Exact prefix match** - `lam` → `lambda` ranks higher\n2. **Search term relevance** - Fuzzy match quality against human names\n3. **Relationship compatibility** - Valid relationships for source/target resources\n\n### Canonical Insertion\n\nCompletions always insert canonical syntax:\n- Service kinds use lowercase kebab-case: `eks`, `cloud-run`, `statefulset`\n- Relationships use lowercase: `connects`, `writes`, `publishes`\n- Directives preserve required format: `provider aws`, `direction LR`\n\n## Grammar Context Detection\n\nThe engine understands cursor position in the grammar:\n\n| Context | Example | Completions |\n|---------|---------|-------------|\n| **Directive name** | `prov█` | `provider`, `direction`, `validation` |\n| **Directive value** | `provider █` | `aws`, `gcp`, `k8s` |\n| **Resource kind** | `service: █` | AWS/GCP/K8s services |\n| **Resource name** | `█: lambda` | Identifier suggestions |\n| **Relationship type** | `a -[█` | `connects`, `writes`, etc. |\n| **Relationship target** | `a -[writes]-> █` | Declared identifiers |\n\n## Performance\n\n- **Document caching** - WeakMap-based cache for repeated completions\n- **Incremental updates** - Only re-parses when document version changes\n- **Fast lookups** - O(1) catalog access, O(log n) search term matching\n- **Browser tested** - Meets <50ms p95 latency on 100+ declaration documents\n\n## Architecture\n\n- **DOM-Neutral**: No browser or editor dependencies - works in Node.js, browsers, and workers\n- **Immutable**: All document and completion objects are readonly\n- **Editor-agnostic**: Works with Monaco, VSCode, CodeMirror, or any editor supporting offsets\n\n## TypeScript Support\n\nFully typed with exported interfaces:\n- `LanguageDocument`\n- `CompletionEngine`\n- `LanguageCompletion`\n- `CompletionKind`\n- `CursorContext`\n- `CatalogIndex`\n\n## License\n\nMIT\n","readmeFilename":"README.md"}