@zenithbuild/language-server 0.6.1 → 0.6.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/imports.ts DELETED
@@ -1,207 +0,0 @@
1
- /**
2
- * Import Resolution & Awareness
3
- *
4
- * Handles recognition and resolution of Zenith imports.
5
- * - zenith/* imports are core modules (virtual, symbolic resolution)
6
- * - zenith:* imports are plugin modules (soft diagnostics if missing)
7
- */
8
-
9
- import {
10
- CORE_MODULES,
11
- getCoreModule,
12
- getCoreExport,
13
- isCoreModule,
14
- type CoreModuleMetadata,
15
- type ModuleExport
16
- } from './metadata/core-imports';
17
-
18
- import {
19
- PLUGIN_MODULES,
20
- getPluginModule,
21
- getPluginExport,
22
- isPluginModule,
23
- isKnownPluginModule,
24
- type PluginModuleMetadata,
25
- type PluginExport
26
- } from './metadata/plugin-imports';
27
-
28
- export interface ParsedImport {
29
- module: string;
30
- specifiers: string[];
31
- isType: boolean;
32
- line: number;
33
- }
34
-
35
- export interface ResolvedImport {
36
- module: string;
37
- kind: 'core' | 'plugin' | 'external';
38
- metadata?: CoreModuleMetadata | PluginModuleMetadata;
39
- isKnown: boolean;
40
- }
41
-
42
- /**
43
- * Parse Zenith imports from script content
44
- */
45
- export function parseZenithImports(script: string): ParsedImport[] {
46
- const imports: ParsedImport[] = [];
47
- const lines = script.split('\n');
48
-
49
- for (let i = 0; i < lines.length; i++) {
50
- const line = lines[i];
51
-
52
- // Match: import { x, y } from 'module' or import type { x } from 'module'
53
- const importMatch = line.match(/import\s+(type\s+)?(?:\{([^}]+)\}|(\*\s+as\s+\w+)|(\w+))\s+from\s+['"]([^'"]+)['"]/);
54
-
55
- if (importMatch) {
56
- const isType = !!importMatch[1];
57
- const namedImports = importMatch[2];
58
- const namespaceImport = importMatch[3];
59
- const defaultImport = importMatch[4];
60
- const moduleName = importMatch[5];
61
-
62
- // Only track zenith imports
63
- if (moduleName.startsWith('zenith') || moduleName.startsWith('zenith:')) {
64
- const specifiers: string[] = [];
65
-
66
- if (namedImports) {
67
- // Parse named imports: { a, b as c, d }
68
- const parts = namedImports.split(',');
69
- for (const part of parts) {
70
- const cleaned = part.trim().split(/\s+as\s+/)[0].trim();
71
- if (cleaned) specifiers.push(cleaned);
72
- }
73
- } else if (namespaceImport) {
74
- specifiers.push(namespaceImport.trim());
75
- } else if (defaultImport) {
76
- specifiers.push(defaultImport);
77
- }
78
-
79
- imports.push({
80
- module: moduleName,
81
- specifiers,
82
- isType,
83
- line: i + 1
84
- });
85
- }
86
- }
87
-
88
- // Match: import 'module' (side-effect import)
89
- const sideEffectMatch = line.match(/import\s+['"]([^'"]+)['"]/);
90
- if (sideEffectMatch && !importMatch) {
91
- const moduleName = sideEffectMatch[1];
92
- if (moduleName.startsWith('zenith') || moduleName.startsWith('zenith:')) {
93
- imports.push({
94
- module: moduleName,
95
- specifiers: [],
96
- isType: false,
97
- line: i + 1
98
- });
99
- }
100
- }
101
- }
102
-
103
- return imports;
104
- }
105
-
106
- /**
107
- * Resolve a module name to its metadata
108
- */
109
- export function resolveModule(moduleName: string): ResolvedImport {
110
- if (isCoreModule(moduleName)) {
111
- return {
112
- module: moduleName,
113
- kind: 'core',
114
- metadata: getCoreModule(moduleName),
115
- isKnown: true
116
- };
117
- }
118
-
119
- if (isPluginModule(moduleName)) {
120
- return {
121
- module: moduleName,
122
- kind: 'plugin',
123
- metadata: getPluginModule(moduleName),
124
- isKnown: isKnownPluginModule(moduleName)
125
- };
126
- }
127
-
128
- return {
129
- module: moduleName,
130
- kind: 'external',
131
- isKnown: false
132
- };
133
- }
134
-
135
- /**
136
- * Get export metadata for a specific import
137
- */
138
- export function resolveExport(moduleName: string, exportName: string): ModuleExport | PluginExport | undefined {
139
- if (isCoreModule(moduleName)) {
140
- return getCoreExport(moduleName, exportName);
141
- }
142
-
143
- if (isKnownPluginModule(moduleName)) {
144
- return getPluginExport(moduleName, exportName);
145
- }
146
-
147
- return undefined;
148
- }
149
-
150
- /**
151
- * Check if router is imported in the given imports
152
- */
153
- export function hasRouterImport(imports: ParsedImport[]): boolean {
154
- return imports.some(i => i.module === 'zenith/router');
155
- }
156
-
157
- /**
158
- * Check if a specific export is imported
159
- */
160
- export function hasImport(imports: ParsedImport[], exportName: string): boolean {
161
- return imports.some(i => i.specifiers.includes(exportName));
162
- }
163
-
164
- /**
165
- * Get all available modules for completion
166
- */
167
- export function getAllModules(): Array<{ module: string; kind: 'core' | 'plugin'; description: string }> {
168
- const modules: Array<{ module: string; kind: 'core' | 'plugin'; description: string }> = [];
169
-
170
- for (const [name, meta] of Object.entries(CORE_MODULES)) {
171
- modules.push({
172
- module: name,
173
- kind: 'core',
174
- description: meta.description
175
- });
176
- }
177
-
178
- for (const [name, meta] of Object.entries(PLUGIN_MODULES)) {
179
- modules.push({
180
- module: name,
181
- kind: 'plugin',
182
- description: meta.description
183
- });
184
- }
185
-
186
- return modules;
187
- }
188
-
189
- /**
190
- * Get exports for completion from a module
191
- */
192
- export function getModuleExports(moduleName: string): Array<ModuleExport | PluginExport> {
193
- const coreModule = getCoreModule(moduleName);
194
- if (coreModule) return coreModule.exports;
195
-
196
- const pluginModule = getPluginModule(moduleName);
197
- if (pluginModule) return pluginModule.exports;
198
-
199
- return [];
200
- }
201
-
202
- // Re-export utilities
203
- export { isPluginModule } from './metadata/plugin-imports';
204
-
205
- // Re-export types
206
- export type { CoreModuleMetadata, ModuleExport } from './metadata/core-imports';
207
- export type { PluginModuleMetadata, PluginExport } from './metadata/plugin-imports';
@@ -1,163 +0,0 @@
1
- /**
2
- * Core Import Metadata
3
- *
4
- * Static metadata for Zenith core modules.
5
- * These are virtual modules resolved symbolically (no FS probing).
6
- */
7
-
8
- export interface ModuleExport {
9
- name: string;
10
- kind: 'function' | 'component' | 'type' | 'variable';
11
- description: string;
12
- signature?: string;
13
- }
14
-
15
- export interface CoreModuleMetadata {
16
- module: string;
17
- description: string;
18
- exports: ModuleExport[];
19
- }
20
-
21
- /**
22
- * Core Zenith module exports
23
- */
24
- export const CORE_MODULES: Record<string, CoreModuleMetadata> = {
25
- 'zenith': {
26
- module: 'zenith',
27
- description: 'Core Zenith runtime primitives and lifecycle hooks.',
28
- exports: [
29
- {
30
- name: 'zenEffect',
31
- kind: 'function',
32
- description: 'Reactive effect that re-runs when dependencies change.',
33
- signature: 'zenEffect(callback: () => void | (() => void)): void'
34
- },
35
- {
36
- name: 'zenOnMount',
37
- kind: 'function',
38
- description: 'Called when component is mounted to the DOM.',
39
- signature: 'zenOnMount(callback: () => void | (() => void)): void'
40
- },
41
- {
42
- name: 'zenOnDestroy',
43
- kind: 'function',
44
- description: 'Called when component is removed from the DOM.',
45
- signature: 'zenOnDestroy(callback: () => void): void'
46
- },
47
- {
48
- name: 'zenOnUpdate',
49
- kind: 'function',
50
- description: 'Called after any state update causes a re-render.',
51
- signature: 'zenOnUpdate(callback: () => void): void'
52
- },
53
- {
54
- name: 'zenRef',
55
- kind: 'function',
56
- description: 'Create a reactive reference.',
57
- signature: 'zenRef<T>(initial: T): { value: T }'
58
- },
59
- {
60
- name: 'zenState',
61
- kind: 'function',
62
- description: 'Create reactive state.',
63
- signature: 'zenState<T>(initial: T): [T, (value: T) => void]'
64
- },
65
- {
66
- name: 'zenMemo',
67
- kind: 'function',
68
- description: 'Memoize a computed value.',
69
- signature: 'zenMemo<T>(compute: () => T): T'
70
- },
71
- {
72
- name: 'zenBatch',
73
- kind: 'function',
74
- description: 'Batch multiple state updates.',
75
- signature: 'zenBatch(callback: () => void): void'
76
- },
77
- {
78
- name: 'zenUntrack',
79
- kind: 'function',
80
- description: 'Run code without tracking dependencies.',
81
- signature: 'zenUntrack<T>(callback: () => T): T'
82
- }
83
- ]
84
- },
85
- 'zenith/router': {
86
- module: 'zenith/router',
87
- description: 'File-based SPA router for Zenith framework.',
88
- exports: [
89
- {
90
- name: 'ZenLink',
91
- kind: 'component',
92
- description: 'Declarative navigation component for routes.',
93
- signature: '<ZenLink to="/path" preload?>{children}</ZenLink>'
94
- },
95
- {
96
- name: 'useRoute',
97
- kind: 'function',
98
- description: 'Provides reactive access to the current route. Must be called at top-level script scope.',
99
- signature: 'useRoute(): { path: string; params: Record<string, string>; query: Record<string, string> }'
100
- },
101
- {
102
- name: 'useRouter',
103
- kind: 'function',
104
- description: 'Provides programmatic navigation methods.',
105
- signature: 'useRouter(): { navigate: (to: string, options?: { replace?: boolean }) => void; back: () => void; forward: () => void }'
106
- },
107
- {
108
- name: 'navigate',
109
- kind: 'function',
110
- description: 'Navigate to a route programmatically.',
111
- signature: 'navigate(to: string, options?: { replace?: boolean }): void'
112
- },
113
- {
114
- name: 'prefetch',
115
- kind: 'function',
116
- description: 'Prefetch a route for faster navigation.',
117
- signature: 'prefetch(path: string): Promise<void>'
118
- },
119
- {
120
- name: 'isActive',
121
- kind: 'function',
122
- description: 'Check if a route is currently active.',
123
- signature: 'isActive(path: string, exact?: boolean): boolean'
124
- },
125
- {
126
- name: 'getRoute',
127
- kind: 'function',
128
- description: 'Get the current route state.',
129
- signature: 'getRoute(): { path: string; params: Record<string, string>; query: Record<string, string> }'
130
- }
131
- ]
132
- }
133
- };
134
-
135
- /**
136
- * Get a core module by name
137
- */
138
- export function getCoreModule(moduleName: string): CoreModuleMetadata | undefined {
139
- return CORE_MODULES[moduleName];
140
- }
141
-
142
- /**
143
- * Get all core module names
144
- */
145
- export function getCoreModuleNames(): string[] {
146
- return Object.keys(CORE_MODULES);
147
- }
148
-
149
- /**
150
- * Get an export from a core module
151
- */
152
- export function getCoreExport(moduleName: string, exportName: string): ModuleExport | undefined {
153
- const module = CORE_MODULES[moduleName];
154
- if (!module) return undefined;
155
- return module.exports.find(e => e.name === exportName);
156
- }
157
-
158
- /**
159
- * Check if a module is a core Zenith module
160
- */
161
- export function isCoreModule(moduleName: string): boolean {
162
- return moduleName in CORE_MODULES;
163
- }
@@ -1,109 +0,0 @@
1
- /**
2
- * Directive Metadata
3
- *
4
- * Compile-time directive definitions for Zenith.
5
- * These are compiler directives, not runtime attributes.
6
- */
7
-
8
- export interface DirectiveMetadata {
9
- name: string;
10
- category: 'control-flow' | 'iteration' | 'reactive-effect' | 'conditional-visibility';
11
- description: string;
12
- syntax: string;
13
- placement: ('element' | 'component')[];
14
- example: string;
15
- createsScope?: boolean;
16
- scopeVariables?: string[];
17
- }
18
-
19
- /**
20
- * All Zenith compiler directives
21
- *
22
- * These are processed at compile-time and transformed into static DOM instructions.
23
- * The LSP must describe these directives without assuming runtime behavior.
24
- */
25
- export const DIRECTIVES: Record<string, DirectiveMetadata> = {
26
- 'zen:if': {
27
- name: 'zen:if',
28
- category: 'control-flow',
29
- description: 'Compile-time conditional directive. Conditionally renders the element based on a boolean expression.',
30
- syntax: 'zen:if="condition"',
31
- placement: ['element', 'component'],
32
- example: '<div zen:if="isVisible">Conditionally rendered</div>'
33
- },
34
- 'zen:for': {
35
- name: 'zen:for',
36
- category: 'iteration',
37
- description: 'Compile-time iteration directive. Repeats the element for each item in a collection.',
38
- syntax: 'zen:for="item in items" or zen:for="item, index in items"',
39
- placement: ['element', 'component'],
40
- example: '<li zen:for="item in items">{item.name}</li>',
41
- createsScope: true,
42
- scopeVariables: ['item', 'index']
43
- },
44
- 'zen:effect': {
45
- name: 'zen:effect',
46
- category: 'reactive-effect',
47
- description: 'Compile-time reactive effect directive. Attaches a side effect to the element lifecycle.',
48
- syntax: 'zen:effect="expression"',
49
- placement: ['element', 'component'],
50
- example: '<div zen:effect="console.log(\'rendered\')">Content</div>'
51
- },
52
- 'zen:show': {
53
- name: 'zen:show',
54
- category: 'conditional-visibility',
55
- description: 'Compile-time visibility directive. Toggles element visibility without removing from DOM.',
56
- syntax: 'zen:show="condition"',
57
- placement: ['element', 'component'],
58
- example: '<div zen:show="isOpen">Toggle visibility</div>'
59
- }
60
- };
61
-
62
- /**
63
- * Check if a string is a valid directive name
64
- */
65
- export function isDirective(name: string): name is keyof typeof DIRECTIVES {
66
- return name in DIRECTIVES;
67
- }
68
-
69
- /**
70
- * Get directive metadata by name
71
- */
72
- export function getDirective(name: string): DirectiveMetadata | undefined {
73
- return DIRECTIVES[name];
74
- }
75
-
76
- /**
77
- * Get all directive names
78
- */
79
- export function getDirectiveNames(): string[] {
80
- return Object.keys(DIRECTIVES);
81
- }
82
-
83
- /**
84
- * Check if a directive can be placed on a specific element type
85
- */
86
- export function canPlaceDirective(directiveName: string, elementType: 'element' | 'component' | 'slot'): boolean {
87
- const directive = DIRECTIVES[directiveName];
88
- if (!directive) return false;
89
-
90
- // Directives cannot be placed on <slot>
91
- if (elementType === 'slot') return false;
92
-
93
- return directive.placement.includes(elementType as 'element' | 'component');
94
- }
95
-
96
- /**
97
- * Parse a zen:for expression to extract variables
98
- */
99
- export function parseForExpression(expression: string): { itemVar: string; indexVar?: string; source: string } | null {
100
- // Match: "item in items" or "item, index in items"
101
- const match = expression.match(/^\s*([a-zA-Z_$][\w$]*)(?:\s*,\s*([a-zA-Z_$][\w$]*))?\s+in\s+(.+)\s*$/);
102
- if (!match) return null;
103
-
104
- return {
105
- itemVar: match[1],
106
- indexVar: match[2],
107
- source: match[3].trim()
108
- };
109
- }
@@ -1,116 +0,0 @@
1
- /**
2
- * Plugin Import Metadata
3
- *
4
- * Static metadata for Zenith plugin modules.
5
- * Plugin modules use the zenith:* namespace.
6
- *
7
- * Important: The LSP must NOT assume plugin presence.
8
- * If a plugin is not installed, diagnostics should be soft warnings, not errors.
9
- */
10
-
11
- export interface PluginExport {
12
- name: string;
13
- kind: 'function' | 'type' | 'variable';
14
- description: string;
15
- signature?: string;
16
- }
17
-
18
- export interface PluginModuleMetadata {
19
- module: string;
20
- description: string;
21
- exports: PluginExport[];
22
- required: boolean;
23
- }
24
-
25
- /**
26
- * Known Zenith plugin modules
27
- */
28
- export const PLUGIN_MODULES: Record<string, PluginModuleMetadata> = {
29
- 'zenith:content': {
30
- module: 'zenith:content',
31
- description: 'Content collections plugin for Zenith. Provides type-safe content management for Markdown, MDX, and JSON files.',
32
- exports: [
33
- {
34
- name: 'zenCollection',
35
- kind: 'function',
36
- description: 'Define a content collection with schema validation.',
37
- signature: 'zenCollection<T>(options: { name: string; schema: T }): Collection<T>'
38
- },
39
- {
40
- name: 'getCollection',
41
- kind: 'function',
42
- description: 'Get all entries from a content collection.',
43
- signature: 'getCollection(name: string): Promise<CollectionEntry[]>'
44
- },
45
- {
46
- name: 'getEntry',
47
- kind: 'function',
48
- description: 'Get a single entry from a content collection.',
49
- signature: 'getEntry(collection: string, slug: string): Promise<CollectionEntry | undefined>'
50
- },
51
- {
52
- name: 'useZenOrder',
53
- kind: 'function',
54
- description: 'Hook to sort collection entries by frontmatter order field.',
55
- signature: 'useZenOrder(entries: CollectionEntry[]): CollectionEntry[]'
56
- }
57
- ],
58
- required: false
59
- },
60
- 'zenith:image': {
61
- module: 'zenith:image',
62
- description: 'Image optimization plugin for Zenith.',
63
- exports: [
64
- {
65
- name: 'Image',
66
- kind: 'function',
67
- description: 'Optimized image component with automatic format conversion and lazy loading.',
68
- signature: 'Image({ src: string; alt: string; width?: number; height?: number })'
69
- },
70
- {
71
- name: 'getImage',
72
- kind: 'function',
73
- description: 'Get optimized image metadata.',
74
- signature: 'getImage(src: string, options?: ImageOptions): Promise<ImageMetadata>'
75
- }
76
- ],
77
- required: false
78
- }
79
- };
80
-
81
- /**
82
- * Get a plugin module by name
83
- */
84
- export function getPluginModule(moduleName: string): PluginModuleMetadata | undefined {
85
- return PLUGIN_MODULES[moduleName];
86
- }
87
-
88
- /**
89
- * Get all plugin module names
90
- */
91
- export function getPluginModuleNames(): string[] {
92
- return Object.keys(PLUGIN_MODULES);
93
- }
94
-
95
- /**
96
- * Get an export from a plugin module
97
- */
98
- export function getPluginExport(moduleName: string, exportName: string): PluginExport | undefined {
99
- const module = PLUGIN_MODULES[moduleName];
100
- if (!module) return undefined;
101
- return module.exports.find(e => e.name === exportName);
102
- }
103
-
104
- /**
105
- * Check if a module is a plugin module (zenith:* namespace)
106
- */
107
- export function isPluginModule(moduleName: string): boolean {
108
- return moduleName.startsWith('zenith:');
109
- }
110
-
111
- /**
112
- * Check if a plugin module is known
113
- */
114
- export function isKnownPluginModule(moduleName: string): boolean {
115
- return moduleName in PLUGIN_MODULES;
116
- }