@rightcapital/phpdoc-parser
Version:
TypeScript version of PHPDoc parser with support for intersection types and generics
613 lines (612 loc) • 31.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Printer = void 0;
const base_node_1 = require("../ast/base-node");
const const_expr_array_node_1 = require("../ast/const-expr/const-expr-array-node");
const const_expr_node_1 = require("../ast/const-expr/const-expr-node");
const assert_tag_method_value_node_1 = require("../ast/php-doc/assert-tag-method-value-node");
const assert_tag_property_value_node_1 = require("../ast/php-doc/assert-tag-property-value-node");
const assert_tag_value_node_1 = require("../ast/php-doc/assert-tag-value-node");
const extends_tag_value_node_1 = require("../ast/php-doc/extends-tag-value-node");
const implements_tag_value_node_1 = require("../ast/php-doc/implements-tag-value-node");
const method_tag_value_node_1 = require("../ast/php-doc/method-tag-value-node");
const method_tag_value_parameter_node_1 = require("../ast/php-doc/method-tag-value-parameter-node");
const mixin_tag_value_node_1 = require("../ast/php-doc/mixin-tag-value-node");
const param_out_tag_value_node_1 = require("../ast/php-doc/param-out-tag-value-node");
const param_tag_value_node_1 = require("../ast/php-doc/param-tag-value-node");
const php_doc_node_1 = require("../ast/php-doc/php-doc-node");
const php_doc_tag_node_1 = require("../ast/php-doc/php-doc-tag-node");
const php_doc_tag_value_node_1 = require("../ast/php-doc/php-doc-tag-value-node");
const php_doc_text_node_1 = require("../ast/php-doc/php-doc-text-node");
const property_tag_value_node_1 = require("../ast/php-doc/property-tag-value-node");
const return_tag_value_node_1 = require("../ast/php-doc/return-tag-value-node");
const self_out_tag_value_node_1 = require("../ast/php-doc/self-out-tag-value-node");
const template_tag_value_node_1 = require("../ast/php-doc/template-tag-value-node");
const throws_tag_value_node_1 = require("../ast/php-doc/throws-tag-value-node");
const type_alias_import_tag_value_node_1 = require("../ast/php-doc/type-alias-import-tag-value-node");
const type_alias_tag_value_node_1 = require("../ast/php-doc/type-alias-tag-value-node");
const uses_tag_value_node_1 = require("../ast/php-doc/uses-tag-value-node");
const var_tag_value_node_1 = require("../ast/php-doc/var-tag-value-node");
const array_shape_item_node_1 = require("../ast/type/array-shape-item-node");
const array_shape_node_1 = require("../ast/type/array-shape-node");
const array_type_node_1 = require("../ast/type/array-type-node");
const callable_type_node_1 = require("../ast/type/callable-type-node");
const callable_type_parameter_node_1 = require("../ast/type/callable-type-parameter-node");
const conditional_type_for_parameter_node_1 = require("../ast/type/conditional-type-for-parameter-node");
const conditional_type_node_1 = require("../ast/type/conditional-type-node");
const const_type_node_1 = require("../ast/type/const-type-node");
const generic_type_node_1 = require("../ast/type/generic-type-node");
const identifier_type_node_1 = require("../ast/type/identifier-type-node");
const intersection_type_node_1 = require("../ast/type/intersection-type-node");
const invalid_type_node_1 = require("../ast/type/invalid-type-node");
const nullable_type_node_1 = require("../ast/type/nullable-type-node");
const object_shape_item_node_1 = require("../ast/type/object-shape-item-node");
const object_shape_node_1 = require("../ast/type/object-shape-node");
const offset_access_type_node_1 = require("../ast/type/offset-access-type-node");
const this_type_node_1 = require("../ast/type/this-type-node");
const type_node_1 = require("../ast/type/type-node");
const union_type_node_1 = require("../ast/type/union-type-node");
const types_1 = require("../ast/types");
const lexer_1 = require("../lexer/lexer");
const diff_elem_1 = require("./diff-elem");
const differ_1 = require("./differ");
class Printer {
constructor() {
this.listInsertionMap = {
[`${php_doc_node_1.PhpDocNode.name}->children`]: '\n * ',
[`${union_type_node_1.UnionTypeNode.name}->types`]: '|',
[`${intersection_type_node_1.IntersectionTypeNode.name}->types`]: '&',
[`${array_shape_node_1.ArrayShapeNode.name}->items`]: ', ',
[`${object_shape_node_1.ObjectShapeNode.name}->items`]: ', ',
[`${callable_type_node_1.CallableTypeNode.name}->parameters`]: ', ',
[`${generic_type_node_1.GenericTypeNode.name}->genericTypes`]: ', ',
[`${const_expr_array_node_1.ConstExprArrayNode.name}->items`]: ', ',
[`${method_tag_value_node_1.MethodTagValueNode.name}->parameters`]: ', ',
};
this.emptyListInsertionMap = {
[`${callable_type_node_1.CallableTypeNode.name}->parameters`]: ['(', '', ''],
[`${array_shape_node_1.ArrayShapeNode.name}->items`]: ['{', '', '}'],
[`${object_shape_node_1.ObjectShapeNode.name}->items`]: ['{', '', '}'],
};
this.parenthesesMap = {
[`${callable_type_node_1.CallableTypeNode.name}->returnType`]: [
callable_type_node_1.CallableTypeNode.name,
union_type_node_1.UnionTypeNode.name,
intersection_type_node_1.IntersectionTypeNode.name,
],
[`${array_type_node_1.ArrayTypeNode.name}->type`]: [
callable_type_node_1.CallableTypeNode.name,
union_type_node_1.UnionTypeNode.name,
intersection_type_node_1.IntersectionTypeNode.name,
const_type_node_1.ConstTypeNode.name,
nullable_type_node_1.NullableTypeNode.name,
],
[`${offset_access_type_node_1.OffsetAccessTypeNode.name}->type`]: [
callable_type_node_1.CallableTypeNode.name,
union_type_node_1.UnionTypeNode.name,
intersection_type_node_1.IntersectionTypeNode.name,
const_type_node_1.ConstTypeNode.name,
nullable_type_node_1.NullableTypeNode.name,
],
};
this.parenthesesListMap = {
[`${intersection_type_node_1.IntersectionTypeNode.name}->types`]: [
intersection_type_node_1.IntersectionTypeNode.name,
union_type_node_1.UnionTypeNode.name,
nullable_type_node_1.NullableTypeNode.name,
],
[`${union_type_node_1.UnionTypeNode.name}->types`]: [
intersection_type_node_1.IntersectionTypeNode.name,
union_type_node_1.UnionTypeNode.name,
nullable_type_node_1.NullableTypeNode.name,
],
};
}
printFormatPreserving(node, originalNode, originalTokens) {
this.differ = new differ_1.Differ((a, b) => {
if (a instanceof base_node_1.BaseNode && b instanceof base_node_1.BaseNode) {
return a === b.getAttribute(types_1.Attribute.ORIGINAL_NODE);
}
return false;
});
let tokenIndex = 0;
let result;
[result, tokenIndex] = this.printArrayFormatPreserving(node.children, originalNode.children, originalTokens, tokenIndex, php_doc_node_1.PhpDocNode.name, 'children');
if (result !== null) {
return (result +
originalTokens.getContentBetween(tokenIndex, originalTokens.getTokenCount()));
}
return this.print(node);
}
print(node) {
if (node instanceof php_doc_node_1.PhpDocNode) {
return `/**\n *${node.children
.map((child) => {
return ` ${this.print(child)}`;
})
.join('\n *')}\n */`;
}
if (node instanceof php_doc_text_node_1.PhpDocTextNode) {
return node.text;
}
if (node instanceof php_doc_tag_node_1.PhpDocTagNode) {
return `${node.name} ${this.print(node.value)}`.trim();
}
if (node instanceof php_doc_tag_value_node_1.PhpDocTagValueNode) {
return this.printTagValue(node);
}
if (node instanceof type_node_1.TypeNode) {
return this.printType(node);
}
if (node instanceof const_expr_node_1.ConstExprNode) {
return this.printConstExpr(node);
}
if (node instanceof method_tag_value_parameter_node_1.MethodTagValueParameterNode) {
const type = node.type ? `${this.print(node.type)} ` : '';
const isReference = node.isReference ? '&' : '';
const isVariadic = node.isVariadic ? '...' : '';
const defaultValue = node.defaultValue !== null ? ` = ${this.print(node.defaultValue)}` : '';
return `${type}${isReference}${isVariadic}${node.parameterName}${defaultValue}`;
}
if (node instanceof callable_type_parameter_node_1.CallableTypeParameterNode) {
const type = `${this.print(node.type)} `;
const isReference = node.isReference ? '&' : '';
const isVariadic = node.isVariadic ? '...' : '';
const isOptional = node.isOptional ? '=' : '';
return (`${type}${isReference}${isVariadic}${node.parameterName}`.trim() +
isOptional);
}
throw new Error(`Unknown node type ${node.getNodeType()}`);
}
printTagValue(node) {
if (node instanceof assert_tag_method_value_node_1.AssertTagMethodValueNode) {
const isNegated = node.isNegated ? '!' : '';
const isEquality = node.isEquality ? '=' : '';
const type = this.printType(node.type);
return `${isNegated}${isEquality}${type} ${node.parameter}->${node.method}() ${node.description}`.trim();
}
if (node instanceof assert_tag_property_value_node_1.AssertTagPropertyValueNode) {
const isNegated = node.isNegated ? '!' : '';
const isEquality = node.isEquality ? '=' : '';
const type = this.printType(node.type);
return `${isNegated}${isEquality}${type} ${node.parameter}->${node.property} ${node.description}`.trim();
}
if (node instanceof assert_tag_value_node_1.AssertTagValueNode) {
const isNegated = node.isNegated ? '!' : '';
const isEquality = node.isEquality ? '=' : '';
const type = this.printType(node.type);
return `${isNegated}${isEquality}${type} ${node.parameter} ${node.description}`.trim();
}
if (node instanceof extends_tag_value_node_1.ExtendsTagValueNode ||
node instanceof implements_tag_value_node_1.ImplementsTagValueNode) {
const type = this.printType(node.type);
return `${type} ${node.description}`.trim();
}
if (node instanceof method_tag_value_node_1.MethodTagValueNode) {
const staticValue = node.isStatic ? 'static ' : '';
const returnType = node.returnType !== null ? `${this.printType(node.returnType)} ` : '';
const parameters = node.parameters
.map((parameter) => {
return this.print(parameter);
})
.join(', ');
const description = node.description !== '' ? ` ${node.description}` : '';
const templateTypes = node.templateTypes.length > 0
? `<${node.templateTypes
.map((templateTag) => {
return this.print(templateTag);
})
.join(', ')}>`
: '';
return `${staticValue}${returnType}${node.methodName}${templateTypes}(${parameters})${description}`;
}
if (node instanceof mixin_tag_value_node_1.MixinTagValueNode) {
const type = this.printType(node.type);
return `${type} ${node.description}`.trim();
}
if (node instanceof param_out_tag_value_node_1.ParamOutTagValueNode) {
const type = this.printType(node.type);
return `${type} ${node.parameterName} ${node.description}`.trim();
}
if (node instanceof param_tag_value_node_1.ParamTagValueNode) {
const reference = node.isReference ? '&' : '';
const variadic = node.isVariadic ? '...' : '';
const type = this.printType(node.type);
return `${type} ${reference}${variadic}${node.parameterName} ${node.description}`.trim();
}
if (node instanceof property_tag_value_node_1.PropertyTagValueNode) {
const type = this.printType(node.type);
return `${type} ${node.propertyName} ${node.description}`.trim();
}
if (node instanceof return_tag_value_node_1.ReturnTagValueNode) {
const type = this.printType(node.type);
return `${type} ${node.description}`.trim();
}
if (node instanceof self_out_tag_value_node_1.SelfOutTagValueNode) {
const type = this.printType(node.type);
return `${type} ${node.description}`.trim();
}
if (node instanceof template_tag_value_node_1.TemplateTagValueNode) {
const bound = node.bound !== null ? ` of ${this.printType(node.bound)}` : '';
const defaultValue = node.defaultTypeNode !== null
? ` = ${this.printType(node.defaultTypeNode)}`
: '';
return `${node.name}${bound}${defaultValue} ${node.description}`.trim();
}
if (node instanceof throws_tag_value_node_1.ThrowsTagValueNode) {
const type = this.printType(node.type);
return `${type} ${node.description}`.trim();
}
if (node instanceof type_alias_import_tag_value_node_1.TypeAliasImportTagValueNode) {
return `${node.importedAlias} from ${this.printType(node.importedFrom)}${(node.importedAs !== null ? ` as ${node.importedAs}` : '').trim()}`;
}
if (node instanceof type_alias_tag_value_node_1.TypeAliasTagValueNode) {
const type = this.printType(node.type);
return `${node.alias} ${type}`.trim();
}
if (node instanceof uses_tag_value_node_1.UsesTagValueNode) {
const type = this.printType(node.type);
return `${type} ${node.description}`.trim();
}
if (node instanceof var_tag_value_node_1.VarTagValueNode) {
const type = this.printType(node.type);
return `${type} ${node.variableName} ${node.description}`.trim();
}
return node.toString();
}
printType(node) {
if (node instanceof array_shape_node_1.ArrayShapeNode) {
const items = node.items.map((item) => this.printType(item));
if (!node.sealed) {
items.push('...');
}
return `${node.kind}{${items.join(', ')}}`;
}
if (node instanceof array_shape_item_node_1.ArrayShapeItemNode) {
if (node.keyName !== null) {
return `${this.print(node.keyName)}${node.optional ? '?' : ''}: ${this.printType(node.valueType)}`;
}
return this.printType(node.valueType);
}
if (node instanceof array_type_node_1.ArrayTypeNode) {
return `${this.printOffsetAccessType(node.type)}[]`;
}
if (node instanceof callable_type_node_1.CallableTypeNode) {
const returnType = node.returnType instanceof callable_type_node_1.CallableTypeNode ||
node.returnType instanceof union_type_node_1.UnionTypeNode ||
node.returnType instanceof intersection_type_node_1.IntersectionTypeNode
? this.wrapInParentheses(node.returnType)
: this.printType(node.returnType);
const parameters = node.parameters
.map((parameter) => this.print(parameter))
.join(', ');
return `${node.identifier.toString()}(${parameters}): ${returnType}`;
}
if (node instanceof conditional_type_for_parameter_node_1.ConditionalTypeForParameterNode) {
return `(${node.parameterName} ${node.negated ? 'is not' : 'is'} ${this.printType(node.targetType)} ? ${this.printType(node.ifCondition)} : ${this.printType(node.elseCondition)})`;
}
if (node instanceof conditional_type_node_1.ConditionalTypeNode) {
return `(${this.printType(node.subjectType)} ${node.negated ? 'is not' : 'is'} ${this.printType(node.targetType)} ? ${this.printType(node.ifType)} : ${this.printType(node.elseType)})`;
}
if (node instanceof const_type_node_1.ConstTypeNode) {
return this.printConstExpr(node.constExpr);
}
if (node instanceof generic_type_node_1.GenericTypeNode) {
const genericTypes = node.genericTypes.map((type, index) => {
var _a;
const variance = (_a = node.variances[index]) !== null && _a !== void 0 ? _a : generic_type_node_1.GenericTypeNode.VARIANCE_INVARIANT;
if (variance === generic_type_node_1.GenericTypeNode.VARIANCE_INVARIANT) {
return this.printType(type);
}
if (variance === generic_type_node_1.GenericTypeNode.VARIANCE_BIVARIANT) {
return '*';
}
return `${variance} ${this.print(type)}`;
});
return `${node.type.toString()}<${genericTypes.join(', ')}>`;
}
if (node instanceof identifier_type_node_1.IdentifierTypeNode) {
return node.name;
}
if (node instanceof intersection_type_node_1.IntersectionTypeNode || node instanceof union_type_node_1.UnionTypeNode) {
const items = node.types.map((type) => {
if (type instanceof intersection_type_node_1.IntersectionTypeNode ||
type instanceof union_type_node_1.UnionTypeNode ||
type instanceof nullable_type_node_1.NullableTypeNode) {
return this.wrapInParentheses(type);
}
return this.printType(type);
});
return items.join(node instanceof intersection_type_node_1.IntersectionTypeNode ? '&' : '|');
}
if (node instanceof invalid_type_node_1.InvalidTypeNode) {
return node.toString();
}
if (node instanceof nullable_type_node_1.NullableTypeNode) {
if (node.type instanceof intersection_type_node_1.IntersectionTypeNode ||
node.type instanceof union_type_node_1.UnionTypeNode) {
return `?(${this.printType(node.type)})`;
}
return `?${this.printType(node.type)}`;
}
if (node instanceof object_shape_node_1.ObjectShapeNode) {
const items = node.items.map((item) => this.printType(item));
return `object{${items.join(', ')}}`;
}
if (node instanceof object_shape_item_node_1.ObjectShapeItemNode) {
if (node.keyName !== null) {
return `${this.print(node.keyName)}${node.optional ? '?' : ''}: ${this.printType(node.valueType)}`;
}
return this.printType(node.valueType);
}
if (node instanceof offset_access_type_node_1.OffsetAccessTypeNode) {
return `${this.printOffsetAccessType(node.type)}[${this.printType(node.offset)}]`;
}
if (node instanceof this_type_node_1.ThisTypeNode) {
return node.toString();
}
throw new Error(`Unknown type ${node.getNodeType()}`);
}
wrapInParentheses(node) {
return `(${this.printType(node)})`;
}
printOffsetAccessType(type) {
if (type instanceof callable_type_node_1.CallableTypeNode ||
type instanceof union_type_node_1.UnionTypeNode ||
type instanceof intersection_type_node_1.IntersectionTypeNode ||
type instanceof const_type_node_1.ConstTypeNode ||
type instanceof nullable_type_node_1.NullableTypeNode) {
return this.wrapInParentheses(type);
}
return this.printType(type);
}
printConstExpr(node) {
return node.toString();
}
printArrayFormatPreserving(nodes, originalNodes, originalTokens, tokenIndex, parentNodeClassName, subNodeName) {
var _a, _b, _c, _d, _e;
const diff = this.differ.diffWithReplacements(originalNodes, nodes);
const mapKey = `${parentNodeClassName}->${subNodeName}`;
let insertStr = (_a = this.listInsertionMap[mapKey]) !== null && _a !== void 0 ? _a : null;
let result = '';
let beforeFirstKeepOrReplace = true;
let delayedAdd = [];
let insertNewline = false;
const [isMultiline, beforeAsteriskIndent, afterAsteriskIndent] = this.isMultiline(tokenIndex, originalNodes, originalTokens);
if (insertStr === '\n * ') {
insertStr = `\n${beforeAsteriskIndent}*${afterAsteriskIndent}`;
}
for (let i = 0; i < diff.length; i++) {
const diffElem = diff[i];
const newNode = diffElem.new;
const originalNode = diffElem.old;
if (diffElem.type === diff_elem_1.DiffElemType.KEEP ||
diffElem.type === diff_elem_1.DiffElemType.REPLACE) {
beforeFirstKeepOrReplace = false;
if (!(newNode instanceof base_node_1.BaseNode) ||
!(originalNode instanceof base_node_1.BaseNode)) {
return null;
}
const itemStartPos = originalNode.getAttribute(types_1.Attribute.START_INDEX);
const itemEndPos = originalNode.getAttribute(types_1.Attribute.END_INDEX);
if (itemStartPos < 0 || itemEndPos < 0 || itemStartPos < tokenIndex) {
throw new Error('Invalid position');
}
result += originalTokens.getContentBetween(tokenIndex, itemStartPos);
if (delayedAdd.length > 0) {
for (const delayedNode of delayedAdd) {
const parenthesesNeeded = mapKey in this.parenthesesListMap &&
this.parenthesesListMap[mapKey].includes(delayedNode.constructor.name);
if (parenthesesNeeded) {
result += '(';
}
result += this.printNodeFormatPreserving(delayedNode, originalTokens);
if (parenthesesNeeded) {
result += ')';
}
if (insertNewline) {
result += `\n${beforeAsteriskIndent}*${afterAsteriskIndent}`;
}
else {
result += insertStr;
}
}
delayedAdd = [];
}
const parenthesesNeeded = ((_b = this.parenthesesListMap[mapKey]) === null || _b === void 0 ? void 0 : _b.includes(newNode.constructor.name)) &&
!((_c = this.parenthesesListMap[mapKey]) === null || _c === void 0 ? void 0 : _c.includes(originalNode.constructor.name));
const addParentheses = parenthesesNeeded &&
!originalTokens.hasParentheses(itemStartPos, itemEndPos);
if (addParentheses) {
result += '(';
}
result += this.printNodeFormatPreserving(newNode, originalTokens);
if (addParentheses) {
result += ')';
}
tokenIndex = itemEndPos + 1;
}
else if (diffElem.type === diff_elem_1.DiffElemType.ADD) {
if (insertStr === null) {
return null;
}
if (!(newNode instanceof base_node_1.BaseNode)) {
return null;
}
if (insertStr === ', ' && isMultiline) {
insertStr = ',';
insertNewline = true;
}
if (beforeFirstKeepOrReplace) {
delayedAdd.push(newNode);
continue;
}
const itemEndPos = tokenIndex - 1;
if (insertNewline) {
result += `${insertStr}\n${beforeAsteriskIndent}*${afterAsteriskIndent}`;
}
else {
result += insertStr;
}
const parenthesesNeeded = (_d = this.parenthesesListMap[mapKey]) === null || _d === void 0 ? void 0 : _d.includes(newNode.constructor.name);
if (parenthesesNeeded) {
result += '(';
}
result += this.printNodeFormatPreserving(newNode, originalTokens);
if (parenthesesNeeded) {
result += ')';
}
tokenIndex = itemEndPos + 1;
}
else if (diffElem.type === diff_elem_1.DiffElemType.REMOVE) {
if (!(originalNode instanceof base_node_1.BaseNode)) {
return null;
}
const itemStartPos = originalNode.getAttribute(types_1.Attribute.START_INDEX);
const itemEndPos = originalNode.getAttribute(types_1.Attribute.END_INDEX);
if (itemStartPos < 0 || itemEndPos < 0) {
throw new Error('Invalid index');
}
if (i === 0) {
const originalTokensArray = originalTokens.getTokens();
for (let j = tokenIndex; j < itemStartPos; j++) {
if (originalTokensArray[j][lexer_1.Lexer.TYPE_OFFSET] ===
lexer_1.Lexer.TOKEN_PHPDOC_EOL) {
break;
}
result += originalTokensArray[j][lexer_1.Lexer.VALUE_OFFSET];
}
}
tokenIndex = itemEndPos + 1;
}
if (delayedAdd.length > 0) {
if (!(mapKey in this.emptyListInsertionMap)) {
return null;
}
const [findToken, extraLeft, extraRight] = this.emptyListInsertionMap[mapKey];
if (findToken !== null) {
const originalTokensArray = originalTokens.getTokens();
for (; tokenIndex < originalTokensArray.length; tokenIndex++) {
result += originalTokensArray[tokenIndex][lexer_1.Lexer.VALUE_OFFSET];
if (originalTokensArray[tokenIndex][lexer_1.Lexer.VALUE_OFFSET] !== findToken) {
continue;
}
tokenIndex++;
break;
}
}
let isFirst = true;
result += extraLeft;
for (const delayedAddNode of delayedAdd) {
if (!isFirst) {
result += insertStr;
if (insertNewline) {
result += `${(_e = originalTokens.getDetectedNewline()) !== null && _e !== void 0 ? _e : '\n'}${beforeAsteriskIndent}${afterAsteriskIndent}`;
}
result += this.printNodeFormatPreserving(delayedAddNode, originalTokens);
isFirst = false;
}
result += extraRight;
}
}
}
return [result, tokenIndex];
}
isMultiline(initialIndex, nodes, originalTokens) {
let isMultiline = nodes.length > 1;
let pos = initialIndex;
let allText = '';
for (const node of nodes) {
if (!(node instanceof base_node_1.BaseNode)) {
continue;
}
const endPos = node.getAttribute(types_1.Attribute.END_INDEX) + 1;
const text = originalTokens.getContentBetween(pos, endPos);
allText += text;
if (text.indexOf('\n') === -1) {
isMultiline = false;
}
pos = endPos;
}
const matches = allText.matchAll(/\n(\s*)\*(\s*)/g);
let before = '';
let after = '';
for (const match of matches) {
if (match[1].length > before.length) {
before = match[1];
}
if (match[2].length > after.length) {
after = match[2];
}
}
return [isMultiline, before, after];
}
printNodeFormatPreserving(node, originalTokens) {
const originalNode = node.getAttribute(types_1.Attribute.ORIGINAL_NODE);
if (!originalNode) {
return this.print(node);
}
const className = node.constructor.name;
if (className !== originalNode.constructor.name) {
throw new Error('Class name mismatch');
}
const startPos = originalNode.getAttribute(types_1.Attribute.START_INDEX);
const endPos = originalNode.getAttribute(types_1.Attribute.END_INDEX);
if (startPos < 0 || endPos < 0) {
throw new Error('Invalid start or end index');
}
let result = '';
let pos = startPos;
const subNodeNames = Object.keys(node);
for (const subNodeName of subNodeNames) {
const subNode = node[subNodeName];
const origSubNode = originalNode[subNodeName];
if (!(subNode instanceof base_node_1.BaseNode) ||
!(origSubNode instanceof base_node_1.BaseNode)) {
if (subNode === origSubNode) {
continue;
}
if (Array.isArray(subNode) && Array.isArray(origSubNode)) {
let listResult;
[listResult, pos] = this.printArrayFormatPreserving(subNode, origSubNode, originalTokens, pos, className, subNodeName);
if (listResult === null) {
return this.print(node);
}
result += listResult;
continue;
}
return this.print(node);
}
const subStartPos = origSubNode.getAttribute(types_1.Attribute.START_INDEX);
const subEndPos = origSubNode.getAttribute(types_1.Attribute.END_INDEX);
if (subStartPos < 0 || subEndPos < 0) {
throw new Error('Invalid start or end index');
}
if (!subNode) {
return this.print(node);
}
result += originalTokens.getContentBetween(pos, subStartPos);
const mapKey = `${node.constructor.name}->${subNodeName}`;
let isParenthesesNeeded = mapKey in this.parenthesesMap &&
this.parenthesesMap[mapKey].includes(subNode.constructor.name);
if (subNode.getAttribute(types_1.Attribute.ORIGINAL_NODE) !== null) {
isParenthesesNeeded =
isParenthesesNeeded &&
this.parenthesesMap[mapKey].includes(subNode.getAttribute(types_1.Attribute.ORIGINAL_NODE)
.constructor.name);
}
const addParentheses = isParenthesesNeeded &&
!originalTokens.hasParentheses(subStartPos, subEndPos);
if (addParentheses) {
result += '(';
}
result += this.printNodeFormatPreserving(subNode, originalTokens);
if (addParentheses) {
result += ')';
}
pos = subEndPos + 1;
}
return result + originalTokens.getContentBetween(pos, endPos + 1);
}
}
exports.Printer = Printer;