UNPKG

@rightcapital/phpdoc-parser

Version:

TypeScript version of PHPDoc parser with support for intersection types and generics

578 lines (577 loc) • 29.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TypeParser = void 0; const const_expr_array_node_1 = require("../ast/const-expr/const-expr-array-node"); const const_expr_integer_node_1 = require("../ast/const-expr/const-expr-integer-node"); const const_expr_string_node_1 = require("../ast/const-expr/const-expr-string-node"); const quote_aware_const_expr_string_node_1 = require("../ast/const-expr/quote-aware-const-expr-string-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 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 union_type_node_1 = require("../ast/type/union-type-node"); const types_1 = require("../ast/types"); const lexer_1 = require("../lexer/lexer"); const parser_exception_1 = require("./parser-exception"); const string_unescaper_1 = require("./string-unescaper"); class TypeParser { constructor(constExprParser = null, quoteAwareConstExprString = false, usedAttributes = {}) { var _a, _b; this.constExprParser = constExprParser; this.quoteAwareConstExprString = quoteAwareConstExprString; this.useLinesAttributes = (_a = usedAttributes.lines) !== null && _a !== void 0 ? _a : false; this.useIndexAttributes = (_b = usedAttributes.indexes) !== null && _b !== void 0 ? _b : false; } parse(tokens) { const startLine = tokens.currentTokenLine(); const startIndex = tokens.currentTokenIndex(); if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_NULLABLE)) { return this.parseNullable(tokens); } let type = this.parseAtomic(tokens); if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_UNION)) { type = this.parseUnion(tokens, type); } else if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_INTERSECTION)) { type = this.parseIntersection(tokens, type); } else if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) { type = this.tryParseArrayOrOffsetAccess(tokens, type); } return this.enrichWithAttributes(tokens, type, startLine, startIndex); } enrichWithAttributes(tokens, type, startLine, startIndex) { if (this.useLinesAttributes) { type.setAttribute(types_1.Attribute.START_LINE, startLine); type.setAttribute(types_1.Attribute.END_LINE, tokens.currentTokenLine()); } if (this.useIndexAttributes) { type.setAttribute(types_1.Attribute.START_INDEX, startIndex); type.setAttribute(types_1.Attribute.END_INDEX, tokens.endIndexOfLastRelevantToken()); } return type; } subParse(tokens) { const startLine = tokens.currentTokenLine(); const startIndex = tokens.currentTokenIndex(); let type; if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_NULLABLE)) { type = this.parseNullable(tokens); } else { type = this.parseAtomic(tokens); if (tokens.isCurrentTokenValue('is')) { type = this.parseConditional(tokens, type); } else { tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_UNION)) { type = this.subParseUnion(tokens, type); } else if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_INTERSECTION)) { type = this.subParseIntersection(tokens, type); } } } return this.enrichWithAttributes(tokens, type, startLine, startIndex); } parseAtomic(tokens) { const startLine = tokens.currentTokenLine(); const startIndex = tokens.currentTokenIndex(); let type; if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_OPEN_PARENTHESES)) { tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); type = this.subParse(tokens); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); tokens.consumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_PARENTHESES); if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) { type = this.tryParseArrayOrOffsetAccess(tokens, type); } return this.enrichWithAttributes(tokens, type, startLine, startIndex); } if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_THIS_VARIABLE)) { type = new this_type_node_1.ThisTypeNode(); if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) { type = this.tryParseArrayOrOffsetAccess(tokens, this.enrichWithAttributes(tokens, type, startLine, startIndex)); } return this.enrichWithAttributes(tokens, type, startLine, startIndex); } const currentTokenValue = tokens.currentTokenValue(); tokens.pushSavePoint(); if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_IDENTIFIER)) { const identifierTypeNode = new identifier_type_node_1.IdentifierTypeNode(currentTokenValue); type = identifierTypeNode; if (!tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_DOUBLE_COLON)) { if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_ANGLE_BRACKET)) { type = this.parseGeneric(tokens, identifierTypeNode); } else if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) { type = this.tryParseArrayOrOffsetAccess(tokens, type); } else if (['array', 'list', 'object'].includes(identifierTypeNode.name) && tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_CURLY_BRACKET) && !tokens.isPrecededByHorizontalWhitespace()) { if (identifierTypeNode.name === 'object') { type = this.parseObjectShape(tokens); } else { type = this.parseArrayShape(tokens, type, identifierTypeNode.name); } if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) { type = this.tryParseArrayOrOffsetAccess(tokens, type); } } return this.enrichWithAttributes(tokens, type, startLine, startIndex); } tokens.rollback(); } else { tokens.dropSavePoint(); } const exception = new parser_exception_1.ParserException(tokens.currentTokenValue(), tokens.currentTokenType(), tokens.currentTokenOffset(), lexer_1.Lexer.TOKEN_IDENTIFIER, null, tokens.currentTokenLine()); if (this.constExprParser === null) { throw exception; } try { const constExpr = this.constExprParser.parse(tokens, true); if (constExpr instanceof const_expr_array_node_1.ConstExprArrayNode) { throw exception; } return this.enrichWithAttributes(tokens, new const_type_node_1.ConstTypeNode(constExpr), startLine, startIndex); } catch (error) { exception.cause = error; throw exception; } } parseUnion(tokens, type) { const types = [type]; while (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_UNION)) { types.push(this.parseAtomic(tokens)); } return new union_type_node_1.UnionTypeNode(types); } subParseUnion(tokens, type) { const types = [type]; while (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_UNION)) { tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); types.push(this.parseAtomic(tokens)); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); } return new union_type_node_1.UnionTypeNode(types); } parseIntersection(tokens, type) { const types = [type]; while (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_INTERSECTION)) { types.push(this.parseAtomic(tokens)); } return new intersection_type_node_1.IntersectionTypeNode(types); } subParseIntersection(tokens, type) { const types = [type]; while (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_INTERSECTION)) { tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); types.push(this.parseAtomic(tokens)); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); } return new intersection_type_node_1.IntersectionTypeNode(types); } parseConditional(tokens, subjectType) { tokens.consumeTokenType(lexer_1.Lexer.TOKEN_IDENTIFIER); let negated = false; if (tokens.isCurrentTokenValue('not')) { negated = true; tokens.consumeTokenType(lexer_1.Lexer.TOKEN_IDENTIFIER); } const targetType = this.parse(tokens); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); tokens.consumeTokenType(lexer_1.Lexer.TOKEN_NULLABLE); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); const ifType = this.parse(tokens); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); tokens.consumeTokenType(lexer_1.Lexer.TOKEN_COLON); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); const elseType = this.subParse(tokens); return new conditional_type_node_1.ConditionalTypeNode(subjectType, targetType, ifType, elseType, negated); } parseConditionalForParameter(tokens, parameterName) { tokens.consumeTokenType(lexer_1.Lexer.TOKEN_VARIABLE); tokens.consumeTokenValue(lexer_1.Lexer.TOKEN_IDENTIFIER, 'is'); let negated = false; if (tokens.isCurrentTokenValue('not')) { negated = true; tokens.consumeTokenType(lexer_1.Lexer.TOKEN_IDENTIFIER); } const targetType = this.parse(tokens); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); tokens.consumeTokenType(lexer_1.Lexer.TOKEN_NULLABLE); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); const ifType = this.parse(tokens); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); tokens.consumeTokenType(lexer_1.Lexer.TOKEN_COLON); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); const elseType = this.subParse(tokens); return new conditional_type_for_parameter_node_1.ConditionalTypeForParameterNode(parameterName, targetType, ifType, elseType, negated); } parseNullable(tokens) { tokens.consumeTokenType(lexer_1.Lexer.TOKEN_NULLABLE); const type = this.parseAtomic(tokens); return new nullable_type_node_1.NullableTypeNode(type); } isHtml(tokens) { tokens.consumeTokenType(lexer_1.Lexer.TOKEN_OPEN_ANGLE_BRACKET); if (!tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_IDENTIFIER)) { return false; } const htmlTagName = tokens.currentTokenValue(); tokens.next(); if (!tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_ANGLE_BRACKET)) { return false; } while (!tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_END)) { if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_OPEN_ANGLE_BRACKET) && tokens.currentTokenValue().includes(`/${htmlTagName}>`)) { return true; } tokens.next(); } return false; } parseGeneric(tokens, baseType) { tokens.consumeTokenType(lexer_1.Lexer.TOKEN_OPEN_ANGLE_BRACKET); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); const genericTypes = []; const variances = []; const [genericType, variance] = this.parseGenericTypeArgument(tokens); genericTypes.push(genericType); variances.push(variance); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); while (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_COMMA)) { tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_ANGLE_BRACKET)) { break; } const [genericTypeToAddInWhileLoop, varianceToAddInWhileLoop] = this.parseGenericTypeArgument(tokens); genericTypes.push(genericTypeToAddInWhileLoop); variances.push(varianceToAddInWhileLoop); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); } tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); tokens.consumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_ANGLE_BRACKET); const type = new generic_type_node_1.GenericTypeNode(baseType, genericTypes, variances); const startLine = baseType.getAttribute(types_1.Attribute.START_LINE); const startIndex = baseType.getAttribute(types_1.Attribute.START_INDEX); if (startLine !== null && startIndex !== null) { return this.enrichWithAttributes(tokens, type, baseType.getAttribute(types_1.Attribute.START_LINE), baseType.getAttribute(types_1.Attribute.START_INDEX)); } return type; } parseGenericTypeArgument(tokens) { const startLine = tokens.currentTokenLine(); const startIndex = tokens.currentTokenIndex(); if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_WILDCARD)) { return [ this.enrichWithAttributes(tokens, new identifier_type_node_1.IdentifierTypeNode('mixed'), startLine, startIndex), generic_type_node_1.GenericTypeNode.VARIANCE_BIVARIANT, ]; } let variance; if (tokens.tryConsumeTokenValue('contravariant')) { variance = generic_type_node_1.GenericTypeNode.VARIANCE_CONTRAVARIANT; } else if (tokens.tryConsumeTokenValue('covariant')) { variance = generic_type_node_1.GenericTypeNode.VARIANCE_COVARIANT; } else { variance = generic_type_node_1.GenericTypeNode.VARIANCE_INVARIANT; } const type = this.parse(tokens); return [type, variance]; } parseCallable(tokens, identifier) { tokens.consumeTokenType(lexer_1.Lexer.TOKEN_OPEN_PARENTHESES); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); const parameters = []; if (!tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_CLOSE_PARENTHESES)) { parameters.push(this.parseCallableParameter(tokens)); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); while (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_COMMA)) { tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_CLOSE_PARENTHESES)) { break; } parameters.push(this.parseCallableParameter(tokens)); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); } } tokens.consumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_PARENTHESES); tokens.consumeTokenType(lexer_1.Lexer.TOKEN_COLON); const returnType = this.parseCallableReturnType(tokens); return new callable_type_node_1.CallableTypeNode(identifier, parameters, returnType); } parseCallableParameter(tokens) { const startLine = tokens.currentTokenLine(); const startIndex = tokens.currentTokenIndex(); const type = this.parse(tokens); const isReference = tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_REFERENCE); const isVariadic = tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_VARIADIC); let parameterName = ''; if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_VARIABLE)) { parameterName = tokens.currentTokenValue(); tokens.consumeTokenType(lexer_1.Lexer.TOKEN_VARIABLE); } const isOptional = tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_EQUAL); return this.enrichWithAttributes(tokens, new callable_type_parameter_node_1.CallableTypeParameterNode(type, isReference, isVariadic, parameterName, isOptional), startLine, startIndex); } parseCallableReturnType(tokens) { const startLine = tokens.currentTokenLine(); const startIndex = tokens.currentTokenIndex(); let type; if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_NULLABLE)) { return this.parseNullable(tokens); } if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_OPEN_PARENTHESES)) { type = this.parse(tokens); tokens.consumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_PARENTHESES); if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) { type = this.tryParseArrayOrOffsetAccess(tokens, type); } return type; } if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_THIS_VARIABLE)) { type = new this_type_node_1.ThisTypeNode(); if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) { type = this.tryParseArrayOrOffsetAccess(tokens, this.enrichWithAttributes(tokens, type, startLine, startIndex)); } return type; } const currentTokenValue = tokens.currentTokenValue(); tokens.pushSavePoint(); if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_IDENTIFIER)) { type = new identifier_type_node_1.IdentifierTypeNode(currentTokenValue); if (!tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_DOUBLE_COLON)) { if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_ANGLE_BRACKET)) { type = this.parseGeneric(tokens, this.enrichWithAttributes(tokens, type, startLine, startIndex)); } else if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) { type = this.tryParseArrayOrOffsetAccess(tokens, this.enrichWithAttributes(tokens, type, startLine, startIndex)); } } else { tokens.rollback(); } return type; } tokens.dropSavePoint(); const exception = new parser_exception_1.ParserException(tokens.currentTokenValue(), tokens.currentTokenType(), tokens.currentTokenOffset(), lexer_1.Lexer.TOKEN_IDENTIFIER, null, tokens.currentTokenLine()); if (this.constExprParser === null) { throw exception; } if (this.constExprParser === null) { throw exception; } try { const constExpr = this.constExprParser.parse(tokens, true); if (constExpr instanceof const_expr_array_node_1.ConstExprArrayNode) { throw exception; } type = new const_type_node_1.ConstTypeNode(constExpr); if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) { type = this.tryParseArrayOrOffsetAccess(tokens, this.enrichWithAttributes(tokens, type, startLine, startIndex)); } return type; } catch (e) { if (e instanceof Error) { throw exception; } else { throw e; } } } tryParseCallable(tokens, identifier) { try { tokens.pushSavePoint(); const type = this.parseCallable(tokens, identifier); tokens.dropSavePoint(); return type; } catch (e) { if (e instanceof parser_exception_1.ParserException) { tokens.rollback(); return identifier; } throw e; } } tryParseArrayOrOffsetAccess(tokens, type) { try { while (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET)) { tokens.pushSavePoint(); const canBeOffsetAccessType = !tokens.isPrecededByHorizontalWhitespace(); tokens.consumeTokenType(lexer_1.Lexer.TOKEN_OPEN_SQUARE_BRACKET); if (canBeOffsetAccessType && !tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_CLOSE_SQUARE_BRACKET)) { const offset = this.parse(tokens); tokens.consumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_SQUARE_BRACKET); tokens.dropSavePoint(); type = new offset_access_type_node_1.OffsetAccessTypeNode(type, offset); } else { tokens.consumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_SQUARE_BRACKET); tokens.dropSavePoint(); type = new array_type_node_1.ArrayTypeNode(type); } } } catch (e) { if (e instanceof parser_exception_1.ParserException) { tokens.rollback(); } else { throw e; } } return type; } parseArrayShape(tokens, type, kind) { tokens.consumeTokenType(lexer_1.Lexer.TOKEN_OPEN_CURLY_BRACKET); const items = []; let sealed = true; do { tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_CURLY_BRACKET)) { return new array_shape_node_1.ArrayShapeNode(items, true, kind); } if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_VARIADIC)) { sealed = false; tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_COMMA); break; } items.push(this.parseArrayShapeItem(tokens)); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); } while (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_COMMA)); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); tokens.consumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_CURLY_BRACKET); return new array_shape_node_1.ArrayShapeNode(items, sealed, kind); } parseArrayShapeItem(tokens) { const startLine = tokens.currentTokenLine(); const startIndex = tokens.currentTokenIndex(); try { tokens.pushSavePoint(); const key = this.parseArrayShapeKey(tokens); const optional = tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_NULLABLE); tokens.consumeTokenType(lexer_1.Lexer.TOKEN_COLON); const value = this.parse(tokens); tokens.dropSavePoint(); return this.enrichWithAttributes(tokens, new array_shape_item_node_1.ArrayShapeItemNode(key, optional, value), startLine, startIndex); } catch (e) { if (e instanceof parser_exception_1.ParserException) { tokens.rollback(); const value = this.parse(tokens); return this.enrichWithAttributes(tokens, new array_shape_item_node_1.ArrayShapeItemNode(null, false, value), startLine, startIndex); } throw e; } } parseArrayShapeKey(tokens) { const startLine = tokens.currentTokenLine(); const startIndex = tokens.currentTokenIndex(); let key; if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_INTEGER)) { key = new const_expr_integer_node_1.ConstExprIntegerNode(tokens.currentTokenValue().replaceAll('_', '')); tokens.next(); } else if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_SINGLE_QUOTED_STRING)) { if (this.quoteAwareConstExprString) { key = new quote_aware_const_expr_string_node_1.QuoteAwareConstExprStringNode(string_unescaper_1.StringUnescaper.unescapeString(tokens.currentTokenValue()), quote_aware_const_expr_string_node_1.QuoteAwareConstExprStringNode.SINGLE_QUOTED); } else { key = new const_expr_string_node_1.ConstExprStringNode(tokens.currentTokenValue().replace(/(^'|'$)/g, '')); } tokens.next(); } else if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_DOUBLE_QUOTED_STRING)) { if (this.quoteAwareConstExprString) { key = new quote_aware_const_expr_string_node_1.QuoteAwareConstExprStringNode(string_unescaper_1.StringUnescaper.unescapeString(tokens.currentTokenValue()), quote_aware_const_expr_string_node_1.QuoteAwareConstExprStringNode.DOUBLE_QUOTED); } else { key = new const_expr_string_node_1.ConstExprStringNode(tokens.currentTokenValue().replace(/(^"|"$)/g, '')); } tokens.next(); } else { key = new identifier_type_node_1.IdentifierTypeNode(tokens.currentTokenValue()); tokens.consumeTokenType(lexer_1.Lexer.TOKEN_IDENTIFIER); } return this.enrichWithAttributes(tokens, key, startLine, startIndex); } parseObjectShape(tokens) { tokens.consumeTokenType(lexer_1.Lexer.TOKEN_OPEN_CURLY_BRACKET); const items = []; do { tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); if (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_CURLY_BRACKET)) { return new object_shape_node_1.ObjectShapeNode(items); } items.push(this.parseObjectShapeItem(tokens)); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); } while (tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_COMMA)); tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_PHPDOC_EOL); tokens.consumeTokenType(lexer_1.Lexer.TOKEN_CLOSE_CURLY_BRACKET); return new object_shape_node_1.ObjectShapeNode(items); } parseObjectShapeItem(tokens) { const startLine = tokens.currentTokenLine(); const startIndex = tokens.currentTokenIndex(); const key = this.parseObjectShapeKey(tokens); const optional = tokens.tryConsumeTokenType(lexer_1.Lexer.TOKEN_NULLABLE); tokens.consumeTokenType(lexer_1.Lexer.TOKEN_COLON); const value = this.parse(tokens); return this.enrichWithAttributes(tokens, new object_shape_item_node_1.ObjectShapeItemNode(key, optional, value), startLine, startIndex); } parseObjectShapeKey(tokens) { const startLine = tokens.currentTokenLine(); const startIndex = tokens.currentTokenIndex(); let key; if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_SINGLE_QUOTED_STRING)) { if (this.quoteAwareConstExprString) { key = new quote_aware_const_expr_string_node_1.QuoteAwareConstExprStringNode(string_unescaper_1.StringUnescaper.unescapeString(tokens.currentTokenValue()), quote_aware_const_expr_string_node_1.QuoteAwareConstExprStringNode.SINGLE_QUOTED); } else { key = new const_expr_string_node_1.ConstExprStringNode(tokens.currentTokenValue().replace(/(^'|'$)/g, '')); } tokens.next(); } else if (tokens.isCurrentTokenType(lexer_1.Lexer.TOKEN_DOUBLE_QUOTED_STRING)) { if (this.quoteAwareConstExprString) { key = new quote_aware_const_expr_string_node_1.QuoteAwareConstExprStringNode(string_unescaper_1.StringUnescaper.unescapeString(tokens.currentTokenValue()), quote_aware_const_expr_string_node_1.QuoteAwareConstExprStringNode.DOUBLE_QUOTED); } else { key = new const_expr_string_node_1.ConstExprStringNode(tokens.currentTokenValue().replace(/(^"|"$)/g, '')); } tokens.next(); } else { key = new identifier_type_node_1.IdentifierTypeNode(tokens.currentTokenValue()); tokens.consumeTokenType(lexer_1.Lexer.TOKEN_IDENTIFIER); } return this.enrichWithAttributes(tokens, key, startLine, startIndex); } } exports.TypeParser = TypeParser;