private renderDeclarationEnd ( code: MagicString, separatorString: string, lastSeparatorPos: number, actualContentEnd: number, renderedContentEnd: number, addSemicolon: boolean ) { if (code.original.charCodeAt(this.end - 1) === 59 /*";"*/) { code.remove(this.end - 1, this.end); } if (addSemicolon) { separatorString += ';'; } if (lastSeparatorPos !== null) { if ( code.original.charCodeAt(actualContentEnd - 1) === 10 /*"\n"*/ && (code.original.charCodeAt(this.end) === 10 /*"\n"*/ || code.original.charCodeAt(this.end) === 13 /*"\r"*/) ) { actualContentEnd--; if (code.original.charCodeAt(actualContentEnd) === 13 /*"\r"*/) { actualContentEnd--; } } if (actualContentEnd === lastSeparatorPos + 1) { code.overwrite(lastSeparatorPos, renderedContentEnd, separatorString); } else { code.overwrite(lastSeparatorPos, lastSeparatorPos + 1, separatorString); code.remove(actualContentEnd, renderedContentEnd); } } else { code.appendLeft(renderedContentEnd, separatorString); } return separatorString; }
render(code: MagicString, options: RenderOptions) { // Note that unknown test values are always included if ( !this.test.included && (this.testValue ? this.alternate === null || !this.alternate.included : !this.consequent.included) ) { const singleRetainedBranch = this.testValue ? this.consequent : this.alternate; code.remove(this.start, singleRetainedBranch.start); code.remove(singleRetainedBranch.end, this.end); removeAnnotations(this, code); singleRetainedBranch.render(code, options); } else { if (this.test.included) { this.test.render(code, options); } else { code.overwrite(this.test.start, this.test.end, this.testValue ? 'true' : 'false'); } if (this.consequent.included) { this.consequent.render(code, options); } else { code.overwrite(this.consequent.start, this.consequent.end, ';'); } if (this.alternate !== null) { if (this.alternate.included) { this.alternate.render(code, options); } else { code.remove(this.consequent.end, this.alternate.end); } } } }
render (code: MagicString, options: RenderOptions) { if (!this.module.graph.treeshake) { super.render(code, options); } else { const last = this.expressions[this.expressions.length - 1]; last.render(code, options); if ( this.parent.type === NodeType.CallExpression && last.type === NodeType.MemberExpression && this.expressions.length > 1 ) { this.expressions[0].included = true; } const included = this.expressions .slice(0, this.expressions.length - 1) .filter(expression => expression.included); if (included.length === 0) { code.remove(this.start, last.start); code.remove(last.end, this.end); } else { let previousEnd = this.start; for (const expression of included) { expression.render(code, options); code.remove(previousEnd, expression.start); code.appendLeft(expression.end, ', '); previousEnd = expression.end; } code.remove(previousEnd, last.start); code.remove(last.end, this.end); } } }
render (code: MagicString, options: RenderOptions) { if (this.declaration) { code.remove(this.start, this.declaration.start); this.declaration.render(code, options); } else { const start = this.leadingCommentStart || this.start; const end = this.next || this.end; code.remove(start, end); } }
export function treeshakeNode(node: Node, code: MagicString, start: number, end: number) { code.remove(start, end); if (node.annotations) { for (const annotation of node.annotations) { if (annotation.start < start) { code.remove(annotation.start, annotation.end); } else { return; } } } }
render (code: MagicString, options: RenderOptions) { if (this.module.graph.treeshake) { if (this.testValue === UNKNOWN_VALUE) { super.render(code, options); } else { code.overwrite( this.test.start, this.test.end, JSON.stringify(this.testValue) ); // TODO if no block-scoped declarations, remove enclosing // curlies and dedent block (if there is a block) if (this.hoistedVars) { const names = this.hoistedVars .map(name => { const variable = this.scope.findVariable(name); return variable.included ? variable.getName() : null; }) .filter(Boolean); if (names.length > 0) { code.appendLeft(this.start, `var ${names.join(', ')};\n\n`); } } if (this.testValue) { code.remove(this.start, this.consequent.start); code.remove(this.consequent.end, this.end); this.consequent.render(code, options); } else { code.remove( this.start, this.alternate ? this.alternate.start : this.next || this.end ); if (this.alternate) { this.alternate.render(code, options); } else if (statementsWithIfStatements.has(this.parent.type)) { code.prependRight(this.start, '{}'); } } } } else { super.render(code, options); } }
export function remove_indentation(code: MagicString, node: Node) { const indent = code.getIndentString(); const pattern = new RegExp(`^${indent}`, 'gm'); const excluded = []; walk(node, { enter(node) { if (node.type === 'TemplateElement') { excluded.push(node); } } }); const str = code.original.slice(node.start, node.end); let match; while (match = pattern.exec(str)) { const index = node.start + match.index; while (excluded[0] && excluded[0].end < index) excluded.shift(); if (excluded[0] && excluded[0].start < index) continue; code.remove(index, index + indent.length); } }
export function removeNode(code: MagicString, parent: Node, node: Node) { const key = keys[parent.type]; const offset = offsets[parent.type]; if (!key || !offset) throw new Error(`not implemented: ${parent.type}`); const list = parent[key]; const i = list.indexOf(node); if (i === -1) throw new Error('node not in list'); let a; let b; if (list.length === 1) { // remove everything, leave {} a = parent.start + offset[0]; b = parent.end + offset[1]; } else if (i === 0) { // remove everything before second node, including comments a = parent.start + offset[0]; while (/\s/.test(code.original[a])) a += 1; b = list[i].end; while (/[\s,]/.test(code.original[b])) b += 1; } else { // remove the end of the previous node to the end of this one a = list[i - 1].end; b = node.end; } code.remove(a, b); list.splice(i, 1); return; }
export function renderStatementList (statements: Node[], code: MagicString, start: number, end: number, options: RenderOptions) { if (statements.length === 0) return; let currentNode, currentNodeStart, currentNodeNeedsBoundaries, nextNodeStart; let nextNode = statements[0]; let nextNodeNeedsBoundaries = !nextNode.included || nextNode.needsBoundaries; if (nextNodeNeedsBoundaries) { nextNodeStart = start + findFirstLineBreakOutsideComment(code.original.slice(start, nextNode.start)) + 1; } for (let nextIndex = 1; nextIndex <= statements.length; nextIndex++) { currentNode = nextNode; currentNodeStart = nextNodeStart; currentNodeNeedsBoundaries = nextNodeNeedsBoundaries; nextNode = statements[nextIndex]; nextNodeNeedsBoundaries = nextNode === undefined ? false : !nextNode.included || nextNode.needsBoundaries; if (currentNodeNeedsBoundaries || nextNodeNeedsBoundaries) { nextNodeStart = currentNode.end + findFirstLineBreakOutsideComment( code.original.slice(currentNode.end, nextNode === undefined ? end : nextNode.start) ) + 1; if (currentNode.included) { currentNodeNeedsBoundaries ? currentNode.render(code, options, { start: currentNodeStart, end: nextNodeStart }) : currentNode.render(code, options); } else { code.remove(currentNodeStart, nextNodeStart); } } else { currentNode.render(code, options); } } }
nodesToRemove.forEach(node => { // remove any trailing comma const end = (output.slice(node.getEnd(), node.getEnd() + 1) === ',') ? node.getEnd() + 1 : node.getEnd(); output.remove(node.getFullStart(), end); });