{"version":3,"sources":["../../src/transactions/typeTag/parser.ts"],"sourcesContent":["// Copyright © Aptos Foundation\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n  StructTag,\n  TypeTag,\n  TypeTagAddress,\n  TypeTagBool,\n  TypeTagGeneric,\n  TypeTagReference,\n  TypeTagSigner,\n  TypeTagStruct,\n  TypeTagU128,\n  TypeTagU16,\n  TypeTagU256,\n  TypeTagU32,\n  TypeTagU64,\n  TypeTagU8,\n  TypeTagVector,\n} from \".\";\nimport { AccountAddress } from \"../../core\";\nimport { Identifier } from \"../instances/identifier\";\n\nfunction isValidIdentifier(str: string) {\n  return !!str.match(/^[_a-zA-Z0-9]+$/);\n}\n\nfunction isValidWhitespaceCharacter(char: string) {\n  return !!char.match(/\\s/);\n}\n\nfunction isGeneric(str: string) {\n  return !!str.match(/^T[0-9]+$/);\n}\n\nfunction consumeWhitespace(tagStr: string, pos: number) {\n  let i = pos;\n  for (; i < tagStr.length; i += 1) {\n    const innerChar = tagStr[i];\n\n    if (!isValidWhitespaceCharacter(innerChar)) {\n      // If it's not colons, and it's an invalid character, we will stop here\n      break;\n    }\n  }\n  return i;\n}\n\ntype TypeTagState = {\n  savedExpectedTypes: number;\n  savedStr: string;\n  savedTypes: Array<TypeTag>;\n};\n\nexport enum TypeTagParserErrorType {\n  InvalidTypeTag = \"unknown type\",\n  UnexpectedGenericType = \"unexpected generic type\",\n  UnexpectedTypeArgumentClose = \"unexpected '>'\",\n  UnexpectedWhitespaceCharacter = \"unexpected whitespace character\",\n  UnexpectedComma = \"unexpected ','\",\n  TypeArgumentCountMismatch = \"type argument count doesn't match expected amount\",\n  MissingTypeArgumentClose = \"no matching '>' for '<'\",\n  UnexpectedPrimitiveTypeArguments = \"primitive types not expected to have type arguments\",\n  UnexpectedVectorTypeArgumentCount = \"vector type expected to have exactly one type argument\",\n  UnexpectedStructFormat = \"unexpected struct format, must be of the form 0xaddress::module_name::struct_name\",\n  InvalidModuleNameCharacter = \"module name must only contain alphanumeric or '_' characters\",\n  InvalidStructNameCharacter = \"struct name must only contain alphanumeric or '_' characters\",\n}\n\nexport class TypeTagParserError extends Error {\n  constructor(typeTagStr: string, invalidReason: TypeTagParserErrorType) {\n    super(`Failed to parse typeTag '${typeTagStr}', ${invalidReason}`);\n  }\n}\n\n/**\n * All types are made of a few parts they're either:\n * 1. A simple type e.g. u8\n * 2. A standalone struct e.g. 0x1::account::Account\n * 3. A nested struct e.g. 0x1::coin::Coin<0x1234::coin::MyCoin>\n *\n * There are a few more special cases that need to be handled, however.\n * 1. Multiple generics e.g 0x1::pair::Pair<u8, u16>\n * 2. Spacing in the generics e.g. 0x1::pair::Pair< u8 , u16>\n * 3. Nested generics of different depths e.g. 0x1::pair::Pair<0x1::coin::Coin<0x1234::coin::MyCoin>, u8>\n * 4. Generics for types in ABIs are filled in with placeholders e.g T1, T2, T3\n */\nexport function parseTypeTag(typeStr: string, options?: { allowGenerics?: boolean }) {\n  const allowGenerics = options?.allowGenerics ?? false;\n\n  const saved: Array<TypeTagState> = [];\n  // This represents the internal types for a type tag e.g. '0x1::coin::Coin<innerTypes>'\n  let innerTypes: Array<TypeTag> = [];\n  // This represents the current parsed types in a comma list e.g. 'u8, u8'\n  let curTypes: Array<TypeTag> = [];\n  // This represents the current character index\n  let cur: number = 0;\n  // This represents the current working string as a type or struct name\n  let currentStr: string = \"\";\n  let expectedTypes: number = 1;\n\n  // Iterate through each character, and handle the border conditions\n  while (cur < typeStr.length) {\n    const char = typeStr[cur];\n\n    if (char === \"<\") {\n      // Start of a type argument, push current state onto a stack\n      saved.push({\n        savedExpectedTypes: expectedTypes,\n        savedStr: currentStr,\n        savedTypes: curTypes,\n      });\n\n      // Clear current state\n      currentStr = \"\";\n      curTypes = [];\n      expectedTypes = 1;\n    } else if (char === \">\") {\n      // Process last type, if there is no type string, then don't parse it\n      if (currentStr !== \"\") {\n        const newType = parseTypeTagInner(currentStr, innerTypes, allowGenerics);\n        curTypes.push(newType);\n      }\n\n      // Pop off stack outer type, if there's nothing left, there were too many '>'\n      const savedPop = saved.pop();\n      if (savedPop === undefined) {\n        throw new TypeTagParserError(typeStr, TypeTagParserErrorType.UnexpectedTypeArgumentClose);\n      }\n\n      // If the expected types don't match the number of commas, then we also fail\n      if (expectedTypes !== curTypes.length) {\n        throw new TypeTagParserError(typeStr, TypeTagParserErrorType.TypeArgumentCountMismatch);\n      }\n\n      // Add in the new created type, shifting the current types to the inner types\n      const { savedStr, savedTypes, savedExpectedTypes } = savedPop;\n      innerTypes = curTypes;\n      curTypes = savedTypes;\n      currentStr = savedStr;\n      expectedTypes = savedExpectedTypes;\n    } else if (char === \",\") {\n      // Comma means we need to start parsing a new tag, push the previous one to the curTypes\n      // Process last type, if there is no type string, then don't parse it\n      if (currentStr.length !== 0) {\n        const newType = parseTypeTagInner(currentStr, innerTypes, allowGenerics);\n\n        // parse type tag and push it on the types\n        innerTypes = [];\n        curTypes.push(newType);\n        currentStr = \"\";\n        expectedTypes += 1;\n      }\n    } else if (isValidWhitespaceCharacter(char)) {\n      // This means we should save what we have and everything else should skip until the next\n      let parsedTypeTag = false;\n      if (currentStr.length !== 0) {\n        const newType = parseTypeTagInner(currentStr, innerTypes, allowGenerics);\n\n        // parse type tag and push it on the types\n        innerTypes = [];\n        curTypes.push(newType);\n        currentStr = \"\";\n        parsedTypeTag = true;\n      }\n\n      // Skip ahead on any more whitespace\n      cur = consumeWhitespace(typeStr, cur);\n\n      // The next space MUST be a comma, or a closing > if there was something parsed before\n      // e.g. `u8 u8` is invalid but `u8, u8` is valid\n      const nextChar = typeStr[cur];\n      if (cur < typeStr.length && parsedTypeTag && nextChar !== \",\" && nextChar !== \">\") {\n        throw new TypeTagParserError(typeStr, TypeTagParserErrorType.UnexpectedWhitespaceCharacter);\n      }\n\n      // eslint-disable-next-line no-continue\n      continue;\n    } else {\n      // Any other characters just append to the current string\n      currentStr += char;\n    }\n\n    cur += 1;\n  }\n\n  // This prevents a missing '>' on type arguments\n  if (saved.length > 0) {\n    throw new TypeTagParserError(typeStr, TypeTagParserErrorType.MissingTypeArgumentClose);\n  }\n\n  // This prevents 'u8, u8' as an input\n  switch (curTypes.length) {\n    case 0:\n      return parseTypeTagInner(currentStr, innerTypes, allowGenerics);\n    case 1:\n      if (currentStr === \"\") {\n        return curTypes[0];\n      }\n      throw new TypeTagParserError(typeStr, TypeTagParserErrorType.UnexpectedComma);\n    default:\n      throw new TypeTagParserError(typeStr, TypeTagParserErrorType.UnexpectedWhitespaceCharacter);\n  }\n}\n\n/**\n * Parses a type tag with internal types associated\n * @param str\n * @param types\n */\nfunction parseTypeTagInner(str: string, types: Array<TypeTag>, allowGenerics: boolean): TypeTag {\n  // TODO: Parse references to any item not just signer\n  switch (str) {\n    case \"&signer\":\n      if (types.length > 0) {\n        throw new TypeTagParserError(str, TypeTagParserErrorType.UnexpectedPrimitiveTypeArguments);\n      }\n      return new TypeTagReference(new TypeTagSigner());\n    case \"signer\":\n      if (types.length > 0) {\n        throw new TypeTagParserError(str, TypeTagParserErrorType.UnexpectedPrimitiveTypeArguments);\n      }\n      return new TypeTagSigner();\n    case \"bool\":\n      if (types.length > 0) {\n        throw new TypeTagParserError(str, TypeTagParserErrorType.UnexpectedPrimitiveTypeArguments);\n      }\n      return new TypeTagBool();\n    case \"address\":\n      if (types.length > 0) {\n        throw new TypeTagParserError(str, TypeTagParserErrorType.UnexpectedPrimitiveTypeArguments);\n      }\n      return new TypeTagAddress();\n    case \"u8\":\n      if (types.length > 0) {\n        throw new TypeTagParserError(str, TypeTagParserErrorType.UnexpectedPrimitiveTypeArguments);\n      }\n      return new TypeTagU8();\n    case \"u16\":\n      if (types.length > 0) {\n        throw new TypeTagParserError(str, TypeTagParserErrorType.UnexpectedPrimitiveTypeArguments);\n      }\n      return new TypeTagU16();\n    case \"u32\":\n      if (types.length > 0) {\n        throw new TypeTagParserError(str, TypeTagParserErrorType.UnexpectedPrimitiveTypeArguments);\n      }\n      return new TypeTagU32();\n    case \"u64\":\n      if (types.length > 0) {\n        throw new TypeTagParserError(str, TypeTagParserErrorType.UnexpectedPrimitiveTypeArguments);\n      }\n      return new TypeTagU64();\n    case \"u128\":\n      if (types.length > 0) {\n        throw new TypeTagParserError(str, TypeTagParserErrorType.UnexpectedPrimitiveTypeArguments);\n      }\n      return new TypeTagU128();\n    case \"u256\":\n      if (types.length > 0) {\n        throw new TypeTagParserError(str, TypeTagParserErrorType.UnexpectedPrimitiveTypeArguments);\n      }\n      return new TypeTagU256();\n    case \"vector\":\n      if (types.length !== 1) {\n        throw new TypeTagParserError(str, TypeTagParserErrorType.UnexpectedVectorTypeArgumentCount);\n      }\n      return new TypeTagVector(types[0]);\n    default:\n      if (isGeneric(str)) {\n        if (allowGenerics) {\n          return new TypeTagGeneric(Number(str.split(\"T\")[1]));\n        }\n        throw new TypeTagParserError(str, TypeTagParserErrorType.UnexpectedGenericType);\n      }\n\n      // If the value doesn't contain a colon, then we'll assume it isn't trying to be a struct\n      if (!str.match(/:/)) {\n        throw new TypeTagParserError(str, TypeTagParserErrorType.InvalidTypeTag);\n      }\n\n      // Parse for a struct tag\n      // eslint-disable-next-line no-case-declarations\n      const structParts = str.split(\"::\");\n      if (structParts.length !== 3) {\n        throw new TypeTagParserError(str, TypeTagParserErrorType.UnexpectedStructFormat);\n      }\n\n      // Validate identifier characters\n      if (!isValidIdentifier(structParts[1])) {\n        throw new TypeTagParserError(str, TypeTagParserErrorType.InvalidModuleNameCharacter);\n      }\n      if (!isValidIdentifier(structParts[2])) {\n        throw new TypeTagParserError(str, TypeTagParserErrorType.InvalidStructNameCharacter);\n      }\n\n      return new TypeTagStruct(\n        new StructTag(\n          AccountAddress.fromString(structParts[0]),\n          new Identifier(structParts[1]),\n          new Identifier(structParts[2]),\n          types,\n        ),\n      );\n  }\n}\n"],"mappings":"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","names":["isValidIdentifier","str","isValidWhitespaceCharacter","char","isGeneric","consumeWhitespace","tagStr","pos","innerChar","TypeTagParserErrorType","TypeTagParserError","typeTagStr","invalidReason","parseTypeTag","typeStr","options","allowGenerics","saved","innerTypes","curTypes","cur","currentStr","expectedTypes","newType","parseTypeTagInner","savedPop","savedStr","savedTypes","savedExpectedTypes","parsedTypeTag","nextChar","types","TypeTagReference","TypeTagSigner","TypeTagBool","TypeTagAddress","TypeTagU8","TypeTagU16","TypeTagU32","TypeTagU64","TypeTagU128","TypeTagU256","TypeTagVector","TypeTagGeneric","structParts","TypeTagStruct","StructTag","AccountAddress","Identifier"]}