fix(compiler-sfc): fix whitespace preservation when block contains single self-closing tag
This commit is contained in:
		
							parent
							
								
									47f488350c
								
							
						
					
					
						commit
						ec6abe8d5e
					
				@ -96,8 +96,8 @@ export interface ParserContext {
 | 
				
			|||||||
  offset: number
 | 
					  offset: number
 | 
				
			||||||
  line: number
 | 
					  line: number
 | 
				
			||||||
  column: number
 | 
					  column: number
 | 
				
			||||||
  inPre: boolean // HTML <pre> tag, preserve whitespaces
 | 
					  inPre: number // HTML <pre> tag, preserve whitespaces
 | 
				
			||||||
  inVPre: boolean // v-pre, do not process directives and interpolations
 | 
					  inVPre: number // v-pre, do not process directives and interpolations
 | 
				
			||||||
  onWarn: NonNullable<ErrorHandlingOptions['onWarn']>
 | 
					  onWarn: NonNullable<ErrorHandlingOptions['onWarn']>
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -134,8 +134,8 @@ function createParserContext(
 | 
				
			|||||||
    offset: 0,
 | 
					    offset: 0,
 | 
				
			||||||
    originalSource: content,
 | 
					    originalSource: content,
 | 
				
			||||||
    source: content,
 | 
					    source: content,
 | 
				
			||||||
    inPre: false,
 | 
					    inPre: 0,
 | 
				
			||||||
    inVPre: false,
 | 
					    inVPre: 0,
 | 
				
			||||||
    onWarn: options.onWarn
 | 
					    onWarn: options.onWarn
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -254,7 +254,7 @@ function parseChildren(
 | 
				
			|||||||
  // Whitespace handling strategy like v2
 | 
					  // Whitespace handling strategy like v2
 | 
				
			||||||
  let removedWhitespace = false
 | 
					  let removedWhitespace = false
 | 
				
			||||||
  if (mode !== TextModes.RAWTEXT && mode !== TextModes.RCDATA) {
 | 
					  if (mode !== TextModes.RAWTEXT && mode !== TextModes.RCDATA) {
 | 
				
			||||||
    const preserve = context.options.whitespace === 'preserve'
 | 
					    const shouldCondense = context.options.whitespace !== 'preserve'
 | 
				
			||||||
    for (let i = 0; i < nodes.length; i++) {
 | 
					    for (let i = 0; i < nodes.length; i++) {
 | 
				
			||||||
      const node = nodes[i]
 | 
					      const node = nodes[i]
 | 
				
			||||||
      if (!context.inPre && node.type === NodeTypes.TEXT) {
 | 
					      if (!context.inPre && node.type === NodeTypes.TEXT) {
 | 
				
			||||||
@ -268,7 +268,7 @@ function parseChildren(
 | 
				
			|||||||
          if (
 | 
					          if (
 | 
				
			||||||
            !prev ||
 | 
					            !prev ||
 | 
				
			||||||
            !next ||
 | 
					            !next ||
 | 
				
			||||||
            (!preserve &&
 | 
					            (shouldCondense &&
 | 
				
			||||||
              (prev.type === NodeTypes.COMMENT ||
 | 
					              (prev.type === NodeTypes.COMMENT ||
 | 
				
			||||||
                next.type === NodeTypes.COMMENT ||
 | 
					                next.type === NodeTypes.COMMENT ||
 | 
				
			||||||
                (prev.type === NodeTypes.ELEMENT &&
 | 
					                (prev.type === NodeTypes.ELEMENT &&
 | 
				
			||||||
@ -281,7 +281,7 @@ function parseChildren(
 | 
				
			|||||||
            // Otherwise, the whitespace is condensed into a single space
 | 
					            // Otherwise, the whitespace is condensed into a single space
 | 
				
			||||||
            node.content = ' '
 | 
					            node.content = ' '
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        } else if (!preserve) {
 | 
					        } else if (shouldCondense) {
 | 
				
			||||||
          // in condense mode, consecutive whitespaces in text are condensed
 | 
					          // in condense mode, consecutive whitespaces in text are condensed
 | 
				
			||||||
          // down to a single space.
 | 
					          // down to a single space.
 | 
				
			||||||
          node.content = node.content.replace(/[\t\r\n\f ]+/g, ' ')
 | 
					          node.content = node.content.replace(/[\t\r\n\f ]+/g, ' ')
 | 
				
			||||||
@ -428,7 +428,7 @@ function parseElement(
 | 
				
			|||||||
  if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {
 | 
					  if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {
 | 
				
			||||||
    // #4030 self-closing <pre> tag
 | 
					    // #4030 self-closing <pre> tag
 | 
				
			||||||
    if (context.options.isPreTag(element.tag)) {
 | 
					    if (context.options.isPreTag(element.tag)) {
 | 
				
			||||||
      context.inPre = false
 | 
					      context.inPre--
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return element
 | 
					    return element
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -479,10 +479,10 @@ function parseElement(
 | 
				
			|||||||
  element.loc = getSelection(context, element.loc.start)
 | 
					  element.loc = getSelection(context, element.loc.start)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (isPreBoundary) {
 | 
					  if (isPreBoundary) {
 | 
				
			||||||
    context.inPre = false
 | 
					    context.inPre--
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (isVPreBoundary) {
 | 
					  if (isVPreBoundary) {
 | 
				
			||||||
    context.inVPre = false
 | 
					    context.inVPre--
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return element
 | 
					  return element
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -534,9 +534,8 @@ function parseTag(
 | 
				
			|||||||
  const currentSource = context.source
 | 
					  const currentSource = context.source
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // check <pre> tag
 | 
					  // check <pre> tag
 | 
				
			||||||
  const isPreTag = context.options.isPreTag(tag)
 | 
					  if (context.options.isPreTag(tag)) {
 | 
				
			||||||
  if (isPreTag) {
 | 
					    context.inPre++
 | 
				
			||||||
    context.inPre = true
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Attributes.
 | 
					  // Attributes.
 | 
				
			||||||
@ -548,7 +547,7 @@ function parseTag(
 | 
				
			|||||||
    !context.inVPre &&
 | 
					    !context.inVPre &&
 | 
				
			||||||
    props.some(p => p.type === NodeTypes.DIRECTIVE && p.name === 'pre')
 | 
					    props.some(p => p.type === NodeTypes.DIRECTIVE && p.name === 'pre')
 | 
				
			||||||
  ) {
 | 
					  ) {
 | 
				
			||||||
    context.inVPre = true
 | 
					    context.inVPre++
 | 
				
			||||||
    // reset context
 | 
					    // reset context
 | 
				
			||||||
    extend(context, cursor)
 | 
					    extend(context, cursor)
 | 
				
			||||||
    context.source = currentSource
 | 
					    context.source = currentSource
 | 
				
			||||||
 | 
				
			|||||||
@ -111,6 +111,22 @@ h1 { color: red }
 | 
				
			|||||||
    )
 | 
					    )
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  test('should parse correct range for root level self closing tag', () => {
 | 
				
			||||||
 | 
					    const content = `\n  <div/>\n`
 | 
				
			||||||
 | 
					    const { descriptor } = parse(`<template>${content}</template>`)
 | 
				
			||||||
 | 
					    expect(descriptor.template).toBeTruthy()
 | 
				
			||||||
 | 
					    expect(descriptor.template!.content).toBe(content)
 | 
				
			||||||
 | 
					    expect(descriptor.template!.loc).toMatchObject({
 | 
				
			||||||
 | 
					      start: { line: 1, column: 11, offset: 10 },
 | 
				
			||||||
 | 
					      end: {
 | 
				
			||||||
 | 
					        line: 3,
 | 
				
			||||||
 | 
					        column: 1,
 | 
				
			||||||
 | 
					        offset: 10 + content.length
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      source: content
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  test('should parse correct range for blocks with no content (self closing)', () => {
 | 
					  test('should parse correct range for blocks with no content (self closing)', () => {
 | 
				
			||||||
    const { descriptor } = parse(`<template/>`)
 | 
					    const { descriptor } = parse(`<template/>`)
 | 
				
			||||||
    expect(descriptor.template).toBeTruthy()
 | 
					    expect(descriptor.template).toBeTruthy()
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user