diff --git a/src/type-gen.test.ts b/src/type-gen.test.ts index e36c6e3..48c6373 100644 --- a/src/type-gen.test.ts +++ b/src/type-gen.test.ts @@ -26,6 +26,15 @@ describe('Type generation for string literals and unions', () => { expect(schema.schema.type).toBe('stringLiteral'); expect(schema.parse('"hello-world"')).toBe('hello-world'); }); + + it('should parse string literal without quotes', () => { + const schema = defineSchema('"on"'); + expect(schema.schema.type).toBe('stringLiteral'); + // 不带引号的值应该像普通字符串一样解析 + expect(schema.parse('on')).toBe('on'); + expect(schema.validator('on')).toBe(true); + expect(schema.validator('off')).toBe(false); + }); }); describe('Union schema', () => { @@ -42,10 +51,12 @@ describe('Type generation for string literals and unions', () => { it('should generate correct type for union of string literals', () => { const schema = defineSchema('"on" | "off"'); expect(schema.schema.type).toBe('union'); - - // Both values should be valid + + // 带引号和不带引号的值都应该有效 expect(schema.parse('"on"')).toBe('on'); expect(schema.parse('"off"')).toBe('off'); + expect(schema.parse('on')).toBe('on'); + expect(schema.parse('off')).toBe('off'); expect(schema.validator('on')).toBe(true); expect(schema.validator('off')).toBe(true); expect(schema.validator('maybe')).toBe(false); @@ -70,19 +81,29 @@ describe('Type generation for string literals and unions', () => { it('should handle tuple with union field', () => { const schema = defineSchema('[name: string; status: "active" | "inactive"]'); expect(schema.schema.type).toBe('tuple'); - - const value = schema.parse('[john; "active"]'); - expect(value).toEqual(['john', 'active']); + + // 带引号和不带引号的值都应该有效 + const value1 = schema.parse('[john; "active"]'); + expect(value1).toEqual(['john', 'active']); expect(schema.validator(['john', 'active'])).toBe(true); + + const value2 = schema.parse('[john; active]'); + expect(value2).toEqual(['john', 'active']); + expect(schema.validator(['john', 'unknown'])).toBe(false); }); it('should handle array of unions', () => { const schema = defineSchema('("pending" | "approved" | "rejected")[]'); expect(schema.schema.type).toBe('array'); + + // 带引号和不带引号的值都应该有效 + const value1 = schema.parse('["pending"; "approved"]'); + expect(value1).toEqual(['pending', 'approved']); + + const value2 = schema.parse('[pending; approved]'); + expect(value2).toEqual(['pending', 'approved']); - const value = schema.parse('["pending"; "approved"]'); - expect(value).toEqual(['pending', 'approved']); expect(schema.validator(['pending', 'approved'])).toBe(true); expect(schema.validator(['pending', 'unknown'])).toBe(false); }); @@ -90,9 +111,14 @@ describe('Type generation for string literals and unions', () => { it('should handle array of string literals', () => { const schema = defineSchema('"item"[]'); expect(schema.schema.type).toBe('array'); + + // 带引号和不带引号的值都应该有效 + const value1 = schema.parse('["item"; "item"; "item"]'); + expect(value1).toEqual(['item', 'item', 'item']); + + const value2 = schema.parse('[item; item; item]'); + expect(value2).toEqual(['item', 'item', 'item']); - const value = schema.parse('["item"; "item"; "item"]'); - expect(value).toEqual(['item', 'item', 'item']); expect(schema.validator(['item', 'item'])).toBe(true); expect(schema.validator(['item', 'other'])).toBe(false); }); diff --git a/src/validator.ts b/src/validator.ts index 3d6023e..0679bd1 100644 --- a/src/validator.ts +++ b/src/validator.ts @@ -126,40 +126,62 @@ class ValueParser { private parseStringLiteralValue(schema: StringLiteralSchema): string { const quote = this.peek(); - if (quote !== '"' && quote !== "'") { - throw new ParseError(`Expected string literal with quotes for value "${schema.value}"`, this.pos); - } - this.consume(); // Consume opening quote - let value = ''; - while (this.pos < this.input.length) { - const char = this.peek(); - - if (char === '\\') { - this.consume(); - const nextChar = this.consume(); - if (nextChar === '"' || nextChar === "'" || nextChar === '\\' || nextChar === ';') { - value += nextChar; + // 支持带引号或不带引号的字符串值 + if (quote === '"' || quote === "'") { + this.consume(); // Consume opening quote + + let value = ''; + while (this.pos < this.input.length) { + const char = this.peek(); + + if (char === '\\') { + this.consume(); + const nextChar = this.consume(); + if (nextChar === '"' || nextChar === "'" || nextChar === '\\' || nextChar === ';') { + value += nextChar; + } else { + value += '\\' + nextChar; + } + } else if (char === quote) { + this.consume(); // Consume closing quote + + if (value !== schema.value) { + throw new ParseError( + `Invalid value '"${value}"'. Expected '"${schema.value}"'`, + this.pos + ); + } + + return value; } else { - value += '\\' + nextChar; + value += this.consume(); } - } else if (char === quote) { - this.consume(); // Consume closing quote - - if (value !== schema.value) { - throw new ParseError( - `Invalid value '"${value}"'. Expected '"${schema.value}"'`, - this.pos - ); + } + + throw new ParseError('Unterminated string literal', this.pos); + } else { + // 不带引号的字符串,像普通字符串一样解析 + let value = ''; + while (this.pos < this.input.length) { + const char = this.peek(); + if (char === ';' || char === ']' || char === ')') { + break; } - - return value; - } else { value += this.consume(); } + + value = value.trim(); + + if (value !== schema.value) { + throw new ParseError( + `Invalid value '${value}'. Expected '${schema.value}'`, + this.pos - value.length + ); + } + + return value; } - - throw new ParseError('Unterminated string literal', this.pos); } private parseUnionValue(schema: UnionSchema): unknown {