205 lines
5.7 KiB
TypeScript
205 lines
5.7 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
|
|
/**
|
|
* Helper function that mimics the validation logic in ConfigTemplate.tsx
|
|
* This is the improved version with comment support
|
|
*/
|
|
function validateJsonWithComments(value: string): { valid: boolean; error?: string } {
|
|
try {
|
|
if (!value.trim()) {
|
|
return { valid: true };
|
|
}
|
|
|
|
// Step 1: Remove /* */ multi-line comments
|
|
let sanitized = value.replace(/\/\*[\s\S]*?\*\//g, '');
|
|
|
|
// Step 2: Process line by line to handle // comments outside quotes
|
|
const lines = sanitized.split('\n');
|
|
const processedLines = lines.map(line => {
|
|
let result = '';
|
|
let inQuote = false;
|
|
let quoteChar = '';
|
|
|
|
for (let i = 0; i < line.length; i++) {
|
|
const char = line[i];
|
|
const prevChar = i > 0 ? line[i - 1] : '';
|
|
|
|
// Check for quote start/end (not escaped)
|
|
if ((char === '"' || char === "'") && prevChar !== '\\') {
|
|
if (!inQuote) {
|
|
inQuote = true;
|
|
quoteChar = char;
|
|
} else if (char === quoteChar) {
|
|
inQuote = false;
|
|
quoteChar = '';
|
|
}
|
|
result += char;
|
|
}
|
|
// Check for // comment start (only outside quotes)
|
|
else if (!inQuote && char === '/' && line[i + 1] === '/') {
|
|
break; // Rest of line is comment
|
|
}
|
|
else {
|
|
result += char;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
});
|
|
|
|
sanitized = processedLines.join('\n');
|
|
|
|
// Step 3: Replace @placeholders@ with dummy values
|
|
sanitized = sanitized.replace(/@[^@]+@/g, '1');
|
|
|
|
JSON.parse(sanitized);
|
|
return { valid: true };
|
|
} catch (e) {
|
|
return { valid: false, error: (e as Error).message };
|
|
}
|
|
}
|
|
|
|
describe('JSON Validation - Comment Support', () => {
|
|
it('should remove single-line // comments outside quotes', () => {
|
|
const json = `{
|
|
"key": "value" // this is a comment
|
|
}`;
|
|
const result = validateJsonWithComments(json);
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
it('should preserve // inside quoted strings', () => {
|
|
const json = `{
|
|
"url": "http://example.com/path",
|
|
"description": "This // that // other"
|
|
}`;
|
|
const result = validateJsonWithComments(json);
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
it('should preserve URLs with // in values', () => {
|
|
const json = `{
|
|
"apiUrl": "http://localhost:8080/api",
|
|
"cdn": "https://cdn.example.com/assets"
|
|
}`;
|
|
const result = validateJsonWithComments(json);
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
it('should remove multi-line /* */ comments', () => {
|
|
const json = `{
|
|
/* This is a
|
|
multi-line comment */
|
|
"key": "value"
|
|
}`;
|
|
const result = validateJsonWithComments(json);
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
it('should handle mixed comments and placeholders', () => {
|
|
const json = `{
|
|
// Host configuration
|
|
"host": "@host@",
|
|
"port": @port@, // unquoted placeholder
|
|
/* API settings */
|
|
"apiUrl": "http://@host@:@port@/api" // URL with placeholders
|
|
}`;
|
|
const result = validateJsonWithComments(json);
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
it('should handle comment-only lines', () => {
|
|
const json = `{
|
|
// Just a comment
|
|
"key": "value"
|
|
// Another comment
|
|
}`;
|
|
const result = validateJsonWithComments(json);
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
it('should preserve // in string values with special characters', () => {
|
|
const json = `{
|
|
"regex": "pattern // with slashes",
|
|
"path": "C://Program Files//App",
|
|
"comment": "text // more text // even more"
|
|
}`;
|
|
const result = validateJsonWithComments(json);
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
it('should handle escaped quotes correctly', () => {
|
|
const json = `{
|
|
"message": "He said \\"hello // world\\""
|
|
}`;
|
|
const result = validateJsonWithComments(json);
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
it('should reject invalid JSON with comments', () => {
|
|
const json = `{
|
|
"key": "value" // missing comma
|
|
"another": "key"
|
|
}`;
|
|
const result = validateJsonWithComments(json);
|
|
expect(result.valid).toBe(false);
|
|
expect(result.error).toContain('Expected');
|
|
});
|
|
|
|
it('should handle empty template', () => {
|
|
const result = validateJsonWithComments('');
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
it('should handle whitespace only', () => {
|
|
const result = validateJsonWithComments(' \n\t ');
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('JSON Validation - Placeholder Support', () => {
|
|
it('should validate quoted placeholders', () => {
|
|
const json = `{
|
|
"Host": "@host@",
|
|
"Port": "@port@"
|
|
}`;
|
|
const result = validateJsonWithComments(json);
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
it('should validate unquoted placeholders', () => {
|
|
const json = `{
|
|
"Host": "@host@",
|
|
"Port": @port@
|
|
}`;
|
|
const result = validateJsonWithComments(json);
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
it('should validate placeholders in URLs', () => {
|
|
const json = `{
|
|
"ApiUrl": "http://@host@:@port@/api/v1"
|
|
}`;
|
|
const result = validateJsonWithComments(json);
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
|
|
it('should validate complex template with comments and placeholders', () => {
|
|
const json = `{
|
|
// Database config
|
|
"db": {
|
|
"host": "@db_host@",
|
|
"port": @db_port@,
|
|
"url": "jdbc:mysql://@db_host@:@db_port@/mydb" // connection string
|
|
},
|
|
/* API settings */
|
|
"api": {
|
|
"baseUrl": "https://@api_host@/v1",
|
|
"timeout": @timeout@
|
|
}
|
|
}`;
|
|
const result = validateJsonWithComments(json);
|
|
expect(result.valid).toBe(true);
|
|
});
|
|
});
|