feat: precise line/col for tokenization Error, #613

This commit is contained in:
Harttle
2023-06-04 02:06:42 +08:00
committed by Jun Yang
parent 0480d3317d
commit e347e603d7
42 changed files with 280 additions and 200 deletions
+1 -1
View File
@@ -254,7 +254,7 @@ describe('Issues', function () {
})
it('#519 should throw parse error for invalid assign expression', () => {
const engine = new Liquid()
expect(() => engine.parse('{% assign headshot = https://testurl.com/not_enclosed_in_quotes.jpg %}')).toThrow(/unexpected token at ":/)
expect(() => engine.parse('{% assign headshot = https://testurl.com/not_enclosed_in_quotes.jpg %}')).toThrow(/expected "|" before filter, line:1, col:27/)
})
it('#527 export Liquid Expression', () => {
const tokenizer = new Tokenizer('a > b')
+9 -1
View File
@@ -22,7 +22,7 @@ describe('filters/array', function () {
it('should throw when comma missing', async () => {
const src = '{% assign beatles = "John, Paul, George, Ringo" | split: ", " %}' +
'{{ beatles | join " and " }}'
return expect(render(src)).rejects.toThrow('unexpected token at "\\" and \\"", line:1, col:65')
return expect(render(src)).rejects.toThrow('expected ":" after filter name, line:1, col:83')
})
})
describe('last', () => {
@@ -138,6 +138,14 @@ describe('filters/array', function () {
'{{ "hello,world" | split: "," | sample: 1 | size }}',
'1'
))
it('should sample nil value', () => test(
'{{ nil | sample: 2 }}',
''
))
it('should sample string characters', () => test(
'{{ "aaa" | sample: 2 }}',
'aa'
))
})
describe('size', function () {
it('should return string length', () => test(
+4 -4
View File
@@ -1,12 +1,12 @@
import { Liquid } from '../../../src/liquid'
import { ParseError } from '../../../src'
import { TokenizationError } from '../../../src'
describe('tags/assign', function () {
const liquid = new Liquid()
it('should throw when variable name illegal', function () {
const src = '{% assign / %}'
const ctx = {}
return expect(liquid.parseAndRender(src, ctx)).rejects.toThrow(/illegal/)
return expect(liquid.parseAndRender(src, ctx)).rejects.toThrow(/expected variable name/)
})
it('should support assign to a string', async function () {
const src = '{% assign foo="bar" %}{{foo}}'
@@ -15,8 +15,8 @@ describe('tags/assign', function () {
})
it('should throw when variable value illegal', function () {
const src = '{% assign foo = “bar” %}'
expect(() => liquid.parse(src)).toThrow(/unexpected token at "“bar”"/)
expect(() => liquid.parse(src)).toThrow(ParseError)
expect(() => liquid.parse(src)).toThrow(/invalid value expression: "“bar”"/)
expect(() => liquid.parse(src)).toThrow(TokenizationError)
})
it('should support assign to a number', async function () {
const src = '{% assign foo=10086 %}{{foo}}'
+1 -1
View File
@@ -26,7 +26,7 @@ describe('tags/capture', function () {
it('should throw on invalid identifier', function () {
const src = '{% capture = %}{%endcapture%}'
return expect(liquid.parseAndRender(src))
.rejects.toThrow(/= not valid identifier/)
.rejects.toThrow('invalid capture name, line:1, col:12')
})
it('should throw when capture not closed', function () {
+1 -1
View File
@@ -11,7 +11,7 @@ describe('tags/cycle', function () {
it('should throw when cycle candidates empty', function () {
return expect(liquid.parseAndRender('{%cycle%}'))
.rejects.toThrow(/empty candidates/)
.rejects.toThrow('empty candidates: "{%cycle%}", line:1, col:8')
})
it('should support cycle in for block', async function () {
+3 -3
View File
@@ -49,8 +49,8 @@ describe('tags/include', function () {
'/parent.html': '{%include , %}'
})
return liquid.renderFile('/parent.html').catch(function (e) {
expect(e.name).toBe('ParseError')
expect(e.message).toMatch(/illegal argument ","/)
expect(e.name).toBe('TokenizationError')
expect(e.message).toMatch('illegal file path, file:/parent.html, line:1, col:11')
})
})
@@ -60,7 +60,7 @@ describe('tags/include', function () {
})
return liquid.renderFile('/parent.html').catch(function (e) {
expect(e.name).toBe('RenderError')
expect(e.message).toMatch(/illegal filename "undefined"/)
expect(e.message).toMatch(/illegal file path "undefined"/)
})
})
+3 -3
View File
@@ -23,8 +23,8 @@ describe('tags/layout', function () {
'/parent.html': '{%layout%}'
})
return liquid.renderFile('/parent.html').catch(function (e) {
expect(e.name).toBe('ParseError')
expect(e.message).toMatch(/illegal argument ""/)
expect(e.name).toBe('TokenizationError')
expect(e.message).toMatch(/illegal file path/)
})
})
it('should throw when filename resolved to falsy', function () {
@@ -33,7 +33,7 @@ describe('tags/layout', function () {
})
return liquid.renderFile('/parent.html').catch(function (e) {
expect(e.name).toBe('RenderError')
expect(e.message).toContain('illegal filename "undefined"')
expect(e.message).toContain('illegal file path')
})
})
it('should handle layout none', async function () {
+3 -3
View File
@@ -42,8 +42,8 @@ describe('tags/render', function () {
'/parent.html': '{%render%}'
})
return liquid.renderFile('/parent.html').catch(function (e) {
expect(e.name).toBe('ParseError')
expect(e.message).toMatch(/illegal argument ""/)
expect(e.name).toBe('TokenizationError')
expect(e.message).toMatch(/illegal file path/)
})
})
@@ -53,7 +53,7 @@ describe('tags/render', function () {
})
return liquid.renderFile('/parent.html').catch(function (e) {
expect(e.name).toBe('RenderError')
expect(e.message).toMatch(/illegal filename "undefined"/)
expect(e.message).toMatch(/illegal file path/)
})
})
+17 -4
View File
@@ -25,11 +25,12 @@ describe('error', function () {
' 1| 1st',
' 2| 2nd',
'>> 3| X{% . a %} Y',
' ^',
' 4| 4th',
'TokenizationError'
]
await expect(engine.parseAndRender(html.join('\n'))).rejects.toMatchObject({
message: 'illegal tag syntax, line:3, col:2',
message: 'illegal tag syntax, tag name expected, line:3, col:5',
stack: expect.stringContaining(message.join('\n')),
name: 'TokenizationError'
})
@@ -61,7 +62,7 @@ describe('error', function () {
it('should throw error with [line, col] if tag unmatched', async function () {
await expect(engine.parseAndRender('1\n2\nfoo{% assign a = 4 }\n4')).rejects.toMatchObject({
name: 'TokenizationError',
message: 'tag "{% assign a =..." not closed, line:3, col:4'
message: 'tag "{% assign a = 4 }\\n4" not closed, line:3, col:4'
})
})
})
@@ -122,6 +123,7 @@ describe('error', function () {
' 2| 2nd',
' 3| 3rd',
'>> 4| X{%throwingTag%} Y',
' ^',
' 5| 5th',
' 6| 6th',
' 7| 7th',
@@ -150,6 +152,7 @@ describe('error', function () {
' 2| 2nd',
' 3| 3rd',
'>> 4| X{%throwingTag%} Y',
' ^',
' 5| 5th',
' 6| {%block%}{%endblock%}',
' 7| 7th',
@@ -171,6 +174,7 @@ describe('error', function () {
' 2| 2nd',
' 3| 3rd',
'>> 4| X{%throwingTag%} Y',
' ^',
' 5| 5th',
' 6| 6th',
' 7| 7th',
@@ -207,9 +211,15 @@ describe('error', function () {
})
})
it('should throw ParseError when tag not closed', async function () {
await expect(engine.parseAndRender('{% if %}')).rejects.toMatchObject({
await expect(engine.parseAndRender('{% if true %}')).rejects.toMatchObject({
name: 'ParseError',
message: expect.stringContaining('tag {% if %} not closed')
message: expect.stringContaining('tag {% if true %} not closed')
})
})
it('should throw ParseError when tag value not specified', async function () {
await expect(engine.parseAndRender('{% if %}{% endif %}')).rejects.toMatchObject({
name: 'TokenizationError',
message: 'invalid value expression: "", line:1, col:1'
})
})
it('should throw ParseError when tag parse throws', async function () {
@@ -238,6 +248,7 @@ describe('error', function () {
' 2| 2nd',
' 3| 3rd',
'>> 4| X{% a %} {% enda %} Y',
' ^',
' 5| 5th',
' 6| 6th',
' 7| 7th',
@@ -255,6 +266,7 @@ describe('error', function () {
const message = [
' 1| 1st',
'>> 2| X{% a %} {% enda %} Y',
' ^',
' 3| 3rd',
' 4| 4th',
'ParseError: tag "a" not found'
@@ -300,6 +312,7 @@ describe('error', function () {
' 2| 2nd',
' 3| 3rd',
'>> 4| X{%throwingTag%} Y',
' ^',
' 5| 5th',
' 6| 6th',
' 7| 7th',