Skip to content

Commit c917502

Browse files
committed
[Feature] Verify the demo IDs when in source mode #265 #release
1 parent 81c46a0 commit c917502

File tree

2 files changed

+100
-17
lines changed

2 files changed

+100
-17
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
- [#262](https://github.com/estruyf/vscode-demo-time/issues/262): Added a recent files dropdown to
66
the path input component in the config editor
7+
- [#265](https://github.com/estruyf/vscode-demo-time/issues/265): Verify the demo IDs when in source
8+
mode so that there are no duplicate IDs across multiple files in the workspace
79
- [#266](https://github.com/estruyf/vscode-demo-time/issues/266): Added a `generate demo id` button
810
to (re)generate a unique id for the demo
911
- [#267](https://github.com/estruyf/vscode-demo-time/issues/267): Clean up unrelated properties

apps/vscode-extension/src/services/DemoValidationService.ts

Lines changed: 98 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -283,20 +283,28 @@ export class DemoValidationService {
283283
continue;
284284
}
285285

286-
// Detect start of a new demo
286+
// Detect start of a new demo object
287287
let isNewDemo = false;
288288
if (isYaml) {
289-
// YAML: look for "- id:" or "- title:" or just "- " at start of line (accounting for indentation)
290-
if (
291-
trimmedLine.startsWith('- ') &&
292-
(trimmedLine.includes('id:') || trimmedLine.includes('title:') || trimmedLine === '-')
293-
) {
294-
isNewDemo = true;
289+
// YAML: look for lines that start with "- " but be more specific
290+
// We need to ensure we're detecting actual demo items, not sub-items like steps
291+
if (trimmedLine.startsWith('- ')) {
292+
// Check if this is likely a demo object by looking for demo properties
293+
const isLikelyDemo = this.isLikelyYamlDemoObject(lines, lineNum);
294+
if (isLikelyDemo) {
295+
isNewDemo = true;
296+
}
295297
}
296298
} else {
297-
// JSON: look for opening brace that starts a demo object
298-
if (trimmedLine === '{') {
299-
isNewDemo = true;
299+
// JSON: We need to be very specific about demo objects
300+
// A demo object should be a direct child of the demos array
301+
// Look for opening braces that are likely demo objects by checking the next few lines
302+
if (trimmedLine === '{' && line.indexOf('{') > 0) {
303+
// Check if this brace is followed by demo-like properties within a reasonable distance
304+
const isLikelyDemo = this.isLikelyDemoObject(lines, lineNum);
305+
if (isLikelyDemo) {
306+
isNewDemo = true;
307+
}
300308
}
301309
}
302310

@@ -314,6 +322,75 @@ export class DemoValidationService {
314322
return new Position(0, 0);
315323
}
316324

325+
/**
326+
* Check if an opening brace is likely the start of a demo object
327+
*/
328+
private static isLikelyDemoObject(lines: string[], braceLineNum: number): boolean {
329+
// Look for typical demo properties in the next few lines
330+
const searchLimit = Math.min(braceLineNum + 10, lines.length);
331+
332+
for (let i = braceLineNum + 1; i < searchLimit; i++) {
333+
const line = lines[i];
334+
const trimmedLine = line.trim();
335+
336+
// Stop if we hit a closing brace at the same level
337+
if (trimmedLine === '}' || trimmedLine === '},') {
338+
break;
339+
}
340+
341+
// Look for demo-specific properties
342+
if (
343+
trimmedLine.includes('"id"') ||
344+
trimmedLine.includes('"title"') ||
345+
trimmedLine.includes('"description"') ||
346+
trimmedLine.includes('"steps"')
347+
) {
348+
return true;
349+
}
350+
}
351+
352+
return false;
353+
}
354+
355+
/**
356+
* Check if a YAML "- " line is likely the start of a demo object
357+
*/
358+
private static isLikelyYamlDemoObject(lines: string[], dashLineNum: number): boolean {
359+
const startLine = lines[dashLineNum];
360+
const startIndentation = startLine.length - startLine.trimStart().length;
361+
const searchLimit = Math.min(dashLineNum + 15, lines.length);
362+
363+
// Look for demo-specific properties at the right indentation level
364+
for (let i = dashLineNum; i < searchLimit; i++) {
365+
const line = lines[i];
366+
const trimmedLine = line.trim();
367+
const currentIndentation = line.length - line.trimStart().length;
368+
369+
// Stop if we hit another "- " at the same indentation level (next demo)
370+
if (
371+
i > dashLineNum &&
372+
trimmedLine.startsWith('- ') &&
373+
currentIndentation <= startIndentation
374+
) {
375+
break;
376+
}
377+
378+
// Look for demo-specific properties
379+
if (
380+
trimmedLine.startsWith('id:') ||
381+
trimmedLine.startsWith('title:') ||
382+
trimmedLine.startsWith('description:') ||
383+
trimmedLine.startsWith('steps:') ||
384+
// Also check for inline format: "- id: value"
385+
(i === dashLineNum && (trimmedLine.includes('id:') || trimmedLine.includes('title:')))
386+
) {
387+
return true;
388+
}
389+
}
390+
391+
return false;
392+
}
393+
317394
/**
318395
* Find a specific property within a demo object
319396
*/
@@ -323,21 +400,26 @@ export class DemoValidationService {
323400
property: string,
324401
isYaml: boolean,
325402
): Position {
403+
const startIndentation = lines[startLine].length - lines[startLine].trimStart().length;
404+
326405
for (let lineNum = startLine; lineNum < lines.length; lineNum++) {
327406
const line = lines[lineNum];
328407
const trimmedLine = line.trim();
408+
const currentIndentation = line.length - line.trimStart().length;
329409

330410
// Stop searching if we hit the next demo or end of current demo
331411
if (lineNum > startLine) {
332412
if (isYaml) {
333-
if (
334-
trimmedLine.startsWith('- ') &&
335-
(trimmedLine.includes('id:') || trimmedLine.includes('title:'))
336-
) {
413+
// In YAML, if we encounter another item at the same level or less indented, we've left this demo
414+
if (trimmedLine.startsWith('- ') && currentIndentation <= startIndentation) {
337415
break; // Start of next demo
338416
}
339417
} else {
340-
if (trimmedLine === '}' || trimmedLine === '},') {
418+
// In JSON, look for closing brace at the same indentation level as the opening brace
419+
if (
420+
(trimmedLine === '}' || trimmedLine === '},') &&
421+
currentIndentation <= startIndentation
422+
) {
341423
break; // End of current demo
342424
}
343425
}
@@ -358,8 +440,7 @@ export class DemoValidationService {
358440
}
359441

360442
// If property not found, return the demo start position
361-
const indentation = lines[startLine].length - lines[startLine].trimStart().length;
362-
return new Position(startLine, indentation);
443+
return new Position(startLine, startIndentation);
363444
}
364445

365446
/**

0 commit comments

Comments
 (0)