11import * as vscode from 'vscode' ;
2- import * as path from 'path' ;
3- import * as fs from 'fs' ;
2+ import { createNewFile } from './commands/createFile' ;
3+ import { validateCurrentFile } from './commands/validate' ;
4+ import { ObjectIndex } from './services/ObjectIndex' ;
5+ import { ObjectDefinitionProvider } from './providers/ObjectDefinitionProvider' ;
6+ import { ObjectCompletionProvider } from './providers/ObjectCompletionProvider' ;
7+ import { LANGUAGES , SCHEMES } from './utils/constants' ;
8+
9+ let objectIndex : ObjectIndex ;
410
511/**
612 * Extension activation function
@@ -9,7 +15,10 @@ import * as fs from 'fs';
915export function activate ( context : vscode . ExtensionContext ) {
1016 console . log ( 'ObjectQL extension is now active!' ) ;
1117
12- // Register commands
18+ // Initialize Services
19+ objectIndex = new ObjectIndex ( ) ;
20+
21+ // Register Commands
1322 context . subscriptions . push (
1423 vscode . commands . registerCommand ( 'objectql.newObject' , ( ) => createNewFile ( context , 'object' ) ) ,
1524 vscode . commands . registerCommand ( 'objectql.newValidation' , ( ) => createNewFile ( context , 'validation' ) ) ,
@@ -18,6 +27,17 @@ export function activate(context: vscode.ExtensionContext) {
1827 vscode . commands . registerCommand ( 'objectql.validateSchema' , validateCurrentFile )
1928 ) ;
2029
30+ // Register Providers
31+ const selector = { language : LANGUAGES . YAML , scheme : SCHEMES . FILE } ;
32+
33+ context . subscriptions . push (
34+ vscode . languages . registerDefinitionProvider ( selector , new ObjectDefinitionProvider ( objectIndex ) ) ,
35+ vscode . languages . registerCompletionItemProvider ( selector , new ObjectCompletionProvider ( objectIndex ) , ' ' )
36+ ) ;
37+
38+ // Clean up
39+ context . subscriptions . push ( objectIndex ) ;
40+
2141 // Show welcome message on first activation
2242 const hasShownWelcome = context . globalState . get ( 'objectql.hasShownWelcome' , false ) ;
2343 if ( ! hasShownWelcome ) {
@@ -29,146 +49,10 @@ export function activate(context: vscode.ExtensionContext) {
2949 * Extension deactivation function
3050 */
3151export function deactivate ( ) {
32- console . log ( 'ObjectQL extension is now deactivated' ) ;
33- }
34-
35- /**
36- * Create a new ObjectQL file from template
37- */
38- async function createNewFile ( context : vscode . ExtensionContext , fileType : 'object' | 'validation' | 'permission' | 'app' ) {
39- const workspaceFolder = vscode . workspace . workspaceFolders ?. [ 0 ] ;
40-
41- if ( ! workspaceFolder ) {
42- vscode . window . showErrorMessage ( 'Please open a workspace folder first' ) ;
43- return ;
44- }
45-
46- // Prompt for filename
47- const fileName = await vscode . window . showInputBox ( {
48- prompt : `Enter ${ fileType } name (without extension)` ,
49- placeHolder : `my_${ fileType } ` ,
50- validateInput : ( value : string ) => {
51- if ( ! value ) {
52- return 'Name cannot be empty' ;
53- }
54- if ( ! / ^ [ a - z _ ] [ a - z 0 - 9 _ ] * $ / . test ( value ) ) {
55- return 'Name must start with lowercase letter or underscore and contain only lowercase letters, numbers, and underscores' ;
56- }
57- return null ;
58- }
59- } ) ;
60-
61- if ( ! fileName ) {
62- return ;
63- }
64-
65- // Determine file path
66- // Guess the location based on standard folder structure
67- let folder = 'src' ;
68- if ( fileType === 'object' ) {
69- folder = 'src/objects' ;
70- } else if ( fileType === 'app' ) {
71- folder = 'src' ;
72- }
73-
74- const fullFileName = `${ fileName } .${ fileType } .yml` ;
75- const defaultPath = path . join ( workspaceFolder . uri . fsPath , folder , fullFileName ) ;
76-
77- // Get template content
78- const template = getTemplate ( context , fileType , fileName ) ;
79-
80- try {
81- // Ensure directory exists
82- const dir = path . dirname ( defaultPath ) ;
83- if ( ! fs . existsSync ( dir ) ) {
84- fs . mkdirSync ( dir , { recursive : true } ) ;
85- }
86-
87- // Check if file already exists
88- if ( fs . existsSync ( defaultPath ) ) {
89- const overwrite = await vscode . window . showWarningMessage (
90- `File ${ fullFileName } already exists. Overwrite?` ,
91- 'Yes' , 'No'
92- ) ;
93- if ( overwrite !== 'Yes' ) {
94- return ;
95- }
96- }
97-
98- // Write file
99- fs . writeFileSync ( defaultPath , template , 'utf8' ) ;
100-
101- // Open file
102- const document = await vscode . workspace . openTextDocument ( defaultPath ) ;
103- await vscode . window . showTextDocument ( document ) ;
104-
105- vscode . window . showInformationMessage ( `Created ${ fullFileName } ` ) ;
106- } catch ( error ) {
107- vscode . window . showErrorMessage ( `Failed to create file: ${ error } ` ) ;
108- }
109- }
110-
111- /**
112- * Get template content for file type from template files
113- */
114- function getTemplate ( context : vscode . ExtensionContext , fileType : string , name : string ) : string {
115- try {
116- // Check if we are running from 'out' or 'src'
117- // Usually extension path is the root of the package.
118-
119- let templatePath = path . join ( context . extensionPath , 'src' , 'templates' , `${ fileType } .template.yml` ) ;
120-
121- // Fallback if not found (maybe flattened or in out)
122- if ( ! fs . existsSync ( templatePath ) ) {
123- templatePath = path . join ( context . extensionPath , 'out' , 'templates' , `${ fileType } .template.yml` ) ;
124- }
125-
126- if ( fs . existsSync ( templatePath ) ) {
127- let content = fs . readFileSync ( templatePath , 'utf8' ) ;
128- content = content . replace ( / { { name} } / g, name ) ;
129- content = content . replace ( / { { label} } / g, capitalizeWords ( name ) ) ;
130- return content ;
131- }
132-
133- // Fallback to hardcoded string if file read fails (Safety net)
134- console . warn ( `Template file not found at ${ templatePath } , utilizing fallback.` ) ;
135- return getFallbackTemplate ( fileType , name ) ;
136-
137- } catch ( e ) {
138- console . error ( 'Error reading template:' , e ) ;
139- return getFallbackTemplate ( fileType , name ) ;
140- }
141- }
142-
143- function getFallbackTemplate ( fileType : string , name : string ) : string {
144- // Minimal fallback
145- return `# ${ capitalizeWords ( name ) } ${ fileType } \nname: ${ name } \n` ;
146- }
147-
148- /**
149- * Validate current file by saving (triggers schema validation)
150- */
151- async function validateCurrentFile ( ) {
152- const editor = vscode . window . activeTextEditor ;
153- if ( ! editor ) {
154- vscode . window . showWarningMessage ( 'No active editor' ) ;
155- return ;
156- }
157-
158- const document = editor . document ;
159- const fileName = path . basename ( document . fileName ) ;
160-
161- // Check if it's an ObjectQL file
162- const objectqlFilePattern = / \. ( o b j e c t | v a l i d a t i o n | p e r m i s s i o n | a p p ) \. ( y m l | y a m l ) $ / ;
163- if ( ! objectqlFilePattern . test ( fileName ) ) {
164- vscode . window . showWarningMessage ( 'This is not an ObjectQL metadata file' ) ;
165- return ;
52+ if ( objectIndex ) {
53+ objectIndex . dispose ( ) ;
16654 }
167-
168- // Trigger validation by saving
169- await document . save ( ) ;
170-
171- vscode . window . showInformationMessage ( 'Validation complete. Check Problems panel for issues.' ) ;
55+ console . log ( 'ObjectQL extension is now deactivated' ) ;
17256}
17357
17458/**
@@ -189,13 +73,3 @@ function showWelcomeMessage(context: vscode.ExtensionContext) {
18973
19074 context . globalState . update ( 'objectql.hasShownWelcome' , true ) ;
19175}
192-
193- /**
194- * Capitalize words for display names
195- */
196- function capitalizeWords ( str : string ) : string {
197- return str
198- . split ( '_' )
199- . map ( word => word . charAt ( 0 ) . toUpperCase ( ) + word . slice ( 1 ) . toLowerCase ( ) )
200- . join ( ' ' ) ;
201- }
0 commit comments