Skip to content

Commit 0c7266d

Browse files
committed
Refactor template handling and add YAML templates
Moved ObjectQL YAML templates to separate files under src/templates and updated extension logic to load templates from these files. Removed hardcoded template strings and improved file creation logic. Also removed unused dependency on vscode-languageclient and cleaned up YAML language server configuration code.
1 parent be551a6 commit 0c7266d

File tree

6 files changed

+209
-217
lines changed

6 files changed

+209
-217
lines changed

packages/tools/vscode-objectql/package.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,6 @@
222222
"typescript": "^5.3.0",
223223
"@vscode/vsce": "^2.22.0"
224224
},
225-
"dependencies": {
226-
"vscode-languageclient": "^9.0.1"
227-
},
228225
"extensionDependencies": [
229226
"redhat.vscode-yaml"
230227
]

packages/tools/vscode-objectql/src/extension.ts

Lines changed: 40 additions & 214 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ export function activate(context: vscode.ExtensionContext) {
1818
vscode.commands.registerCommand('objectql.validateSchema', validateCurrentFile)
1919
);
2020

21-
// Configure YAML language server for ObjectQL files
22-
configureYamlLanguageServer();
23-
2421
// Show welcome message on first activation
2522
const hasShownWelcome = context.globalState.get('objectql.hasShownWelcome', false);
2623
if (!hasShownWelcome) {
@@ -66,11 +63,19 @@ async function createNewFile(context: vscode.ExtensionContext, fileType: 'object
6663
}
6764

6865
// 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+
6974
const fullFileName = `${fileName}.${fileType}.yml`;
70-
const defaultPath = path.join(workspaceFolder.uri.fsPath, 'src', 'objects', fullFileName);
75+
const defaultPath = path.join(workspaceFolder.uri.fsPath, folder, fullFileName);
7176

7277
// Get template content
73-
const template = getTemplate(fileType, fileName);
78+
const template = getTemplate(context, fileType, fileName);
7479

7580
try {
7681
// Ensure directory exists
@@ -104,198 +109,44 @@ async function createNewFile(context: vscode.ExtensionContext, fileType: 'object
104109
}
105110

106111
/**
107-
* Get template content for file type
112+
* Get template content for file type from template files
108113
*/
109-
function getTemplate(fileType: string, name: string): string {
110-
switch (fileType) {
111-
case 'object':
112-
return `# ObjectQL Object Definition
113-
# Documentation: https://github.com/objectstack-ai/objectql
114-
115-
name: ${name}
116-
label: ${capitalizeWords(name)}
117-
description: "${capitalizeWords(name)} object"
118-
119-
fields:
120-
name:
121-
type: text
122-
label: Name
123-
required: true
124-
searchable: true
125-
help_text: "The name of the ${name}"
126-
127-
description:
128-
type: textarea
129-
label: Description
130-
help_text: "Detailed description"
131-
132-
status:
133-
type: select
134-
label: Status
135-
options:
136-
- label: Active
137-
value: active
138-
- label: Inactive
139-
value: inactive
140-
defaultValue: active
141-
142-
created_by:
143-
type: lookup
144-
label: Created By
145-
reference_to: users
146-
readonly: true
147-
148-
created_at:
149-
type: datetime
150-
label: Created At
151-
readonly: true
152-
153-
# Indexes for performance
154-
indexes:
155-
name_idx:
156-
fields: [name]
157-
status_idx:
158-
fields: [status]
159-
160-
# Validation rules (optional)
161-
validation:
162-
rules:
163-
- name: name_required
164-
type: cross_field
165-
message: "Name is required"
166-
rule:
167-
field: name
168-
operator: "!="
169-
value: null
170-
`;
171-
172-
case 'validation':
173-
return `# ObjectQL Validation Rules
174-
# Documentation: https://github.com/objectstack-ai/objectql/docs/spec/validation.md
175-
176-
# Object-level validation rules
177-
rules:
178-
# Cross-field validation example
179-
- name: end_after_start
180-
type: cross_field
181-
message: "End date must be after start date"
182-
fields: [start_date, end_date]
183-
rule:
184-
field: end_date
185-
operator: ">"
186-
compare_to: start_date
187-
trigger: [create, update]
188-
severity: error
189-
190-
# Business rule example
191-
- name: status_approval_required
192-
type: business_rule
193-
message: "Approval required before activation"
194-
constraint:
195-
expression: "status === 'active' && approved === true"
196-
trigger: [create, update]
197-
severity: error
198-
199-
# Uniqueness validation
200-
- name: unique_email
201-
type: unique
202-
message: "Email must be unique"
203-
field: email
204-
case_sensitive: false
205-
trigger: [create, update]
206-
`;
207-
208-
case 'permission':
209-
return `# ObjectQL Permission Rules
210-
# Documentation: https://github.com/objectstack-ai/objectql/docs/spec/permission.md
211-
212-
# Role-based permissions
213-
roles:
214-
admin:
215-
permissions:
216-
create: true
217-
read: true
218-
update: true
219-
delete: true
220-
221-
user:
222-
permissions:
223-
create: true
224-
read: true
225-
update:
226-
condition: "owner === $userId"
227-
delete: false
228-
229-
guest:
230-
permissions:
231-
create: false
232-
read: true
233-
update: false
234-
delete: false
235-
236-
# Field-level permissions
237-
field_permissions:
238-
sensitive_data:
239-
roles: [admin]
240-
mask: true
241-
242-
internal_notes:
243-
roles: [admin, user]
244-
245-
# Record-level security (Row-Level Security)
246-
record_permissions:
247-
owner_only:
248-
condition: "owner === $userId"
249-
roles: [user]
250-
`;
251-
252-
case 'app':
253-
return `# ObjectQL Application Configuration
254-
# Documentation: https://github.com/objectstack-ai/objectql/docs/spec/app.md
255-
256-
name: ${name}
257-
label: ${capitalizeWords(name)}
258-
description: "${capitalizeWords(name)} application"
259-
version: "1.0.0"
260-
261-
# Application metadata
262-
metadata:
263-
author: "Your Name"
264-
license: "MIT"
265-
266-
# Navigation and menu structure
267-
navigation:
268-
- label: Home
269-
path: /
270-
icon: home
271-
272-
- label: ${capitalizeWords(name)}
273-
icon: database
274-
children:
275-
- label: List
276-
path: /${name}
277-
object: ${name}
278-
- label: Create New
279-
path: /${name}/new
280-
object: ${name}
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+
}
281125

282-
# Objects included in this app
283-
objects:
284-
- ${name}
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+
}
285132

286-
# Themes and branding
287-
theme:
288-
primary_color: "#0066cc"
289-
secondary_color: "#6c757d"
290-
`;
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);
291136

292-
default:
293-
return '';
137+
} catch (e) {
138+
console.error('Error reading template:', e);
139+
return getFallbackTemplate(fileType, name);
294140
}
295141
}
296142

143+
function getFallbackTemplate(fileType: string, name: string): string {
144+
// Minimal fallback
145+
return `# ${capitalizeWords(name)} ${fileType}\nname: ${name}\n`;
146+
}
147+
297148
/**
298-
* Validate current file against schema
149+
* Validate current file by saving (triggers schema validation)
299150
*/
300151
async function validateCurrentFile() {
301152
const editor = vscode.window.activeTextEditor;
@@ -320,31 +171,6 @@ async function validateCurrentFile() {
320171
vscode.window.showInformationMessage('Validation complete. Check Problems panel for issues.');
321172
}
322173

323-
/**
324-
* Configure YAML language server settings for ObjectQL
325-
*/
326-
function configureYamlLanguageServer() {
327-
const config = vscode.workspace.getConfiguration('yaml');
328-
const schemas = config.get('schemas', {}) as Record<string, string | string[]>;
329-
330-
// Check if ObjectQL schemas are already configured
331-
const hasObjectSchema = Object.values(schemas).some(val =>
332-
(Array.isArray(val) && val.some(v => v.includes('*.object.yml'))) ||
333-
(typeof val === 'string' && val.includes('*.object.yml'))
334-
);
335-
336-
if (!hasObjectSchema) {
337-
vscode.window.showInformationMessage(
338-
'ObjectQL extension works best with YAML language support. Please install "Red Hat YAML" extension if not already installed.',
339-
'Install'
340-
).then((selection: string | undefined) => {
341-
if (selection === 'Install') {
342-
vscode.commands.executeCommand('workbench.extensions.search', 'redhat.vscode-yaml');
343-
}
344-
});
345-
}
346-
}
347-
348174
/**
349175
* Show welcome message
350176
*/
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# ObjectQL Application Configuration
2+
# Documentation: https://www.objectql.org/docs/spec/app
3+
4+
name: {{name}}
5+
label: {{label}}
6+
description: "{{label}} application"
7+
version: "1.0.0"
8+
9+
# Application metadata
10+
metadata:
11+
author: "Your Name"
12+
license: "MIT"
13+
14+
# Navigation and menu structure
15+
navigation:
16+
- label: Home
17+
path: /
18+
icon: home
19+
20+
- label: {{label}}
21+
icon: database
22+
children:
23+
- label: List
24+
path: /{{name}}
25+
object: {{name}}
26+
- label: Create New
27+
path: /{{name}}/new
28+
object: {{name}}
29+
30+
# Objects included in this app
31+
objects:
32+
- {{name}}
33+
34+
# Themes and branding
35+
theme:
36+
primary_color: "#0066cc"
37+
secondary_color: "#6c757d"
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# ObjectQL Object Definition
2+
# Documentation: https://www.objectql.org/docs/spec/object
3+
4+
name: {{name}}
5+
label: {{label}}
6+
description: "{{label}} object"
7+
8+
fields:
9+
name:
10+
type: text
11+
label: Name
12+
required: true
13+
searchable: true
14+
help_text: "The name of the {{name}}"
15+
16+
description:
17+
type: textarea
18+
label: Description
19+
help_text: "Detailed description"
20+
21+
status:
22+
type: select
23+
label: Status
24+
options:
25+
- label: Active
26+
value: active
27+
- label: Inactive
28+
value: inactive
29+
defaultValue: active
30+
31+
created_by:
32+
type: lookup
33+
label: Created By
34+
reference_to: users
35+
readonly: true
36+
37+
created_at:
38+
type: datetime
39+
label: Created At
40+
readonly: true
41+
42+
# Indexes for performance
43+
indexes:
44+
name_idx:
45+
fields: [name]
46+
status_idx:
47+
fields: [status]
48+
49+
# Validation rules (optional)
50+
validation:
51+
rules:
52+
- name: name_required
53+
type: cross_field
54+
message: "Name is required"
55+
rule:
56+
field: name
57+
operator: "!="
58+
value: null

0 commit comments

Comments
 (0)