From 499abe195e3fe90138743214108d97f78153cb82 Mon Sep 17 00:00:00 2001 From: Kilian Hofmann Date: Tue, 1 Jun 2021 19:56:34 +0200 Subject: [PATCH] Vendor --- vendor/symfony/polyfill-intl-idn/Idn.php | 921 +++ vendor/symfony/polyfill-intl-idn/Info.php | 23 + vendor/symfony/polyfill-intl-idn/LICENSE | 19 + vendor/symfony/polyfill-intl-idn/README.md | 12 + .../Resources/unidata/DisallowedRanges.php | 375 ++ .../Resources/unidata/Regex.php | 24 + .../Resources/unidata/deviation.php | 8 + .../Resources/unidata/disallowed.php | 2638 ++++++++ .../unidata/disallowed_STD3_mapped.php | 308 + .../unidata/disallowed_STD3_valid.php | 71 + .../Resources/unidata/ignored.php | 273 + .../Resources/unidata/mapped.php | 5778 +++++++++++++++++ .../Resources/unidata/virama.php | 65 + .../symfony/polyfill-intl-idn/bootstrap.php | 141 + .../symfony/polyfill-intl-idn/composer.json | 45 + .../symfony/polyfill-intl-normalizer/LICENSE | 19 + .../polyfill-intl-normalizer/Normalizer.php | 308 + .../polyfill-intl-normalizer/README.md | 14 + .../Resources/stubs/Normalizer.php | 17 + .../unidata/canonicalComposition.php | 945 +++ .../unidata/canonicalDecomposition.php | 2065 ++++++ .../Resources/unidata/combiningClass.php | 876 +++ .../unidata/compatibilityDecomposition.php | 3695 +++++++++++ .../polyfill-intl-normalizer/bootstrap.php | 19 + .../polyfill-intl-normalizer/composer.json | 39 + vendor/symfony/polyfill-php70/LICENSE | 19 + vendor/symfony/polyfill-php70/Php70.php | 74 + vendor/symfony/polyfill-php70/README.md | 28 + .../Resources/stubs/ArithmeticError.php | 5 + .../Resources/stubs/AssertionError.php | 5 + .../Resources/stubs/DivisionByZeroError.php | 5 + .../polyfill-php70/Resources/stubs/Error.php | 5 + .../Resources/stubs/ParseError.php | 5 + ...SessionUpdateTimestampHandlerInterface.php | 23 + .../Resources/stubs/TypeError.php | 5 + vendor/symfony/polyfill-php70/bootstrap.php | 30 + vendor/symfony/polyfill-php70/composer.json | 37 + vendor/symfony/polyfill-php72/LICENSE | 19 + vendor/symfony/polyfill-php72/Php72.php | 217 + vendor/symfony/polyfill-php72/README.md | 28 + vendor/symfony/polyfill-php72/bootstrap.php | 57 + vendor/symfony/polyfill-php72/composer.json | 35 + vendor/webonyx/graphql-php/CHANGELOG.md | 208 + vendor/webonyx/graphql-php/LICENSE | 21 + vendor/webonyx/graphql-php/README.md | 52 + vendor/webonyx/graphql-php/UPGRADE.md | 527 ++ vendor/webonyx/graphql-php/composer.json | 56 + .../graphql-php/docs/best-practices.md | 19 + .../graphql-php/docs/complementary-tools.md | 25 + vendor/webonyx/graphql-php/docs/concepts.md | 139 + .../webonyx/graphql-php/docs/data-fetching.md | 273 + .../graphql-php/docs/error-handling.md | 193 + .../graphql-php/docs/executing-queries.md | 208 + .../graphql-php/docs/getting-started.md | 125 + .../webonyx/graphql-php/docs/how-it-works.md | 35 + vendor/webonyx/graphql-php/docs/index.md | 55 + vendor/webonyx/graphql-php/docs/reference.md | 2336 +++++++ vendor/webonyx/graphql-php/docs/security.md | 94 + .../docs/type-system/directives.md | 61 + .../docs/type-system/enum-types.md | 182 + .../graphql-php/docs/type-system/index.md | 127 + .../docs/type-system/input-types.md | 172 + .../docs/type-system/interfaces.md | 136 + .../docs/type-system/lists-and-nonnulls.md | 62 + .../docs/type-system/object-types.md | 210 + .../docs/type-system/scalar-types.md | 130 + .../graphql-php/docs/type-system/schema.md | 194 + .../docs/type-system/type-language.md | 91 + .../graphql-php/docs/type-system/unions.md | 39 + .../examples/00-hello-world/README.md | 18 + .../examples/00-hello-world/graphql.php | 69 + .../examples/01-blog/Blog/AppContext.php | 28 + .../examples/01-blog/Blog/Data/Comment.php | 25 + .../examples/01-blog/Blog/Data/DataSource.php | 206 + .../examples/01-blog/Blog/Data/Image.php | 29 + .../examples/01-blog/Blog/Data/Story.php | 22 + .../examples/01-blog/Blog/Data/User.php | 22 + .../01-blog/Blog/Type/CommentType.php | 76 + .../Blog/Type/Enum/ContentFormatEnum.php | 19 + .../Blog/Type/Enum/ImageSizeEnumType.php | 23 + .../01-blog/Blog/Type/Field/HtmlField.php | 52 + .../examples/01-blog/Blog/Type/ImageType.php | 62 + .../examples/01-blog/Blog/Type/NodeType.php | 34 + .../examples/01-blog/Blog/Type/QueryType.php | 97 + .../01-blog/Blog/Type/Scalar/EmailType.php | 70 + .../01-blog/Blog/Type/Scalar/UrlType.php | 63 + .../01-blog/Blog/Type/SearchResultType.php | 31 + .../examples/01-blog/Blog/Type/StoryType.php | 127 + .../examples/01-blog/Blog/Type/UserType.php | 68 + .../examples/01-blog/Blog/Types.php | 209 + .../graphql-php/examples/01-blog/README.md | 120 + .../graphql-php/examples/01-blog/graphql.php | 71 + .../examples/02-shorthand/README.md | 19 + .../examples/02-shorthand/graphql.php | 31 + .../examples/02-shorthand/rootvalue.php | 35 + .../examples/02-shorthand/schema.graphqls | 13 + .../graphql-php/examples/03-server/README.md | 19 + .../examples/03-server/graphql.php | 61 + vendor/webonyx/graphql-php/phpcs.xml.dist | 102 + vendor/webonyx/graphql-php/phpstan.neon.dist | 17 + vendor/webonyx/graphql-php/src/Deferred.php | 65 + .../graphql-php/src/Error/ClientAware.php | 36 + .../webonyx/graphql-php/src/Error/Debug.php | 16 + .../webonyx/graphql-php/src/Error/Error.php | 380 ++ .../graphql-php/src/Error/FormattedError.php | 440 ++ .../src/Error/InvariantViolation.php | 16 + .../graphql-php/src/Error/SyntaxError.php | 25 + .../graphql-php/src/Error/UserError.php | 29 + .../webonyx/graphql-php/src/Error/Warning.php | 111 + .../src/Executor/ExecutionContext.php | 78 + .../src/Executor/ExecutionResult.php | 162 + .../graphql-php/src/Executor/Executor.php | 187 + .../src/Executor/ExecutorImplementation.php | 15 + .../Promise/Adapter/ReactPromiseAdapter.php | 100 + .../Executor/Promise/Adapter/SyncPromise.php | 170 + .../Promise/Adapter/SyncPromiseAdapter.php | 185 + .../src/Executor/Promise/Promise.php | 40 + .../src/Executor/Promise/PromiseAdapter.php | 92 + .../src/Executor/ReferenceExecutor.php | 1363 ++++ .../graphql-php/src/Executor/Values.php | 278 + .../src/Experimental/Executor/Collector.php | 283 + .../Executor/CoroutineContext.php | 57 + .../Executor/CoroutineContextShared.php | 62 + .../Executor/CoroutineExecutor.php | 948 +++ .../src/Experimental/Executor/Runtime.php | 18 + .../src/Experimental/Executor/Strand.php | 35 + vendor/webonyx/graphql-php/src/GraphQL.php | 351 + .../src/Language/AST/ArgumentNode.php | 17 + .../src/Language/AST/BooleanValueNode.php | 14 + .../src/Language/AST/DefinitionNode.php | 14 + .../Language/AST/DirectiveDefinitionNode.php | 23 + .../src/Language/AST/DirectiveNode.php | 17 + .../src/Language/AST/DocumentNode.php | 14 + .../Language/AST/EnumTypeDefinitionNode.php | 23 + .../Language/AST/EnumTypeExtensionNode.php | 20 + .../Language/AST/EnumValueDefinitionNode.php | 20 + .../src/Language/AST/EnumValueNode.php | 14 + .../Language/AST/ExecutableDefinitionNode.php | 14 + .../src/Language/AST/FieldDefinitionNode.php | 26 + .../src/Language/AST/FieldNode.php | 26 + .../src/Language/AST/FloatValueNode.php | 14 + .../Language/AST/FragmentDefinitionNode.php | 31 + .../src/Language/AST/FragmentSpreadNode.php | 17 + .../src/Language/AST/HasSelectionSet.php | 13 + .../src/Language/AST/InlineFragmentNode.php | 20 + .../AST/InputObjectTypeDefinitionNode.php | 23 + .../AST/InputObjectTypeExtensionNode.php | 20 + .../Language/AST/InputValueDefinitionNode.php | 26 + .../src/Language/AST/IntValueNode.php | 14 + .../AST/InterfaceTypeDefinitionNode.php | 23 + .../AST/InterfaceTypeExtensionNode.php | 20 + .../src/Language/AST/ListTypeNode.php | 14 + .../src/Language/AST/ListValueNode.php | 14 + .../graphql-php/src/Language/AST/Location.php | 79 + .../graphql-php/src/Language/AST/NameNode.php | 14 + .../src/Language/AST/NamedTypeNode.php | 14 + .../graphql-php/src/Language/AST/Node.php | 162 + .../graphql-php/src/Language/AST/NodeKind.php | 138 + .../graphql-php/src/Language/AST/NodeList.php | 129 + .../src/Language/AST/NonNullTypeNode.php | 14 + .../src/Language/AST/NullValueNode.php | 11 + .../src/Language/AST/ObjectFieldNode.php | 17 + .../Language/AST/ObjectTypeDefinitionNode.php | 26 + .../Language/AST/ObjectTypeExtensionNode.php | 23 + .../src/Language/AST/ObjectValueNode.php | 14 + .../Language/AST/OperationDefinitionNode.php | 26 + .../AST/OperationTypeDefinitionNode.php | 21 + .../Language/AST/ScalarTypeDefinitionNode.php | 20 + .../Language/AST/ScalarTypeExtensionNode.php | 17 + .../src/Language/AST/SchemaDefinitionNode.php | 17 + .../Language/AST/SchemaTypeExtensionNode.php | 17 + .../src/Language/AST/SelectionNode.php | 12 + .../src/Language/AST/SelectionSetNode.php | 14 + .../src/Language/AST/StringValueNode.php | 17 + .../src/Language/AST/TypeDefinitionNode.php | 17 + .../src/Language/AST/TypeExtensionNode.php | 18 + .../graphql-php/src/Language/AST/TypeNode.php | 14 + .../Language/AST/TypeSystemDefinitionNode.php | 16 + .../Language/AST/UnionTypeDefinitionNode.php | 23 + .../Language/AST/UnionTypeExtensionNode.php | 20 + .../src/Language/AST/ValueNode.php | 20 + .../Language/AST/VariableDefinitionNode.php | 20 + .../src/Language/AST/VariableNode.php | 14 + .../src/Language/DirectiveLocation.php | 65 + .../graphql-php/src/Language/Lexer.php | 804 +++ .../graphql-php/src/Language/Parser.php | 1786 +++++ .../graphql-php/src/Language/Printer.php | 520 ++ .../graphql-php/src/Language/Source.php | 85 + .../src/Language/SourceLocation.php | 53 + .../graphql-php/src/Language/Token.php | 127 + .../graphql-php/src/Language/Visitor.php | 543 ++ .../src/Language/VisitorOperation.php | 17 + vendor/webonyx/graphql-php/src/Schema.php | 22 + .../webonyx/graphql-php/src/Server/Helper.php | 591 ++ .../src/Server/OperationParams.php | 142 + .../graphql-php/src/Server/RequestError.php | 33 + .../graphql-php/src/Server/ServerConfig.php | 336 + .../graphql-php/src/Server/StandardServer.php | 185 + .../src/Type/Definition/AbstractType.php | 24 + .../src/Type/Definition/BooleanType.php | 65 + .../src/Type/Definition/CompositeType.php | 16 + .../src/Type/Definition/CustomScalarType.php | 80 + .../src/Type/Definition/Directive.php | 172 + .../src/Type/Definition/EnumType.php | 222 + .../Type/Definition/EnumValueDefinition.php | 50 + .../src/Type/Definition/FieldArgument.php | 133 + .../src/Type/Definition/FieldDefinition.php | 243 + .../src/Type/Definition/FloatType.php | 85 + .../src/Type/Definition/IDType.php | 90 + .../src/Type/Definition/InputObjectField.php | 108 + .../src/Type/Definition/InputObjectType.php | 114 + .../src/Type/Definition/InputType.php | 23 + .../src/Type/Definition/IntType.php | 112 + .../src/Type/Definition/InterfaceType.php | 138 + .../src/Type/Definition/LeafType.php | 56 + .../src/Type/Definition/ListOfType.php | 36 + .../src/Type/Definition/NamedType.php | 19 + .../src/Type/Definition/NonNull.php | 71 + .../src/Type/Definition/NullableType.php | 20 + .../src/Type/Definition/ObjectType.php | 248 + .../src/Type/Definition/OutputType.php | 19 + .../src/Type/Definition/QueryPlan.php | 242 + .../src/Type/Definition/ResolveInfo.php | 240 + .../src/Type/Definition/ScalarType.php | 51 + .../src/Type/Definition/StringType.php | 97 + .../graphql-php/src/Type/Definition/Type.php | 410 ++ .../src/Type/Definition/UnionType.php | 135 + .../src/Type/Definition/UnmodifiedType.php | 19 + .../src/Type/Definition/WrappingType.php | 15 + .../graphql-php/src/Type/Introspection.php | 819 +++ .../webonyx/graphql-php/src/Type/Schema.php | 525 ++ .../graphql-php/src/Type/SchemaConfig.php | 312 + .../src/Type/SchemaValidationContext.php | 857 +++ .../webonyx/graphql-php/src/Type/TypeKind.php | 17 + vendor/webonyx/graphql-php/src/Utils/AST.php | 613 ++ .../src/Utils/ASTDefinitionBuilder.php | 530 ++ .../graphql-php/src/Utils/BlockString.php | 77 + .../src/Utils/BreakingChangesFinder.php | 923 +++ .../graphql-php/src/Utils/BuildSchema.php | 243 + .../graphql-php/src/Utils/MixedStore.php | 249 + .../webonyx/graphql-php/src/Utils/PairSet.php | 66 + .../graphql-php/src/Utils/SchemaExtender.php | 631 ++ .../graphql-php/src/Utils/SchemaPrinter.php | 489 ++ .../graphql-php/src/Utils/TypeComparators.php | 140 + .../graphql-php/src/Utils/TypeInfo.php | 495 ++ .../webonyx/graphql-php/src/Utils/Utils.php | 648 ++ .../webonyx/graphql-php/src/Utils/Value.php | 320 + .../src/Validator/DocumentValidator.php | 326 + .../Validator/Rules/CustomValidationRule.php | 30 + .../Validator/Rules/DisableIntrospection.php | 57 + .../Validator/Rules/ExecutableDefinitions.php | 52 + .../Validator/Rules/FieldsOnCorrectType.php | 167 + .../Rules/FragmentsOnCompositeTypes.php | 64 + .../Validator/Rules/KnownArgumentNames.php | 109 + .../Rules/KnownArgumentNamesOnDirectives.php | 93 + .../src/Validator/Rules/KnownDirectives.php | 156 + .../Validator/Rules/KnownFragmentNames.php | 40 + .../src/Validator/Rules/KnownTypeNames.php | 72 + .../Rules/LoneAnonymousOperation.php | 58 + .../Validator/Rules/LoneSchemaDefinition.php | 47 + .../src/Validator/Rules/NoFragmentCycles.php | 125 + .../Validator/Rules/NoUndefinedVariables.php | 62 + .../src/Validator/Rules/NoUnusedFragments.php | 69 + .../src/Validator/Rules/NoUnusedVariables.php | 64 + .../Rules/OverlappingFieldsCanBeMerged.php | 900 +++ .../Rules/PossibleFragmentSpreads.php | 160 + .../Rules/ProvidedNonNullArguments.php | 98 + .../ProvidedRequiredArgumentsOnDirectives.php | 110 + .../src/Validator/Rules/QueryComplexity.php | 297 + .../src/Validator/Rules/QueryDepth.php | 118 + .../src/Validator/Rules/QuerySecurityRule.php | 188 + .../src/Validator/Rules/ScalarLeafs.php | 51 + .../Validator/Rules/UniqueArgumentNames.php | 51 + .../Rules/UniqueDirectivesPerLocation.php | 44 + .../Validator/Rules/UniqueFragmentNames.php | 48 + .../Validator/Rules/UniqueInputFieldNames.php | 59 + .../Validator/Rules/UniqueOperationNames.php | 51 + .../Validator/Rules/UniqueVariableNames.php | 45 + .../src/Validator/Rules/ValidationRule.php | 35 + .../Validator/Rules/ValuesOfCorrectType.php | 288 + .../Rules/VariablesAreInputTypes.php | 42 + .../Rules/VariablesDefaultValueAllowed.php | 65 + .../Rules/VariablesInAllowedPosition.php | 112 + .../src/Validator/ValidationContext.php | 297 + 284 files changed, 55166 insertions(+) create mode 100644 vendor/symfony/polyfill-intl-idn/Idn.php create mode 100644 vendor/symfony/polyfill-intl-idn/Info.php create mode 100644 vendor/symfony/polyfill-intl-idn/LICENSE create mode 100644 vendor/symfony/polyfill-intl-idn/README.md create mode 100644 vendor/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php create mode 100644 vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.php create mode 100644 vendor/symfony/polyfill-intl-idn/Resources/unidata/deviation.php create mode 100644 vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php create mode 100644 vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.php create mode 100644 vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php create mode 100644 vendor/symfony/polyfill-intl-idn/Resources/unidata/ignored.php create mode 100644 vendor/symfony/polyfill-intl-idn/Resources/unidata/mapped.php create mode 100644 vendor/symfony/polyfill-intl-idn/Resources/unidata/virama.php create mode 100644 vendor/symfony/polyfill-intl-idn/bootstrap.php create mode 100644 vendor/symfony/polyfill-intl-idn/composer.json create mode 100644 vendor/symfony/polyfill-intl-normalizer/LICENSE create mode 100644 vendor/symfony/polyfill-intl-normalizer/Normalizer.php create mode 100644 vendor/symfony/polyfill-intl-normalizer/README.md create mode 100644 vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php create mode 100644 vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalComposition.php create mode 100644 vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php create mode 100644 vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php create mode 100644 vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php create mode 100644 vendor/symfony/polyfill-intl-normalizer/bootstrap.php create mode 100644 vendor/symfony/polyfill-intl-normalizer/composer.json create mode 100644 vendor/symfony/polyfill-php70/LICENSE create mode 100644 vendor/symfony/polyfill-php70/Php70.php create mode 100644 vendor/symfony/polyfill-php70/README.md create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/AssertionError.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/Error.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/ParseError.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php create mode 100644 vendor/symfony/polyfill-php70/Resources/stubs/TypeError.php create mode 100644 vendor/symfony/polyfill-php70/bootstrap.php create mode 100644 vendor/symfony/polyfill-php70/composer.json create mode 100644 vendor/symfony/polyfill-php72/LICENSE create mode 100644 vendor/symfony/polyfill-php72/Php72.php create mode 100644 vendor/symfony/polyfill-php72/README.md create mode 100644 vendor/symfony/polyfill-php72/bootstrap.php create mode 100644 vendor/symfony/polyfill-php72/composer.json create mode 100644 vendor/webonyx/graphql-php/CHANGELOG.md create mode 100644 vendor/webonyx/graphql-php/LICENSE create mode 100644 vendor/webonyx/graphql-php/README.md create mode 100644 vendor/webonyx/graphql-php/UPGRADE.md create mode 100644 vendor/webonyx/graphql-php/composer.json create mode 100644 vendor/webonyx/graphql-php/docs/best-practices.md create mode 100644 vendor/webonyx/graphql-php/docs/complementary-tools.md create mode 100644 vendor/webonyx/graphql-php/docs/concepts.md create mode 100644 vendor/webonyx/graphql-php/docs/data-fetching.md create mode 100644 vendor/webonyx/graphql-php/docs/error-handling.md create mode 100644 vendor/webonyx/graphql-php/docs/executing-queries.md create mode 100644 vendor/webonyx/graphql-php/docs/getting-started.md create mode 100644 vendor/webonyx/graphql-php/docs/how-it-works.md create mode 100644 vendor/webonyx/graphql-php/docs/index.md create mode 100644 vendor/webonyx/graphql-php/docs/reference.md create mode 100644 vendor/webonyx/graphql-php/docs/security.md create mode 100644 vendor/webonyx/graphql-php/docs/type-system/directives.md create mode 100644 vendor/webonyx/graphql-php/docs/type-system/enum-types.md create mode 100644 vendor/webonyx/graphql-php/docs/type-system/index.md create mode 100644 vendor/webonyx/graphql-php/docs/type-system/input-types.md create mode 100644 vendor/webonyx/graphql-php/docs/type-system/interfaces.md create mode 100644 vendor/webonyx/graphql-php/docs/type-system/lists-and-nonnulls.md create mode 100644 vendor/webonyx/graphql-php/docs/type-system/object-types.md create mode 100644 vendor/webonyx/graphql-php/docs/type-system/scalar-types.md create mode 100644 vendor/webonyx/graphql-php/docs/type-system/schema.md create mode 100644 vendor/webonyx/graphql-php/docs/type-system/type-language.md create mode 100644 vendor/webonyx/graphql-php/docs/type-system/unions.md create mode 100644 vendor/webonyx/graphql-php/examples/00-hello-world/README.md create mode 100644 vendor/webonyx/graphql-php/examples/00-hello-world/graphql.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/AppContext.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/Data/Comment.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/Data/DataSource.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/Data/Image.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/Data/Story.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/Data/User.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/CommentType.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Enum/ContentFormatEnum.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Enum/ImageSizeEnumType.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Field/HtmlField.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/ImageType.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/NodeType.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/QueryType.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Scalar/EmailType.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Scalar/UrlType.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/SearchResultType.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/StoryType.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/UserType.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/Blog/Types.php create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/README.md create mode 100644 vendor/webonyx/graphql-php/examples/01-blog/graphql.php create mode 100644 vendor/webonyx/graphql-php/examples/02-shorthand/README.md create mode 100644 vendor/webonyx/graphql-php/examples/02-shorthand/graphql.php create mode 100644 vendor/webonyx/graphql-php/examples/02-shorthand/rootvalue.php create mode 100644 vendor/webonyx/graphql-php/examples/02-shorthand/schema.graphqls create mode 100644 vendor/webonyx/graphql-php/examples/03-server/README.md create mode 100644 vendor/webonyx/graphql-php/examples/03-server/graphql.php create mode 100644 vendor/webonyx/graphql-php/phpcs.xml.dist create mode 100644 vendor/webonyx/graphql-php/phpstan.neon.dist create mode 100644 vendor/webonyx/graphql-php/src/Deferred.php create mode 100644 vendor/webonyx/graphql-php/src/Error/ClientAware.php create mode 100644 vendor/webonyx/graphql-php/src/Error/Debug.php create mode 100644 vendor/webonyx/graphql-php/src/Error/Error.php create mode 100644 vendor/webonyx/graphql-php/src/Error/FormattedError.php create mode 100644 vendor/webonyx/graphql-php/src/Error/InvariantViolation.php create mode 100644 vendor/webonyx/graphql-php/src/Error/SyntaxError.php create mode 100644 vendor/webonyx/graphql-php/src/Error/UserError.php create mode 100644 vendor/webonyx/graphql-php/src/Error/Warning.php create mode 100644 vendor/webonyx/graphql-php/src/Executor/ExecutionContext.php create mode 100644 vendor/webonyx/graphql-php/src/Executor/ExecutionResult.php create mode 100644 vendor/webonyx/graphql-php/src/Executor/Executor.php create mode 100644 vendor/webonyx/graphql-php/src/Executor/ExecutorImplementation.php create mode 100644 vendor/webonyx/graphql-php/src/Executor/Promise/Adapter/ReactPromiseAdapter.php create mode 100644 vendor/webonyx/graphql-php/src/Executor/Promise/Adapter/SyncPromise.php create mode 100644 vendor/webonyx/graphql-php/src/Executor/Promise/Adapter/SyncPromiseAdapter.php create mode 100644 vendor/webonyx/graphql-php/src/Executor/Promise/Promise.php create mode 100644 vendor/webonyx/graphql-php/src/Executor/Promise/PromiseAdapter.php create mode 100644 vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php create mode 100644 vendor/webonyx/graphql-php/src/Executor/Values.php create mode 100644 vendor/webonyx/graphql-php/src/Experimental/Executor/Collector.php create mode 100644 vendor/webonyx/graphql-php/src/Experimental/Executor/CoroutineContext.php create mode 100644 vendor/webonyx/graphql-php/src/Experimental/Executor/CoroutineContextShared.php create mode 100644 vendor/webonyx/graphql-php/src/Experimental/Executor/CoroutineExecutor.php create mode 100644 vendor/webonyx/graphql-php/src/Experimental/Executor/Runtime.php create mode 100644 vendor/webonyx/graphql-php/src/Experimental/Executor/Strand.php create mode 100644 vendor/webonyx/graphql-php/src/GraphQL.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/ArgumentNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/BooleanValueNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/DefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/DirectiveDefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/DirectiveNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/DocumentNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/EnumTypeDefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/EnumTypeExtensionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/EnumValueDefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/EnumValueNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/ExecutableDefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/FieldDefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/FieldNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/FloatValueNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/FragmentDefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/FragmentSpreadNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/HasSelectionSet.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/InlineFragmentNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/InputObjectTypeDefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/InputObjectTypeExtensionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/InputValueDefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/IntValueNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/InterfaceTypeDefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/InterfaceTypeExtensionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/ListTypeNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/ListValueNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/Location.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/NameNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/NamedTypeNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/Node.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/NodeKind.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/NodeList.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/NonNullTypeNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/NullValueNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/ObjectFieldNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/ObjectTypeDefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/ObjectTypeExtensionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/ObjectValueNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/OperationDefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/OperationTypeDefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/ScalarTypeDefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/ScalarTypeExtensionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/SchemaDefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/SchemaTypeExtensionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/SelectionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/SelectionSetNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/StringValueNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/TypeDefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/TypeExtensionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/TypeNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/TypeSystemDefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/UnionTypeDefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/UnionTypeExtensionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/ValueNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/VariableDefinitionNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/AST/VariableNode.php create mode 100644 vendor/webonyx/graphql-php/src/Language/DirectiveLocation.php create mode 100644 vendor/webonyx/graphql-php/src/Language/Lexer.php create mode 100644 vendor/webonyx/graphql-php/src/Language/Parser.php create mode 100644 vendor/webonyx/graphql-php/src/Language/Printer.php create mode 100644 vendor/webonyx/graphql-php/src/Language/Source.php create mode 100644 vendor/webonyx/graphql-php/src/Language/SourceLocation.php create mode 100644 vendor/webonyx/graphql-php/src/Language/Token.php create mode 100644 vendor/webonyx/graphql-php/src/Language/Visitor.php create mode 100644 vendor/webonyx/graphql-php/src/Language/VisitorOperation.php create mode 100644 vendor/webonyx/graphql-php/src/Schema.php create mode 100644 vendor/webonyx/graphql-php/src/Server/Helper.php create mode 100644 vendor/webonyx/graphql-php/src/Server/OperationParams.php create mode 100644 vendor/webonyx/graphql-php/src/Server/RequestError.php create mode 100644 vendor/webonyx/graphql-php/src/Server/ServerConfig.php create mode 100644 vendor/webonyx/graphql-php/src/Server/StandardServer.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/AbstractType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/BooleanType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/CompositeType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/CustomScalarType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/Directive.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/EnumType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/EnumValueDefinition.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/FieldArgument.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/FieldDefinition.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/FloatType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/IDType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/InputObjectField.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/InputObjectType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/InputType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/IntType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/InterfaceType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/LeafType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/ListOfType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/NamedType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/NonNull.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/NullableType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/ObjectType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/OutputType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/QueryPlan.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/ResolveInfo.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/ScalarType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/StringType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/Type.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/UnionType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/UnmodifiedType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Definition/WrappingType.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Introspection.php create mode 100644 vendor/webonyx/graphql-php/src/Type/Schema.php create mode 100644 vendor/webonyx/graphql-php/src/Type/SchemaConfig.php create mode 100644 vendor/webonyx/graphql-php/src/Type/SchemaValidationContext.php create mode 100644 vendor/webonyx/graphql-php/src/Type/TypeKind.php create mode 100644 vendor/webonyx/graphql-php/src/Utils/AST.php create mode 100644 vendor/webonyx/graphql-php/src/Utils/ASTDefinitionBuilder.php create mode 100644 vendor/webonyx/graphql-php/src/Utils/BlockString.php create mode 100644 vendor/webonyx/graphql-php/src/Utils/BreakingChangesFinder.php create mode 100644 vendor/webonyx/graphql-php/src/Utils/BuildSchema.php create mode 100644 vendor/webonyx/graphql-php/src/Utils/MixedStore.php create mode 100644 vendor/webonyx/graphql-php/src/Utils/PairSet.php create mode 100644 vendor/webonyx/graphql-php/src/Utils/SchemaExtender.php create mode 100644 vendor/webonyx/graphql-php/src/Utils/SchemaPrinter.php create mode 100644 vendor/webonyx/graphql-php/src/Utils/TypeComparators.php create mode 100644 vendor/webonyx/graphql-php/src/Utils/TypeInfo.php create mode 100644 vendor/webonyx/graphql-php/src/Utils/Utils.php create mode 100644 vendor/webonyx/graphql-php/src/Utils/Value.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/DocumentValidator.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/CustomValidationRule.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/DisableIntrospection.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/ExecutableDefinitions.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/FieldsOnCorrectType.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/FragmentsOnCompositeTypes.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/KnownArgumentNames.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/KnownArgumentNamesOnDirectives.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/KnownDirectives.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/KnownFragmentNames.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/KnownTypeNames.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/LoneAnonymousOperation.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/LoneSchemaDefinition.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/NoFragmentCycles.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/NoUndefinedVariables.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/NoUnusedFragments.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/NoUnusedVariables.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/OverlappingFieldsCanBeMerged.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/PossibleFragmentSpreads.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/ProvidedNonNullArguments.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/ProvidedRequiredArgumentsOnDirectives.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/QueryComplexity.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/QueryDepth.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/QuerySecurityRule.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/ScalarLeafs.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/UniqueArgumentNames.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/UniqueDirectivesPerLocation.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/UniqueFragmentNames.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/UniqueInputFieldNames.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/UniqueOperationNames.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/UniqueVariableNames.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/ValidationRule.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/ValuesOfCorrectType.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/VariablesAreInputTypes.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/VariablesDefaultValueAllowed.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/Rules/VariablesInAllowedPosition.php create mode 100644 vendor/webonyx/graphql-php/src/Validator/ValidationContext.php diff --git a/vendor/symfony/polyfill-intl-idn/Idn.php b/vendor/symfony/polyfill-intl-idn/Idn.php new file mode 100644 index 0000000..6720af9 --- /dev/null +++ b/vendor/symfony/polyfill-intl-idn/Idn.php @@ -0,0 +1,921 @@ + and Trevor Rowbotham + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Intl\Idn; + +use Exception; +use Normalizer; +use Symfony\Polyfill\Intl\Idn\Resources\unidata\DisallowedRanges; +use Symfony\Polyfill\Intl\Idn\Resources\unidata\Regex; + +/** + * @see https://www.unicode.org/reports/tr46/ + * + * @internal + */ +final class Idn +{ + const ERROR_EMPTY_LABEL = 1; + const ERROR_LABEL_TOO_LONG = 2; + const ERROR_DOMAIN_NAME_TOO_LONG = 4; + const ERROR_LEADING_HYPHEN = 8; + const ERROR_TRAILING_HYPHEN = 0x10; + const ERROR_HYPHEN_3_4 = 0x20; + const ERROR_LEADING_COMBINING_MARK = 0x40; + const ERROR_DISALLOWED = 0x80; + const ERROR_PUNYCODE = 0x100; + const ERROR_LABEL_HAS_DOT = 0x200; + const ERROR_INVALID_ACE_LABEL = 0x400; + const ERROR_BIDI = 0x800; + const ERROR_CONTEXTJ = 0x1000; + const ERROR_CONTEXTO_PUNCTUATION = 0x2000; + const ERROR_CONTEXTO_DIGITS = 0x4000; + + const INTL_IDNA_VARIANT_2003 = 0; + const INTL_IDNA_VARIANT_UTS46 = 1; + + const MAX_DOMAIN_SIZE = 253; + const MAX_LABEL_SIZE = 63; + + const BASE = 36; + const TMIN = 1; + const TMAX = 26; + const SKEW = 38; + const DAMP = 700; + const INITIAL_BIAS = 72; + const INITIAL_N = 128; + const DELIMITER = '-'; + const MAX_INT = 2147483647; + + /** + * Contains the numeric value of a basic code point (for use in representing integers) in the + * range 0 to BASE-1, or -1 if b is does not represent a value. + * + * @var array + */ + private static $basicToDigit = array( + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, -1, + + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + ); + + /** + * @var array + */ + private static $virama; + + /** + * @var array + */ + private static $mapped; + + /** + * @var array + */ + private static $ignored; + + /** + * @var array + */ + private static $deviation; + + /** + * @var array + */ + private static $disallowed; + + /** + * @var array + */ + private static $disallowed_STD3_mapped; + + /** + * @var array + */ + private static $disallowed_STD3_valid; + + /** + * @var bool + */ + private static $mappingTableLoaded = false; + + /** + * @see https://www.unicode.org/reports/tr46/#ToASCII + * + * @param string $domainName + * @param int $options + * @param int $variant + * @param array $idna_info + * + * @return string|false + */ + public static function idn_to_ascii($domainName, $options = IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = array()) + { + if (\PHP_VERSION_ID >= 70200 && self::INTL_IDNA_VARIANT_2003 === $variant) { + @trigger_error('idn_to_ascii(): INTL_IDNA_VARIANT_2003 is deprecated', E_USER_DEPRECATED); + } + + $options = array( + 'CheckHyphens' => true, + 'CheckBidi' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 !== ($options & \IDNA_CHECK_BIDI), + 'CheckJoiners' => self::INTL_IDNA_VARIANT_UTS46 === $variant && 0 !== ($options & \IDNA_CHECK_CONTEXTJ), + 'UseSTD3ASCIIRules' => 0 !== ($options & \IDNA_USE_STD3_RULES), + 'Transitional_Processing' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 === ($options & \IDNA_NONTRANSITIONAL_TO_ASCII), + 'VerifyDnsLength' => true, + ); + $info = new Info(); + $labels = self::process((string) $domainName, $options, $info); + + foreach ($labels as $i => $label) { + // Only convert labels to punycode that contain non-ASCII code points and only if that + // label does not contain a character from the gen-delims set specified in + // {@link https://ietf.org/rfc/rfc3987.html#section-2.2} + if (1 === preg_match('/[^\x00-\x7F]/', $label)) { + if (false !== strpbrk($label, ':/?#[]@')) { + continue; + } + + try { + $label = 'xn--'.self::punycodeEncode($label); + } catch (Exception $e) { + $info->errors |= self::ERROR_PUNYCODE; + } + + $labels[$i] = $label; + } + } + + if ($options['VerifyDnsLength']) { + self::validateDomainAndLabelLength($labels, $info); + } + + $idna_info = array( + 'result' => implode('.', $labels), + 'isTransitionalDifferent' => $info->transitionalDifferent, + 'errors' => $info->errors, + ); + + return 0 === $info->errors ? $idna_info['result'] : false; + } + + /** + * @see https://www.unicode.org/reports/tr46/#ToUnicode + * + * @param string $domainName + * @param int $options + * @param int $variant + * @param array $idna_info + * + * @return string|false + */ + public static function idn_to_utf8($domainName, $options = IDNA_DEFAULT, $variant = self::INTL_IDNA_VARIANT_UTS46, &$idna_info = array()) + { + if (\PHP_VERSION_ID >= 70200 && self::INTL_IDNA_VARIANT_2003 === $variant) { + @trigger_error('idn_to_utf8(): INTL_IDNA_VARIANT_2003 is deprecated', E_USER_DEPRECATED); + } + + $info = new Info(); + $labels = self::process((string) $domainName, array( + 'CheckHyphens' => true, + 'CheckBidi' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 !== ($options & \IDNA_CHECK_BIDI), + 'CheckJoiners' => self::INTL_IDNA_VARIANT_UTS46 === $variant && 0 !== ($options & \IDNA_CHECK_CONTEXTJ), + 'UseSTD3ASCIIRules' => 0 !== ($options & \IDNA_USE_STD3_RULES), + 'Transitional_Processing' => self::INTL_IDNA_VARIANT_2003 === $variant || 0 === ($options & \IDNA_NONTRANSITIONAL_TO_UNICODE), + ), $info); + $idna_info = array( + 'result' => implode('.', $labels), + 'isTransitionalDifferent' => $info->transitionalDifferent, + 'errors' => $info->errors, + ); + + return 0 === $info->errors ? $idna_info['result'] : false; + } + + /** + * @param string $label + * + * @return bool + */ + private static function isValidContextJ(array $codePoints, $label) + { + if (!isset(self::$virama)) { + self::$virama = require __DIR__.\DIRECTORY_SEPARATOR.'Resources'.\DIRECTORY_SEPARATOR.'unidata'.\DIRECTORY_SEPARATOR.'virama.php'; + } + + $offset = 0; + + foreach ($codePoints as $i => $codePoint) { + if (0x200C !== $codePoint && 0x200D !== $codePoint) { + continue; + } + + if (!isset($codePoints[$i - 1])) { + return false; + } + + // If Canonical_Combining_Class(Before(cp)) .eq. Virama Then True; + if (isset(self::$virama[$codePoints[$i - 1]])) { + continue; + } + + // If RegExpMatch((Joining_Type:{L,D})(Joining_Type:T)*\u200C(Joining_Type:T)*(Joining_Type:{R,D})) Then + // True; + // Generated RegExp = ([Joining_Type:{L,D}][Joining_Type:T]*\u200C[Joining_Type:T]*)[Joining_Type:{R,D}] + if (0x200C === $codePoint && 1 === preg_match(Regex::ZWNJ, $label, $matches, PREG_OFFSET_CAPTURE, $offset)) { + $offset += \strlen($matches[1][0]); + + continue; + } + + return false; + } + + return true; + } + + /** + * @see https://www.unicode.org/reports/tr46/#ProcessingStepMap + * + * @param string $input + * @param array $options + * + * @return string + */ + private static function mapCodePoints($input, array $options, Info $info) + { + $str = ''; + $useSTD3ASCIIRules = $options['UseSTD3ASCIIRules']; + $transitional = $options['Transitional_Processing']; + + foreach (self::utf8Decode($input) as $codePoint) { + $data = self::lookupCodePointStatus($codePoint, $useSTD3ASCIIRules); + + switch ($data['status']) { + case 'disallowed': + $info->errors |= self::ERROR_DISALLOWED; + + // no break. + + case 'valid': + $str .= mb_chr($codePoint, 'utf-8'); + + break; + + case 'ignored': + // Do nothing. + break; + + case 'mapped': + $str .= $data['mapping']; + + break; + + case 'deviation': + $info->transitionalDifferent = true; + $str .= ($transitional ? $data['mapping'] : mb_chr($codePoint, 'utf-8')); + + break; + } + } + + return $str; + } + + /** + * @see https://www.unicode.org/reports/tr46/#Processing + * + * @param string $domain + * @param array $options + * + * @return array + */ + private static function process($domain, array $options, Info $info) + { + // If VerifyDnsLength is not set, we are doing ToUnicode otherwise we are doing ToASCII and + // we need to respect the VerifyDnsLength option. + $checkForEmptyLabels = !isset($options['VerifyDnsLength']) || $options['VerifyDnsLength']; + + if ($checkForEmptyLabels && '' === $domain) { + $info->errors |= self::ERROR_EMPTY_LABEL; + + return array($domain); + } + + // Step 1. Map each code point in the domain name string + $domain = self::mapCodePoints($domain, $options, $info); + + // Step 2. Normalize the domain name string to Unicode Normalization Form C. + if (!Normalizer::isNormalized($domain, Normalizer::FORM_C)) { + $domain = Normalizer::normalize($domain, Normalizer::FORM_C); + } + + // Step 3. Break the string into labels at U+002E (.) FULL STOP. + $labels = explode('.', $domain); + $lastLabelIndex = \count($labels) - 1; + + // Step 4. Convert and validate each label in the domain name string. + foreach ($labels as $i => $label) { + $validationOptions = $options; + + if ('xn--' === substr($label, 0, 4)) { + try { + $label = self::punycodeDecode(substr($label, 4)); + } catch (Exception $e) { + $info->errors |= self::ERROR_PUNYCODE; + + continue; + } + + $validationOptions['Transitional_Processing'] = false; + $labels[$i] = $label; + } + + self::validateLabel($label, $info, $validationOptions, $i > 0 && $i === $lastLabelIndex); + } + + if ($info->bidiDomain && !$info->validBidiDomain) { + $info->errors |= self::ERROR_BIDI; + } + + // Any input domain name string that does not record an error has been successfully + // processed according to this specification. Conversely, if an input domain_name string + // causes an error, then the processing of the input domain_name string fails. Determining + // what to do with error input is up to the caller, and not in the scope of this document. + return $labels; + } + + /** + * @see https://tools.ietf.org/html/rfc5893#section-2 + * + * @param string $label + */ + private static function validateBidiLabel($label, Info $info) + { + if (1 === preg_match(Regex::RTL_LABEL, $label)) { + $info->bidiDomain = true; + + // Step 1. The first character must be a character with Bidi property L, R, or AL. + // If it has the R or AL property, it is an RTL label + if (1 !== preg_match(Regex::BIDI_STEP_1_RTL, $label)) { + $info->validBidiDomain = false; + + return; + } + + // Step 2. In an RTL label, only characters with the Bidi properties R, AL, AN, EN, ES, + // CS, ET, ON, BN, or NSM are allowed. + if (1 === preg_match(Regex::BIDI_STEP_2, $label)) { + $info->validBidiDomain = false; + + return; + } + + // Step 3. In an RTL label, the end of the label must be a character with Bidi property + // R, AL, EN, or AN, followed by zero or more characters with Bidi property NSM. + if (1 !== preg_match(Regex::BIDI_STEP_3, $label)) { + $info->validBidiDomain = false; + + return; + } + + // Step 4. In an RTL label, if an EN is present, no AN may be present, and vice versa. + if (1 === preg_match(Regex::BIDI_STEP_4_AN, $label) && 1 === preg_match(Regex::BIDI_STEP_4_EN, $label)) { + $info->validBidiDomain = false; + + return; + } + + return; + } + + // We are a LTR label + // Step 1. The first character must be a character with Bidi property L, R, or AL. + // If it has the L property, it is an LTR label. + if (1 !== preg_match(Regex::BIDI_STEP_1_LTR, $label)) { + $info->validBidiDomain = false; + + return; + } + + // Step 5. In an LTR label, only characters with the Bidi properties L, EN, + // ES, CS, ET, ON, BN, or NSM are allowed. + if (1 === preg_match(Regex::BIDI_STEP_5, $label)) { + $info->validBidiDomain = false; + + return; + } + + // Step 6.In an LTR label, the end of the label must be a character with Bidi property L or + // EN, followed by zero or more characters with Bidi property NSM. + if (1 !== preg_match(Regex::BIDI_STEP_6, $label)) { + $info->validBidiDomain = false; + + return; + } + } + + /** + * @param array $labels + */ + private static function validateDomainAndLabelLength(array $labels, Info $info) + { + $maxDomainSize = self::MAX_DOMAIN_SIZE; + $length = \count($labels); + + // Number of "." delimiters. + $domainLength = $length - 1; + + // If the last label is empty and it is not the first label, then it is the root label. + // Increase the max size by 1, making it 254, to account for the root label's "." + // delimiter. This also means we don't need to check the last label's length for being too + // long. + if ($length > 1 && '' === $labels[$length - 1]) { + ++$maxDomainSize; + --$length; + } + + for ($i = 0; $i < $length; ++$i) { + $bytes = \strlen($labels[$i]); + $domainLength += $bytes; + + if ($bytes > self::MAX_LABEL_SIZE) { + $info->errors |= self::ERROR_LABEL_TOO_LONG; + } + } + + if ($domainLength > $maxDomainSize) { + $info->errors |= self::ERROR_DOMAIN_NAME_TOO_LONG; + } + } + + /** + * @see https://www.unicode.org/reports/tr46/#Validity_Criteria + * + * @param string $label + * @param array $options + * @param bool $canBeEmpty + */ + private static function validateLabel($label, Info $info, array $options, $canBeEmpty) + { + if ('' === $label) { + if (!$canBeEmpty && (!isset($options['VerifyDnsLength']) || $options['VerifyDnsLength'])) { + $info->errors |= self::ERROR_EMPTY_LABEL; + } + + return; + } + + // Step 1. The label must be in Unicode Normalization Form C. + if (!Normalizer::isNormalized($label, Normalizer::FORM_C)) { + $info->errors |= self::ERROR_INVALID_ACE_LABEL; + } + + $codePoints = self::utf8Decode($label); + + if ($options['CheckHyphens']) { + // Step 2. If CheckHyphens, the label must not contain a U+002D HYPHEN-MINUS character + // in both the thrid and fourth positions. + if (isset($codePoints[2], $codePoints[3]) && 0x002D === $codePoints[2] && 0x002D === $codePoints[3]) { + $info->errors |= self::ERROR_HYPHEN_3_4; + } + + // Step 3. If CheckHyphens, the label must neither begin nor end with a U+002D + // HYPHEN-MINUS character. + if ('-' === substr($label, 0, 1)) { + $info->errors |= self::ERROR_LEADING_HYPHEN; + } + + if ('-' === substr($label, -1, 1)) { + $info->errors |= self::ERROR_TRAILING_HYPHEN; + } + } + + // Step 4. The label must not contain a U+002E (.) FULL STOP. + if (false !== strpos($label, '.')) { + $info->errors |= self::ERROR_LABEL_HAS_DOT; + } + + // Step 5. The label must not begin with a combining mark, that is: General_Category=Mark. + if (1 === preg_match(Regex::COMBINING_MARK, $label)) { + $info->errors |= self::ERROR_LEADING_COMBINING_MARK; + } + + // Step 6. Each code point in the label must only have certain status values according to + // Section 5, IDNA Mapping Table: + $transitional = $options['Transitional_Processing']; + $useSTD3ASCIIRules = $options['UseSTD3ASCIIRules']; + + foreach ($codePoints as $codePoint) { + $data = self::lookupCodePointStatus($codePoint, $useSTD3ASCIIRules); + $status = $data['status']; + + if ('valid' === $status || (!$transitional && 'deviation' === $status)) { + continue; + } + + $info->errors |= self::ERROR_DISALLOWED; + + break; + } + + // Step 7. If CheckJoiners, the label must satisify the ContextJ rules from Appendix A, in + // The Unicode Code Points and Internationalized Domain Names for Applications (IDNA) + // [IDNA2008]. + if ($options['CheckJoiners'] && !self::isValidContextJ($codePoints, $label)) { + $info->errors |= self::ERROR_CONTEXTJ; + } + + // Step 8. If CheckBidi, and if the domain name is a Bidi domain name, then the label must + // satisfy all six of the numbered conditions in [IDNA2008] RFC 5893, Section 2. + if ($options['CheckBidi'] && (!$info->bidiDomain || $info->validBidiDomain)) { + self::validateBidiLabel($label, $info); + } + } + + /** + * @see https://tools.ietf.org/html/rfc3492#section-6.2 + * + * @param string $input + * + * @return string + */ + private static function punycodeDecode($input) + { + $n = self::INITIAL_N; + $out = 0; + $i = 0; + $bias = self::INITIAL_BIAS; + $lastDelimIndex = strrpos($input, self::DELIMITER); + $b = false === $lastDelimIndex ? 0 : $lastDelimIndex; + $inputLength = \strlen($input); + $output = array(); + $bytes = array_map('ord', str_split($input)); + + for ($j = 0; $j < $b; ++$j) { + if ($bytes[$j] > 0x7F) { + throw new Exception('Invalid input'); + } + + $output[$out++] = $input[$j]; + } + + if ($b > 0) { + ++$b; + } + + for ($in = $b; $in < $inputLength; ++$out) { + $oldi = $i; + $w = 1; + + for ($k = self::BASE; /* no condition */; $k += self::BASE) { + if ($in >= $inputLength) { + throw new Exception('Invalid input'); + } + + $digit = self::$basicToDigit[$bytes[$in++] & 0xFF]; + + if ($digit < 0) { + throw new Exception('Invalid input'); + } + + if ($digit > intdiv(self::MAX_INT - $i, $w)) { + throw new Exception('Integer overflow'); + } + + $i += $digit * $w; + + if ($k <= $bias) { + $t = self::TMIN; + } elseif ($k >= $bias + self::TMAX) { + $t = self::TMAX; + } else { + $t = $k - $bias; + } + + if ($digit < $t) { + break; + } + + $baseMinusT = self::BASE - $t; + + if ($w > intdiv(self::MAX_INT, $baseMinusT)) { + throw new Exception('Integer overflow'); + } + + $w *= $baseMinusT; + } + + $outPlusOne = $out + 1; + $bias = self::adaptBias($i - $oldi, $outPlusOne, 0 === $oldi); + + if (intdiv($i, $outPlusOne) > self::MAX_INT - $n) { + throw new Exception('Integer overflow'); + } + + $n += intdiv($i, $outPlusOne); + $i %= $outPlusOne; + array_splice($output, $i++, 0, array(mb_chr($n, 'utf-8'))); + } + + return implode('', $output); + } + + /** + * @see https://tools.ietf.org/html/rfc3492#section-6.3 + * + * @param string $input + * + * @return string + */ + private static function punycodeEncode($input) + { + $n = self::INITIAL_N; + $delta = 0; + $out = 0; + $bias = self::INITIAL_BIAS; + $inputLength = 0; + $output = ''; + $iter = self::utf8Decode($input); + + foreach ($iter as $codePoint) { + ++$inputLength; + + if ($codePoint < 0x80) { + $output .= \chr($codePoint); + ++$out; + } + } + + $h = $out; + $b = $out; + + if ($b > 0) { + $output .= self::DELIMITER; + ++$out; + } + + while ($h < $inputLength) { + $m = self::MAX_INT; + + foreach ($iter as $codePoint) { + if ($codePoint >= $n && $codePoint < $m) { + $m = $codePoint; + } + } + + if ($m - $n > intdiv(self::MAX_INT - $delta, $h + 1)) { + throw new Exception('Integer overflow'); + } + + $delta += ($m - $n) * ($h + 1); + $n = $m; + + foreach ($iter as $codePoint) { + if ($codePoint < $n && 0 === ++$delta) { + throw new Exception('Integer overflow'); + } elseif ($codePoint === $n) { + $q = $delta; + + for ($k = self::BASE; /* no condition */; $k += self::BASE) { + if ($k <= $bias) { + $t = self::TMIN; + } elseif ($k >= $bias + self::TMAX) { + $t = self::TMAX; + } else { + $t = $k - $bias; + } + + if ($q < $t) { + break; + } + + $qMinusT = $q - $t; + $baseMinusT = self::BASE - $t; + $output .= self::encodeDigit($t + ($qMinusT) % ($baseMinusT), false); + ++$out; + $q = intdiv($qMinusT, $baseMinusT); + } + + $output .= self::encodeDigit($q, false); + ++$out; + $bias = self::adaptBias($delta, $h + 1, $h === $b); + $delta = 0; + ++$h; + } + } + + ++$delta; + ++$n; + } + + return $output; + } + + /** + * @see https://tools.ietf.org/html/rfc3492#section-6.1 + * + * @param int $delta + * @param int $numPoints + * @param bool $firstTime + * + * @return int + */ + private static function adaptBias($delta, $numPoints, $firstTime) + { + // xxx >> 1 is a faster way of doing intdiv(xxx, 2) + $delta = $firstTime ? intdiv($delta, self::DAMP) : $delta >> 1; + $delta += intdiv($delta, $numPoints); + $k = 0; + + while ($delta > ((self::BASE - self::TMIN) * self::TMAX) >> 1) { + $delta = intdiv($delta, self::BASE - self::TMIN); + $k += self::BASE; + } + + return $k + intdiv((self::BASE - self::TMIN + 1) * $delta, $delta + self::SKEW); + } + + /** + * @param int $d + * @param bool $flag + * + * @return string + */ + private static function encodeDigit($d, $flag) + { + return \chr($d + 22 + 75 * ($d < 26 ? 1 : 0) - (($flag ? 1 : 0) << 5)); + } + + /** + * Takes a UTF-8 encoded string and converts it into a series of integer code points. Any + * invalid byte sequences will be replaced by a U+FFFD replacement code point. + * + * @see https://encoding.spec.whatwg.org/#utf-8-decoder + * + * @param string $input + * + * @return array + */ + private static function utf8Decode($input) + { + $bytesSeen = 0; + $bytesNeeded = 0; + $lowerBoundary = 0x80; + $upperBoundary = 0xBF; + $codePoint = 0; + $codePoints = array(); + $length = \strlen($input); + + for ($i = 0; $i < $length; ++$i) { + $byte = \ord($input[$i]); + + if (0 === $bytesNeeded) { + if ($byte >= 0x00 && $byte <= 0x7F) { + $codePoints[] = $byte; + + continue; + } + + if ($byte >= 0xC2 && $byte <= 0xDF) { + $bytesNeeded = 1; + $codePoint = $byte & 0x1F; + } elseif ($byte >= 0xE0 && $byte <= 0xEF) { + if (0xE0 === $byte) { + $lowerBoundary = 0xA0; + } elseif (0xED === $byte) { + $upperBoundary = 0x9F; + } + + $bytesNeeded = 2; + $codePoint = $byte & 0xF; + } elseif ($byte >= 0xF0 && $byte <= 0xF4) { + if (0xF0 === $byte) { + $lowerBoundary = 0x90; + } elseif (0xF4 === $byte) { + $upperBoundary = 0x8F; + } + + $bytesNeeded = 3; + $codePoint = $byte & 0x7; + } else { + $codePoints[] = 0xFFFD; + } + + continue; + } + + if ($byte < $lowerBoundary || $byte > $upperBoundary) { + $codePoint = 0; + $bytesNeeded = 0; + $bytesSeen = 0; + $lowerBoundary = 0x80; + $upperBoundary = 0xBF; + --$i; + $codePoints[] = 0xFFFD; + + continue; + } + + $lowerBoundary = 0x80; + $upperBoundary = 0xBF; + $codePoint = ($codePoint << 6) | ($byte & 0x3F); + + if (++$bytesSeen !== $bytesNeeded) { + continue; + } + + $codePoints[] = $codePoint; + $codePoint = 0; + $bytesNeeded = 0; + $bytesSeen = 0; + } + + // String unexpectedly ended, so append a U+FFFD code point. + if (0 !== $bytesNeeded) { + $codePoints[] = 0xFFFD; + } + + return $codePoints; + } + + /** + * @param int $codePoint + * @param bool $useSTD3ASCIIRules + * + * @return array{status: string, mapping?: string} + */ + private static function lookupCodePointStatus($codePoint, $useSTD3ASCIIRules) + { + if (!self::$mappingTableLoaded) { + self::$mappingTableLoaded = true; + self::$mapped = require __DIR__.'/Resources/unidata/mapped.php'; + self::$ignored = require __DIR__.'/Resources/unidata/ignored.php'; + self::$deviation = require __DIR__.'/Resources/unidata/deviation.php'; + self::$disallowed = require __DIR__.'/Resources/unidata/disallowed.php'; + self::$disallowed_STD3_mapped = require __DIR__.'/Resources/unidata/disallowed_STD3_mapped.php'; + self::$disallowed_STD3_valid = require __DIR__.'/Resources/unidata/disallowed_STD3_valid.php'; + } + + if (isset(self::$mapped[$codePoint])) { + return array('status' => 'mapped', 'mapping' => self::$mapped[$codePoint]); + } + + if (isset(self::$ignored[$codePoint])) { + return array('status' => 'ignored'); + } + + if (isset(self::$deviation[$codePoint])) { + return array('status' => 'deviation', 'mapping' => self::$deviation[$codePoint]); + } + + if (isset(self::$disallowed[$codePoint]) || DisallowedRanges::inRange($codePoint)) { + return array('status' => 'disallowed'); + } + + $isDisallowedMapped = isset(self::$disallowed_STD3_mapped[$codePoint]); + + if ($isDisallowedMapped || isset(self::$disallowed_STD3_valid[$codePoint])) { + $status = 'disallowed'; + + if (!$useSTD3ASCIIRules) { + $status = $isDisallowedMapped ? 'mapped' : 'valid'; + } + + if ($isDisallowedMapped) { + return array('status' => $status, 'mapping' => self::$disallowed_STD3_mapped[$codePoint]); + } + + return array('status' => $status); + } + + return array('status' => 'valid'); + } +} diff --git a/vendor/symfony/polyfill-intl-idn/Info.php b/vendor/symfony/polyfill-intl-idn/Info.php new file mode 100644 index 0000000..25c3582 --- /dev/null +++ b/vendor/symfony/polyfill-intl-idn/Info.php @@ -0,0 +1,23 @@ + and Trevor Rowbotham + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Intl\Idn; + +/** + * @internal + */ +class Info +{ + public $bidiDomain = false; + public $errors = 0; + public $validBidiDomain = true; + public $transitionalDifferent = false; +} diff --git a/vendor/symfony/polyfill-intl-idn/LICENSE b/vendor/symfony/polyfill-intl-idn/LICENSE new file mode 100644 index 0000000..03c5e25 --- /dev/null +++ b/vendor/symfony/polyfill-intl-idn/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-2019 Fabien Potencier and Trevor Rowbotham + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/polyfill-intl-idn/README.md b/vendor/symfony/polyfill-intl-idn/README.md new file mode 100644 index 0000000..2e75f2e --- /dev/null +++ b/vendor/symfony/polyfill-intl-idn/README.md @@ -0,0 +1,12 @@ +Symfony Polyfill / Intl: Idn +============================ + +This component provides [`idn_to_ascii`](https://php.net/idn-to-ascii) and [`idn_to_utf8`](https://php.net/idn-to-utf8) functions to users who run php versions without the [Intl](https://php.net/intl) extension. + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php b/vendor/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php new file mode 100644 index 0000000..5bb70e4 --- /dev/null +++ b/vendor/symfony/polyfill-intl-idn/Resources/unidata/DisallowedRanges.php @@ -0,0 +1,375 @@ += 128 && $codePoint <= 159) { + return true; + } + + if ($codePoint >= 2155 && $codePoint <= 2207) { + return true; + } + + if ($codePoint >= 3676 && $codePoint <= 3712) { + return true; + } + + if ($codePoint >= 3808 && $codePoint <= 3839) { + return true; + } + + if ($codePoint >= 4059 && $codePoint <= 4095) { + return true; + } + + if ($codePoint >= 4256 && $codePoint <= 4293) { + return true; + } + + if ($codePoint >= 6849 && $codePoint <= 6911) { + return true; + } + + if ($codePoint >= 11859 && $codePoint <= 11903) { + return true; + } + + if ($codePoint >= 42955 && $codePoint <= 42996) { + return true; + } + + if ($codePoint >= 55296 && $codePoint <= 57343) { + return true; + } + + if ($codePoint >= 57344 && $codePoint <= 63743) { + return true; + } + + if ($codePoint >= 64218 && $codePoint <= 64255) { + return true; + } + + if ($codePoint >= 64976 && $codePoint <= 65007) { + return true; + } + + if ($codePoint >= 65630 && $codePoint <= 65663) { + return true; + } + + if ($codePoint >= 65953 && $codePoint <= 65999) { + return true; + } + + if ($codePoint >= 66046 && $codePoint <= 66175) { + return true; + } + + if ($codePoint >= 66518 && $codePoint <= 66559) { + return true; + } + + if ($codePoint >= 66928 && $codePoint <= 67071) { + return true; + } + + if ($codePoint >= 67432 && $codePoint <= 67583) { + return true; + } + + if ($codePoint >= 67760 && $codePoint <= 67807) { + return true; + } + + if ($codePoint >= 67904 && $codePoint <= 67967) { + return true; + } + + if ($codePoint >= 68256 && $codePoint <= 68287) { + return true; + } + + if ($codePoint >= 68528 && $codePoint <= 68607) { + return true; + } + + if ($codePoint >= 68681 && $codePoint <= 68735) { + return true; + } + + if ($codePoint >= 68922 && $codePoint <= 69215) { + return true; + } + + if ($codePoint >= 69298 && $codePoint <= 69375) { + return true; + } + + if ($codePoint >= 69466 && $codePoint <= 69551) { + return true; + } + + if ($codePoint >= 70207 && $codePoint <= 70271) { + return true; + } + + if ($codePoint >= 70517 && $codePoint <= 70655) { + return true; + } + + if ($codePoint >= 70874 && $codePoint <= 71039) { + return true; + } + + if ($codePoint >= 71134 && $codePoint <= 71167) { + return true; + } + + if ($codePoint >= 71370 && $codePoint <= 71423) { + return true; + } + + if ($codePoint >= 71488 && $codePoint <= 71679) { + return true; + } + + if ($codePoint >= 71740 && $codePoint <= 71839) { + return true; + } + + if ($codePoint >= 72026 && $codePoint <= 72095) { + return true; + } + + if ($codePoint >= 72441 && $codePoint <= 72703) { + return true; + } + + if ($codePoint >= 72887 && $codePoint <= 72959) { + return true; + } + + if ($codePoint >= 73130 && $codePoint <= 73439) { + return true; + } + + if ($codePoint >= 73465 && $codePoint <= 73647) { + return true; + } + + if ($codePoint >= 74650 && $codePoint <= 74751) { + return true; + } + + if ($codePoint >= 75076 && $codePoint <= 77823) { + return true; + } + + if ($codePoint >= 78905 && $codePoint <= 82943) { + return true; + } + + if ($codePoint >= 83527 && $codePoint <= 92159) { + return true; + } + + if ($codePoint >= 92784 && $codePoint <= 92879) { + return true; + } + + if ($codePoint >= 93072 && $codePoint <= 93759) { + return true; + } + + if ($codePoint >= 93851 && $codePoint <= 93951) { + return true; + } + + if ($codePoint >= 94112 && $codePoint <= 94175) { + return true; + } + + if ($codePoint >= 101590 && $codePoint <= 101631) { + return true; + } + + if ($codePoint >= 101641 && $codePoint <= 110591) { + return true; + } + + if ($codePoint >= 110879 && $codePoint <= 110927) { + return true; + } + + if ($codePoint >= 111356 && $codePoint <= 113663) { + return true; + } + + if ($codePoint >= 113828 && $codePoint <= 118783) { + return true; + } + + if ($codePoint >= 119366 && $codePoint <= 119519) { + return true; + } + + if ($codePoint >= 119673 && $codePoint <= 119807) { + return true; + } + + if ($codePoint >= 121520 && $codePoint <= 122879) { + return true; + } + + if ($codePoint >= 122923 && $codePoint <= 123135) { + return true; + } + + if ($codePoint >= 123216 && $codePoint <= 123583) { + return true; + } + + if ($codePoint >= 123648 && $codePoint <= 124927) { + return true; + } + + if ($codePoint >= 125143 && $codePoint <= 125183) { + return true; + } + + if ($codePoint >= 125280 && $codePoint <= 126064) { + return true; + } + + if ($codePoint >= 126133 && $codePoint <= 126208) { + return true; + } + + if ($codePoint >= 126270 && $codePoint <= 126463) { + return true; + } + + if ($codePoint >= 126652 && $codePoint <= 126703) { + return true; + } + + if ($codePoint >= 126706 && $codePoint <= 126975) { + return true; + } + + if ($codePoint >= 127406 && $codePoint <= 127461) { + return true; + } + + if ($codePoint >= 127590 && $codePoint <= 127743) { + return true; + } + + if ($codePoint >= 129202 && $codePoint <= 129279) { + return true; + } + + if ($codePoint >= 129751 && $codePoint <= 129791) { + return true; + } + + if ($codePoint >= 129995 && $codePoint <= 130031) { + return true; + } + + if ($codePoint >= 130042 && $codePoint <= 131069) { + return true; + } + + if ($codePoint >= 173790 && $codePoint <= 173823) { + return true; + } + + if ($codePoint >= 191457 && $codePoint <= 194559) { + return true; + } + + if ($codePoint >= 195102 && $codePoint <= 196605) { + return true; + } + + if ($codePoint >= 201547 && $codePoint <= 262141) { + return true; + } + + if ($codePoint >= 262144 && $codePoint <= 327677) { + return true; + } + + if ($codePoint >= 327680 && $codePoint <= 393213) { + return true; + } + + if ($codePoint >= 393216 && $codePoint <= 458749) { + return true; + } + + if ($codePoint >= 458752 && $codePoint <= 524285) { + return true; + } + + if ($codePoint >= 524288 && $codePoint <= 589821) { + return true; + } + + if ($codePoint >= 589824 && $codePoint <= 655357) { + return true; + } + + if ($codePoint >= 655360 && $codePoint <= 720893) { + return true; + } + + if ($codePoint >= 720896 && $codePoint <= 786429) { + return true; + } + + if ($codePoint >= 786432 && $codePoint <= 851965) { + return true; + } + + if ($codePoint >= 851968 && $codePoint <= 917501) { + return true; + } + + if ($codePoint >= 917536 && $codePoint <= 917631) { + return true; + } + + if ($codePoint >= 917632 && $codePoint <= 917759) { + return true; + } + + if ($codePoint >= 918000 && $codePoint <= 983037) { + return true; + } + + if ($codePoint >= 983040 && $codePoint <= 1048573) { + return true; + } + + if ($codePoint >= 1048576 && $codePoint <= 1114109) { + return true; + } + + return false; + } +} diff --git a/vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.php b/vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.php new file mode 100644 index 0000000..5c1c51d --- /dev/null +++ b/vendor/symfony/polyfill-intl-idn/Resources/unidata/Regex.php @@ -0,0 +1,24 @@ + 'ss', + 962 => 'σ', + 8204 => '', + 8205 => '', +); diff --git a/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php b/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php new file mode 100644 index 0000000..25a5f56 --- /dev/null +++ b/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed.php @@ -0,0 +1,2638 @@ + true, + 889 => true, + 896 => true, + 897 => true, + 898 => true, + 899 => true, + 907 => true, + 909 => true, + 930 => true, + 1216 => true, + 1328 => true, + 1367 => true, + 1368 => true, + 1419 => true, + 1420 => true, + 1424 => true, + 1480 => true, + 1481 => true, + 1482 => true, + 1483 => true, + 1484 => true, + 1485 => true, + 1486 => true, + 1487 => true, + 1515 => true, + 1516 => true, + 1517 => true, + 1518 => true, + 1525 => true, + 1526 => true, + 1527 => true, + 1528 => true, + 1529 => true, + 1530 => true, + 1531 => true, + 1532 => true, + 1533 => true, + 1534 => true, + 1535 => true, + 1536 => true, + 1537 => true, + 1538 => true, + 1539 => true, + 1540 => true, + 1541 => true, + 1564 => true, + 1565 => true, + 1757 => true, + 1806 => true, + 1807 => true, + 1867 => true, + 1868 => true, + 1970 => true, + 1971 => true, + 1972 => true, + 1973 => true, + 1974 => true, + 1975 => true, + 1976 => true, + 1977 => true, + 1978 => true, + 1979 => true, + 1980 => true, + 1981 => true, + 1982 => true, + 1983 => true, + 2043 => true, + 2044 => true, + 2094 => true, + 2095 => true, + 2111 => true, + 2140 => true, + 2141 => true, + 2143 => true, + 2229 => true, + 2248 => true, + 2249 => true, + 2250 => true, + 2251 => true, + 2252 => true, + 2253 => true, + 2254 => true, + 2255 => true, + 2256 => true, + 2257 => true, + 2258 => true, + 2274 => true, + 2436 => true, + 2445 => true, + 2446 => true, + 2449 => true, + 2450 => true, + 2473 => true, + 2481 => true, + 2483 => true, + 2484 => true, + 2485 => true, + 2490 => true, + 2491 => true, + 2501 => true, + 2502 => true, + 2505 => true, + 2506 => true, + 2511 => true, + 2512 => true, + 2513 => true, + 2514 => true, + 2515 => true, + 2516 => true, + 2517 => true, + 2518 => true, + 2520 => true, + 2521 => true, + 2522 => true, + 2523 => true, + 2526 => true, + 2532 => true, + 2533 => true, + 2559 => true, + 2560 => true, + 2564 => true, + 2571 => true, + 2572 => true, + 2573 => true, + 2574 => true, + 2577 => true, + 2578 => true, + 2601 => true, + 2609 => true, + 2612 => true, + 2615 => true, + 2618 => true, + 2619 => true, + 2621 => true, + 2627 => true, + 2628 => true, + 2629 => true, + 2630 => true, + 2633 => true, + 2634 => true, + 2638 => true, + 2639 => true, + 2640 => true, + 2642 => true, + 2643 => true, + 2644 => true, + 2645 => true, + 2646 => true, + 2647 => true, + 2648 => true, + 2653 => true, + 2655 => true, + 2656 => true, + 2657 => true, + 2658 => true, + 2659 => true, + 2660 => true, + 2661 => true, + 2679 => true, + 2680 => true, + 2681 => true, + 2682 => true, + 2683 => true, + 2684 => true, + 2685 => true, + 2686 => true, + 2687 => true, + 2688 => true, + 2692 => true, + 2702 => true, + 2706 => true, + 2729 => true, + 2737 => true, + 2740 => true, + 2746 => true, + 2747 => true, + 2758 => true, + 2762 => true, + 2766 => true, + 2767 => true, + 2769 => true, + 2770 => true, + 2771 => true, + 2772 => true, + 2773 => true, + 2774 => true, + 2775 => true, + 2776 => true, + 2777 => true, + 2778 => true, + 2779 => true, + 2780 => true, + 2781 => true, + 2782 => true, + 2783 => true, + 2788 => true, + 2789 => true, + 2802 => true, + 2803 => true, + 2804 => true, + 2805 => true, + 2806 => true, + 2807 => true, + 2808 => true, + 2816 => true, + 2820 => true, + 2829 => true, + 2830 => true, + 2833 => true, + 2834 => true, + 2857 => true, + 2865 => true, + 2868 => true, + 2874 => true, + 2875 => true, + 2885 => true, + 2886 => true, + 2889 => true, + 2890 => true, + 2894 => true, + 2895 => true, + 2896 => true, + 2897 => true, + 2898 => true, + 2899 => true, + 2900 => true, + 2904 => true, + 2905 => true, + 2906 => true, + 2907 => true, + 2910 => true, + 2916 => true, + 2917 => true, + 2936 => true, + 2937 => true, + 2938 => true, + 2939 => true, + 2940 => true, + 2941 => true, + 2942 => true, + 2943 => true, + 2944 => true, + 2945 => true, + 2948 => true, + 2955 => true, + 2956 => true, + 2957 => true, + 2961 => true, + 2966 => true, + 2967 => true, + 2968 => true, + 2971 => true, + 2973 => true, + 2976 => true, + 2977 => true, + 2978 => true, + 2981 => true, + 2982 => true, + 2983 => true, + 2987 => true, + 2988 => true, + 2989 => true, + 3002 => true, + 3003 => true, + 3004 => true, + 3005 => true, + 3011 => true, + 3012 => true, + 3013 => true, + 3017 => true, + 3022 => true, + 3023 => true, + 3025 => true, + 3026 => true, + 3027 => true, + 3028 => true, + 3029 => true, + 3030 => true, + 3032 => true, + 3033 => true, + 3034 => true, + 3035 => true, + 3036 => true, + 3037 => true, + 3038 => true, + 3039 => true, + 3040 => true, + 3041 => true, + 3042 => true, + 3043 => true, + 3044 => true, + 3045 => true, + 3067 => true, + 3068 => true, + 3069 => true, + 3070 => true, + 3071 => true, + 3085 => true, + 3089 => true, + 3113 => true, + 3130 => true, + 3131 => true, + 3132 => true, + 3141 => true, + 3145 => true, + 3150 => true, + 3151 => true, + 3152 => true, + 3153 => true, + 3154 => true, + 3155 => true, + 3156 => true, + 3159 => true, + 3163 => true, + 3164 => true, + 3165 => true, + 3166 => true, + 3167 => true, + 3172 => true, + 3173 => true, + 3184 => true, + 3185 => true, + 3186 => true, + 3187 => true, + 3188 => true, + 3189 => true, + 3190 => true, + 3213 => true, + 3217 => true, + 3241 => true, + 3252 => true, + 3258 => true, + 3259 => true, + 3269 => true, + 3273 => true, + 3278 => true, + 3279 => true, + 3280 => true, + 3281 => true, + 3282 => true, + 3283 => true, + 3284 => true, + 3287 => true, + 3288 => true, + 3289 => true, + 3290 => true, + 3291 => true, + 3292 => true, + 3293 => true, + 3295 => true, + 3300 => true, + 3301 => true, + 3312 => true, + 3315 => true, + 3316 => true, + 3317 => true, + 3318 => true, + 3319 => true, + 3320 => true, + 3321 => true, + 3322 => true, + 3323 => true, + 3324 => true, + 3325 => true, + 3326 => true, + 3327 => true, + 3341 => true, + 3345 => true, + 3397 => true, + 3401 => true, + 3408 => true, + 3409 => true, + 3410 => true, + 3411 => true, + 3428 => true, + 3429 => true, + 3456 => true, + 3460 => true, + 3479 => true, + 3480 => true, + 3481 => true, + 3506 => true, + 3516 => true, + 3518 => true, + 3519 => true, + 3527 => true, + 3528 => true, + 3529 => true, + 3531 => true, + 3532 => true, + 3533 => true, + 3534 => true, + 3541 => true, + 3543 => true, + 3552 => true, + 3553 => true, + 3554 => true, + 3555 => true, + 3556 => true, + 3557 => true, + 3568 => true, + 3569 => true, + 3573 => true, + 3574 => true, + 3575 => true, + 3576 => true, + 3577 => true, + 3578 => true, + 3579 => true, + 3580 => true, + 3581 => true, + 3582 => true, + 3583 => true, + 3584 => true, + 3643 => true, + 3644 => true, + 3645 => true, + 3646 => true, + 3715 => true, + 3717 => true, + 3723 => true, + 3748 => true, + 3750 => true, + 3774 => true, + 3775 => true, + 3781 => true, + 3783 => true, + 3790 => true, + 3791 => true, + 3802 => true, + 3803 => true, + 3912 => true, + 3949 => true, + 3950 => true, + 3951 => true, + 3952 => true, + 3992 => true, + 4029 => true, + 4045 => true, + 4294 => true, + 4296 => true, + 4297 => true, + 4298 => true, + 4299 => true, + 4300 => true, + 4302 => true, + 4303 => true, + 4447 => true, + 4448 => true, + 4681 => true, + 4686 => true, + 4687 => true, + 4695 => true, + 4697 => true, + 4702 => true, + 4703 => true, + 4745 => true, + 4750 => true, + 4751 => true, + 4785 => true, + 4790 => true, + 4791 => true, + 4799 => true, + 4801 => true, + 4806 => true, + 4807 => true, + 4823 => true, + 4881 => true, + 4886 => true, + 4887 => true, + 4955 => true, + 4956 => true, + 4989 => true, + 4990 => true, + 4991 => true, + 5018 => true, + 5019 => true, + 5020 => true, + 5021 => true, + 5022 => true, + 5023 => true, + 5110 => true, + 5111 => true, + 5118 => true, + 5119 => true, + 5760 => true, + 5789 => true, + 5790 => true, + 5791 => true, + 5881 => true, + 5882 => true, + 5883 => true, + 5884 => true, + 5885 => true, + 5886 => true, + 5887 => true, + 5901 => true, + 5909 => true, + 5910 => true, + 5911 => true, + 5912 => true, + 5913 => true, + 5914 => true, + 5915 => true, + 5916 => true, + 5917 => true, + 5918 => true, + 5919 => true, + 5943 => true, + 5944 => true, + 5945 => true, + 5946 => true, + 5947 => true, + 5948 => true, + 5949 => true, + 5950 => true, + 5951 => true, + 5972 => true, + 5973 => true, + 5974 => true, + 5975 => true, + 5976 => true, + 5977 => true, + 5978 => true, + 5979 => true, + 5980 => true, + 5981 => true, + 5982 => true, + 5983 => true, + 5997 => true, + 6001 => true, + 6004 => true, + 6005 => true, + 6006 => true, + 6007 => true, + 6008 => true, + 6009 => true, + 6010 => true, + 6011 => true, + 6012 => true, + 6013 => true, + 6014 => true, + 6015 => true, + 6068 => true, + 6069 => true, + 6110 => true, + 6111 => true, + 6122 => true, + 6123 => true, + 6124 => true, + 6125 => true, + 6126 => true, + 6127 => true, + 6138 => true, + 6139 => true, + 6140 => true, + 6141 => true, + 6142 => true, + 6143 => true, + 6150 => true, + 6158 => true, + 6159 => true, + 6170 => true, + 6171 => true, + 6172 => true, + 6173 => true, + 6174 => true, + 6175 => true, + 6265 => true, + 6266 => true, + 6267 => true, + 6268 => true, + 6269 => true, + 6270 => true, + 6271 => true, + 6315 => true, + 6316 => true, + 6317 => true, + 6318 => true, + 6319 => true, + 6390 => true, + 6391 => true, + 6392 => true, + 6393 => true, + 6394 => true, + 6395 => true, + 6396 => true, + 6397 => true, + 6398 => true, + 6399 => true, + 6431 => true, + 6444 => true, + 6445 => true, + 6446 => true, + 6447 => true, + 6460 => true, + 6461 => true, + 6462 => true, + 6463 => true, + 6465 => true, + 6466 => true, + 6467 => true, + 6510 => true, + 6511 => true, + 6517 => true, + 6518 => true, + 6519 => true, + 6520 => true, + 6521 => true, + 6522 => true, + 6523 => true, + 6524 => true, + 6525 => true, + 6526 => true, + 6527 => true, + 6572 => true, + 6573 => true, + 6574 => true, + 6575 => true, + 6602 => true, + 6603 => true, + 6604 => true, + 6605 => true, + 6606 => true, + 6607 => true, + 6619 => true, + 6620 => true, + 6621 => true, + 6684 => true, + 6685 => true, + 6751 => true, + 6781 => true, + 6782 => true, + 6794 => true, + 6795 => true, + 6796 => true, + 6797 => true, + 6798 => true, + 6799 => true, + 6810 => true, + 6811 => true, + 6812 => true, + 6813 => true, + 6814 => true, + 6815 => true, + 6830 => true, + 6831 => true, + 6988 => true, + 6989 => true, + 6990 => true, + 6991 => true, + 7037 => true, + 7038 => true, + 7039 => true, + 7156 => true, + 7157 => true, + 7158 => true, + 7159 => true, + 7160 => true, + 7161 => true, + 7162 => true, + 7163 => true, + 7224 => true, + 7225 => true, + 7226 => true, + 7242 => true, + 7243 => true, + 7244 => true, + 7305 => true, + 7306 => true, + 7307 => true, + 7308 => true, + 7309 => true, + 7310 => true, + 7311 => true, + 7355 => true, + 7356 => true, + 7368 => true, + 7369 => true, + 7370 => true, + 7371 => true, + 7372 => true, + 7373 => true, + 7374 => true, + 7375 => true, + 7419 => true, + 7420 => true, + 7421 => true, + 7422 => true, + 7423 => true, + 7674 => true, + 7958 => true, + 7959 => true, + 7966 => true, + 7967 => true, + 8006 => true, + 8007 => true, + 8014 => true, + 8015 => true, + 8024 => true, + 8026 => true, + 8028 => true, + 8030 => true, + 8062 => true, + 8063 => true, + 8117 => true, + 8133 => true, + 8148 => true, + 8149 => true, + 8156 => true, + 8176 => true, + 8177 => true, + 8181 => true, + 8191 => true, + 8206 => true, + 8207 => true, + 8228 => true, + 8229 => true, + 8230 => true, + 8232 => true, + 8233 => true, + 8234 => true, + 8235 => true, + 8236 => true, + 8237 => true, + 8238 => true, + 8289 => true, + 8290 => true, + 8291 => true, + 8293 => true, + 8294 => true, + 8295 => true, + 8296 => true, + 8297 => true, + 8298 => true, + 8299 => true, + 8300 => true, + 8301 => true, + 8302 => true, + 8303 => true, + 8306 => true, + 8307 => true, + 8335 => true, + 8349 => true, + 8350 => true, + 8351 => true, + 8384 => true, + 8385 => true, + 8386 => true, + 8387 => true, + 8388 => true, + 8389 => true, + 8390 => true, + 8391 => true, + 8392 => true, + 8393 => true, + 8394 => true, + 8395 => true, + 8396 => true, + 8397 => true, + 8398 => true, + 8399 => true, + 8433 => true, + 8434 => true, + 8435 => true, + 8436 => true, + 8437 => true, + 8438 => true, + 8439 => true, + 8440 => true, + 8441 => true, + 8442 => true, + 8443 => true, + 8444 => true, + 8445 => true, + 8446 => true, + 8447 => true, + 8498 => true, + 8579 => true, + 8588 => true, + 8589 => true, + 8590 => true, + 8591 => true, + 9255 => true, + 9256 => true, + 9257 => true, + 9258 => true, + 9259 => true, + 9260 => true, + 9261 => true, + 9262 => true, + 9263 => true, + 9264 => true, + 9265 => true, + 9266 => true, + 9267 => true, + 9268 => true, + 9269 => true, + 9270 => true, + 9271 => true, + 9272 => true, + 9273 => true, + 9274 => true, + 9275 => true, + 9276 => true, + 9277 => true, + 9278 => true, + 9279 => true, + 9291 => true, + 9292 => true, + 9293 => true, + 9294 => true, + 9295 => true, + 9296 => true, + 9297 => true, + 9298 => true, + 9299 => true, + 9300 => true, + 9301 => true, + 9302 => true, + 9303 => true, + 9304 => true, + 9305 => true, + 9306 => true, + 9307 => true, + 9308 => true, + 9309 => true, + 9310 => true, + 9311 => true, + 9352 => true, + 9353 => true, + 9354 => true, + 9355 => true, + 9356 => true, + 9357 => true, + 9358 => true, + 9359 => true, + 9360 => true, + 9361 => true, + 9362 => true, + 9363 => true, + 9364 => true, + 9365 => true, + 9366 => true, + 9367 => true, + 9368 => true, + 9369 => true, + 9370 => true, + 9371 => true, + 11124 => true, + 11125 => true, + 11158 => true, + 11311 => true, + 11359 => true, + 11508 => true, + 11509 => true, + 11510 => true, + 11511 => true, + 11512 => true, + 11558 => true, + 11560 => true, + 11561 => true, + 11562 => true, + 11563 => true, + 11564 => true, + 11566 => true, + 11567 => true, + 11624 => true, + 11625 => true, + 11626 => true, + 11627 => true, + 11628 => true, + 11629 => true, + 11630 => true, + 11633 => true, + 11634 => true, + 11635 => true, + 11636 => true, + 11637 => true, + 11638 => true, + 11639 => true, + 11640 => true, + 11641 => true, + 11642 => true, + 11643 => true, + 11644 => true, + 11645 => true, + 11646 => true, + 11671 => true, + 11672 => true, + 11673 => true, + 11674 => true, + 11675 => true, + 11676 => true, + 11677 => true, + 11678 => true, + 11679 => true, + 11687 => true, + 11695 => true, + 11703 => true, + 11711 => true, + 11719 => true, + 11727 => true, + 11735 => true, + 11743 => true, + 11930 => true, + 12020 => true, + 12021 => true, + 12022 => true, + 12023 => true, + 12024 => true, + 12025 => true, + 12026 => true, + 12027 => true, + 12028 => true, + 12029 => true, + 12030 => true, + 12031 => true, + 12246 => true, + 12247 => true, + 12248 => true, + 12249 => true, + 12250 => true, + 12251 => true, + 12252 => true, + 12253 => true, + 12254 => true, + 12255 => true, + 12256 => true, + 12257 => true, + 12258 => true, + 12259 => true, + 12260 => true, + 12261 => true, + 12262 => true, + 12263 => true, + 12264 => true, + 12265 => true, + 12266 => true, + 12267 => true, + 12268 => true, + 12269 => true, + 12270 => true, + 12271 => true, + 12272 => true, + 12273 => true, + 12274 => true, + 12275 => true, + 12276 => true, + 12277 => true, + 12278 => true, + 12279 => true, + 12280 => true, + 12281 => true, + 12282 => true, + 12283 => true, + 12284 => true, + 12285 => true, + 12286 => true, + 12287 => true, + 12352 => true, + 12439 => true, + 12440 => true, + 12544 => true, + 12545 => true, + 12546 => true, + 12547 => true, + 12548 => true, + 12592 => true, + 12644 => true, + 12687 => true, + 12772 => true, + 12773 => true, + 12774 => true, + 12775 => true, + 12776 => true, + 12777 => true, + 12778 => true, + 12779 => true, + 12780 => true, + 12781 => true, + 12782 => true, + 12783 => true, + 12831 => true, + 13250 => true, + 13255 => true, + 13272 => true, + 40957 => true, + 40958 => true, + 40959 => true, + 42125 => true, + 42126 => true, + 42127 => true, + 42183 => true, + 42184 => true, + 42185 => true, + 42186 => true, + 42187 => true, + 42188 => true, + 42189 => true, + 42190 => true, + 42191 => true, + 42540 => true, + 42541 => true, + 42542 => true, + 42543 => true, + 42544 => true, + 42545 => true, + 42546 => true, + 42547 => true, + 42548 => true, + 42549 => true, + 42550 => true, + 42551 => true, + 42552 => true, + 42553 => true, + 42554 => true, + 42555 => true, + 42556 => true, + 42557 => true, + 42558 => true, + 42559 => true, + 42744 => true, + 42745 => true, + 42746 => true, + 42747 => true, + 42748 => true, + 42749 => true, + 42750 => true, + 42751 => true, + 42944 => true, + 42945 => true, + 43053 => true, + 43054 => true, + 43055 => true, + 43066 => true, + 43067 => true, + 43068 => true, + 43069 => true, + 43070 => true, + 43071 => true, + 43128 => true, + 43129 => true, + 43130 => true, + 43131 => true, + 43132 => true, + 43133 => true, + 43134 => true, + 43135 => true, + 43206 => true, + 43207 => true, + 43208 => true, + 43209 => true, + 43210 => true, + 43211 => true, + 43212 => true, + 43213 => true, + 43226 => true, + 43227 => true, + 43228 => true, + 43229 => true, + 43230 => true, + 43231 => true, + 43348 => true, + 43349 => true, + 43350 => true, + 43351 => true, + 43352 => true, + 43353 => true, + 43354 => true, + 43355 => true, + 43356 => true, + 43357 => true, + 43358 => true, + 43389 => true, + 43390 => true, + 43391 => true, + 43470 => true, + 43482 => true, + 43483 => true, + 43484 => true, + 43485 => true, + 43519 => true, + 43575 => true, + 43576 => true, + 43577 => true, + 43578 => true, + 43579 => true, + 43580 => true, + 43581 => true, + 43582 => true, + 43583 => true, + 43598 => true, + 43599 => true, + 43610 => true, + 43611 => true, + 43715 => true, + 43716 => true, + 43717 => true, + 43718 => true, + 43719 => true, + 43720 => true, + 43721 => true, + 43722 => true, + 43723 => true, + 43724 => true, + 43725 => true, + 43726 => true, + 43727 => true, + 43728 => true, + 43729 => true, + 43730 => true, + 43731 => true, + 43732 => true, + 43733 => true, + 43734 => true, + 43735 => true, + 43736 => true, + 43737 => true, + 43738 => true, + 43767 => true, + 43768 => true, + 43769 => true, + 43770 => true, + 43771 => true, + 43772 => true, + 43773 => true, + 43774 => true, + 43775 => true, + 43776 => true, + 43783 => true, + 43784 => true, + 43791 => true, + 43792 => true, + 43799 => true, + 43800 => true, + 43801 => true, + 43802 => true, + 43803 => true, + 43804 => true, + 43805 => true, + 43806 => true, + 43807 => true, + 43815 => true, + 43823 => true, + 43884 => true, + 43885 => true, + 43886 => true, + 43887 => true, + 44014 => true, + 44015 => true, + 44026 => true, + 44027 => true, + 44028 => true, + 44029 => true, + 44030 => true, + 44031 => true, + 55204 => true, + 55205 => true, + 55206 => true, + 55207 => true, + 55208 => true, + 55209 => true, + 55210 => true, + 55211 => true, + 55212 => true, + 55213 => true, + 55214 => true, + 55215 => true, + 55239 => true, + 55240 => true, + 55241 => true, + 55242 => true, + 55292 => true, + 55293 => true, + 55294 => true, + 55295 => true, + 64110 => true, + 64111 => true, + 64263 => true, + 64264 => true, + 64265 => true, + 64266 => true, + 64267 => true, + 64268 => true, + 64269 => true, + 64270 => true, + 64271 => true, + 64272 => true, + 64273 => true, + 64274 => true, + 64280 => true, + 64281 => true, + 64282 => true, + 64283 => true, + 64284 => true, + 64311 => true, + 64317 => true, + 64319 => true, + 64322 => true, + 64325 => true, + 64450 => true, + 64451 => true, + 64452 => true, + 64453 => true, + 64454 => true, + 64455 => true, + 64456 => true, + 64457 => true, + 64458 => true, + 64459 => true, + 64460 => true, + 64461 => true, + 64462 => true, + 64463 => true, + 64464 => true, + 64465 => true, + 64466 => true, + 64832 => true, + 64833 => true, + 64834 => true, + 64835 => true, + 64836 => true, + 64837 => true, + 64838 => true, + 64839 => true, + 64840 => true, + 64841 => true, + 64842 => true, + 64843 => true, + 64844 => true, + 64845 => true, + 64846 => true, + 64847 => true, + 64912 => true, + 64913 => true, + 64968 => true, + 64969 => true, + 64970 => true, + 64971 => true, + 64972 => true, + 64973 => true, + 64974 => true, + 64975 => true, + 65022 => true, + 65023 => true, + 65042 => true, + 65049 => true, + 65050 => true, + 65051 => true, + 65052 => true, + 65053 => true, + 65054 => true, + 65055 => true, + 65072 => true, + 65106 => true, + 65107 => true, + 65127 => true, + 65132 => true, + 65133 => true, + 65134 => true, + 65135 => true, + 65141 => true, + 65277 => true, + 65278 => true, + 65280 => true, + 65440 => true, + 65471 => true, + 65472 => true, + 65473 => true, + 65480 => true, + 65481 => true, + 65488 => true, + 65489 => true, + 65496 => true, + 65497 => true, + 65501 => true, + 65502 => true, + 65503 => true, + 65511 => true, + 65519 => true, + 65520 => true, + 65521 => true, + 65522 => true, + 65523 => true, + 65524 => true, + 65525 => true, + 65526 => true, + 65527 => true, + 65528 => true, + 65529 => true, + 65530 => true, + 65531 => true, + 65532 => true, + 65533 => true, + 65534 => true, + 65535 => true, + 65548 => true, + 65575 => true, + 65595 => true, + 65598 => true, + 65614 => true, + 65615 => true, + 65787 => true, + 65788 => true, + 65789 => true, + 65790 => true, + 65791 => true, + 65795 => true, + 65796 => true, + 65797 => true, + 65798 => true, + 65844 => true, + 65845 => true, + 65846 => true, + 65935 => true, + 65949 => true, + 65950 => true, + 65951 => true, + 66205 => true, + 66206 => true, + 66207 => true, + 66257 => true, + 66258 => true, + 66259 => true, + 66260 => true, + 66261 => true, + 66262 => true, + 66263 => true, + 66264 => true, + 66265 => true, + 66266 => true, + 66267 => true, + 66268 => true, + 66269 => true, + 66270 => true, + 66271 => true, + 66300 => true, + 66301 => true, + 66302 => true, + 66303 => true, + 66340 => true, + 66341 => true, + 66342 => true, + 66343 => true, + 66344 => true, + 66345 => true, + 66346 => true, + 66347 => true, + 66348 => true, + 66379 => true, + 66380 => true, + 66381 => true, + 66382 => true, + 66383 => true, + 66427 => true, + 66428 => true, + 66429 => true, + 66430 => true, + 66431 => true, + 66462 => true, + 66500 => true, + 66501 => true, + 66502 => true, + 66503 => true, + 66718 => true, + 66719 => true, + 66730 => true, + 66731 => true, + 66732 => true, + 66733 => true, + 66734 => true, + 66735 => true, + 66772 => true, + 66773 => true, + 66774 => true, + 66775 => true, + 66812 => true, + 66813 => true, + 66814 => true, + 66815 => true, + 66856 => true, + 66857 => true, + 66858 => true, + 66859 => true, + 66860 => true, + 66861 => true, + 66862 => true, + 66863 => true, + 66916 => true, + 66917 => true, + 66918 => true, + 66919 => true, + 66920 => true, + 66921 => true, + 66922 => true, + 66923 => true, + 66924 => true, + 66925 => true, + 66926 => true, + 67383 => true, + 67384 => true, + 67385 => true, + 67386 => true, + 67387 => true, + 67388 => true, + 67389 => true, + 67390 => true, + 67391 => true, + 67414 => true, + 67415 => true, + 67416 => true, + 67417 => true, + 67418 => true, + 67419 => true, + 67420 => true, + 67421 => true, + 67422 => true, + 67423 => true, + 67590 => true, + 67591 => true, + 67593 => true, + 67638 => true, + 67641 => true, + 67642 => true, + 67643 => true, + 67645 => true, + 67646 => true, + 67670 => true, + 67743 => true, + 67744 => true, + 67745 => true, + 67746 => true, + 67747 => true, + 67748 => true, + 67749 => true, + 67750 => true, + 67827 => true, + 67830 => true, + 67831 => true, + 67832 => true, + 67833 => true, + 67834 => true, + 67868 => true, + 67869 => true, + 67870 => true, + 67898 => true, + 67899 => true, + 67900 => true, + 67901 => true, + 67902 => true, + 68024 => true, + 68025 => true, + 68026 => true, + 68027 => true, + 68048 => true, + 68049 => true, + 68100 => true, + 68103 => true, + 68104 => true, + 68105 => true, + 68106 => true, + 68107 => true, + 68116 => true, + 68120 => true, + 68150 => true, + 68151 => true, + 68155 => true, + 68156 => true, + 68157 => true, + 68158 => true, + 68169 => true, + 68170 => true, + 68171 => true, + 68172 => true, + 68173 => true, + 68174 => true, + 68175 => true, + 68185 => true, + 68186 => true, + 68187 => true, + 68188 => true, + 68189 => true, + 68190 => true, + 68191 => true, + 68327 => true, + 68328 => true, + 68329 => true, + 68330 => true, + 68343 => true, + 68344 => true, + 68345 => true, + 68346 => true, + 68347 => true, + 68348 => true, + 68349 => true, + 68350 => true, + 68351 => true, + 68406 => true, + 68407 => true, + 68408 => true, + 68438 => true, + 68439 => true, + 68467 => true, + 68468 => true, + 68469 => true, + 68470 => true, + 68471 => true, + 68498 => true, + 68499 => true, + 68500 => true, + 68501 => true, + 68502 => true, + 68503 => true, + 68504 => true, + 68509 => true, + 68510 => true, + 68511 => true, + 68512 => true, + 68513 => true, + 68514 => true, + 68515 => true, + 68516 => true, + 68517 => true, + 68518 => true, + 68519 => true, + 68520 => true, + 68787 => true, + 68788 => true, + 68789 => true, + 68790 => true, + 68791 => true, + 68792 => true, + 68793 => true, + 68794 => true, + 68795 => true, + 68796 => true, + 68797 => true, + 68798 => true, + 68799 => true, + 68851 => true, + 68852 => true, + 68853 => true, + 68854 => true, + 68855 => true, + 68856 => true, + 68857 => true, + 68904 => true, + 68905 => true, + 68906 => true, + 68907 => true, + 68908 => true, + 68909 => true, + 68910 => true, + 68911 => true, + 69247 => true, + 69290 => true, + 69294 => true, + 69295 => true, + 69416 => true, + 69417 => true, + 69418 => true, + 69419 => true, + 69420 => true, + 69421 => true, + 69422 => true, + 69423 => true, + 69580 => true, + 69581 => true, + 69582 => true, + 69583 => true, + 69584 => true, + 69585 => true, + 69586 => true, + 69587 => true, + 69588 => true, + 69589 => true, + 69590 => true, + 69591 => true, + 69592 => true, + 69593 => true, + 69594 => true, + 69595 => true, + 69596 => true, + 69597 => true, + 69598 => true, + 69599 => true, + 69623 => true, + 69624 => true, + 69625 => true, + 69626 => true, + 69627 => true, + 69628 => true, + 69629 => true, + 69630 => true, + 69631 => true, + 69710 => true, + 69711 => true, + 69712 => true, + 69713 => true, + 69744 => true, + 69745 => true, + 69746 => true, + 69747 => true, + 69748 => true, + 69749 => true, + 69750 => true, + 69751 => true, + 69752 => true, + 69753 => true, + 69754 => true, + 69755 => true, + 69756 => true, + 69757 => true, + 69758 => true, + 69821 => true, + 69826 => true, + 69827 => true, + 69828 => true, + 69829 => true, + 69830 => true, + 69831 => true, + 69832 => true, + 69833 => true, + 69834 => true, + 69835 => true, + 69836 => true, + 69837 => true, + 69838 => true, + 69839 => true, + 69865 => true, + 69866 => true, + 69867 => true, + 69868 => true, + 69869 => true, + 69870 => true, + 69871 => true, + 69882 => true, + 69883 => true, + 69884 => true, + 69885 => true, + 69886 => true, + 69887 => true, + 69941 => true, + 69960 => true, + 69961 => true, + 69962 => true, + 69963 => true, + 69964 => true, + 69965 => true, + 69966 => true, + 69967 => true, + 70007 => true, + 70008 => true, + 70009 => true, + 70010 => true, + 70011 => true, + 70012 => true, + 70013 => true, + 70014 => true, + 70015 => true, + 70112 => true, + 70133 => true, + 70134 => true, + 70135 => true, + 70136 => true, + 70137 => true, + 70138 => true, + 70139 => true, + 70140 => true, + 70141 => true, + 70142 => true, + 70143 => true, + 70162 => true, + 70279 => true, + 70281 => true, + 70286 => true, + 70302 => true, + 70314 => true, + 70315 => true, + 70316 => true, + 70317 => true, + 70318 => true, + 70319 => true, + 70379 => true, + 70380 => true, + 70381 => true, + 70382 => true, + 70383 => true, + 70394 => true, + 70395 => true, + 70396 => true, + 70397 => true, + 70398 => true, + 70399 => true, + 70404 => true, + 70413 => true, + 70414 => true, + 70417 => true, + 70418 => true, + 70441 => true, + 70449 => true, + 70452 => true, + 70458 => true, + 70469 => true, + 70470 => true, + 70473 => true, + 70474 => true, + 70478 => true, + 70479 => true, + 70481 => true, + 70482 => true, + 70483 => true, + 70484 => true, + 70485 => true, + 70486 => true, + 70488 => true, + 70489 => true, + 70490 => true, + 70491 => true, + 70492 => true, + 70500 => true, + 70501 => true, + 70509 => true, + 70510 => true, + 70511 => true, + 70748 => true, + 70754 => true, + 70755 => true, + 70756 => true, + 70757 => true, + 70758 => true, + 70759 => true, + 70760 => true, + 70761 => true, + 70762 => true, + 70763 => true, + 70764 => true, + 70765 => true, + 70766 => true, + 70767 => true, + 70768 => true, + 70769 => true, + 70770 => true, + 70771 => true, + 70772 => true, + 70773 => true, + 70774 => true, + 70775 => true, + 70776 => true, + 70777 => true, + 70778 => true, + 70779 => true, + 70780 => true, + 70781 => true, + 70782 => true, + 70783 => true, + 70856 => true, + 70857 => true, + 70858 => true, + 70859 => true, + 70860 => true, + 70861 => true, + 70862 => true, + 70863 => true, + 71094 => true, + 71095 => true, + 71237 => true, + 71238 => true, + 71239 => true, + 71240 => true, + 71241 => true, + 71242 => true, + 71243 => true, + 71244 => true, + 71245 => true, + 71246 => true, + 71247 => true, + 71258 => true, + 71259 => true, + 71260 => true, + 71261 => true, + 71262 => true, + 71263 => true, + 71277 => true, + 71278 => true, + 71279 => true, + 71280 => true, + 71281 => true, + 71282 => true, + 71283 => true, + 71284 => true, + 71285 => true, + 71286 => true, + 71287 => true, + 71288 => true, + 71289 => true, + 71290 => true, + 71291 => true, + 71292 => true, + 71293 => true, + 71294 => true, + 71295 => true, + 71353 => true, + 71354 => true, + 71355 => true, + 71356 => true, + 71357 => true, + 71358 => true, + 71359 => true, + 71451 => true, + 71452 => true, + 71468 => true, + 71469 => true, + 71470 => true, + 71471 => true, + 71923 => true, + 71924 => true, + 71925 => true, + 71926 => true, + 71927 => true, + 71928 => true, + 71929 => true, + 71930 => true, + 71931 => true, + 71932 => true, + 71933 => true, + 71934 => true, + 71943 => true, + 71944 => true, + 71946 => true, + 71947 => true, + 71956 => true, + 71959 => true, + 71990 => true, + 71993 => true, + 71994 => true, + 72007 => true, + 72008 => true, + 72009 => true, + 72010 => true, + 72011 => true, + 72012 => true, + 72013 => true, + 72014 => true, + 72015 => true, + 72104 => true, + 72105 => true, + 72152 => true, + 72153 => true, + 72165 => true, + 72166 => true, + 72167 => true, + 72168 => true, + 72169 => true, + 72170 => true, + 72171 => true, + 72172 => true, + 72173 => true, + 72174 => true, + 72175 => true, + 72176 => true, + 72177 => true, + 72178 => true, + 72179 => true, + 72180 => true, + 72181 => true, + 72182 => true, + 72183 => true, + 72184 => true, + 72185 => true, + 72186 => true, + 72187 => true, + 72188 => true, + 72189 => true, + 72190 => true, + 72191 => true, + 72264 => true, + 72265 => true, + 72266 => true, + 72267 => true, + 72268 => true, + 72269 => true, + 72270 => true, + 72271 => true, + 72355 => true, + 72356 => true, + 72357 => true, + 72358 => true, + 72359 => true, + 72360 => true, + 72361 => true, + 72362 => true, + 72363 => true, + 72364 => true, + 72365 => true, + 72366 => true, + 72367 => true, + 72368 => true, + 72369 => true, + 72370 => true, + 72371 => true, + 72372 => true, + 72373 => true, + 72374 => true, + 72375 => true, + 72376 => true, + 72377 => true, + 72378 => true, + 72379 => true, + 72380 => true, + 72381 => true, + 72382 => true, + 72383 => true, + 72713 => true, + 72759 => true, + 72774 => true, + 72775 => true, + 72776 => true, + 72777 => true, + 72778 => true, + 72779 => true, + 72780 => true, + 72781 => true, + 72782 => true, + 72783 => true, + 72813 => true, + 72814 => true, + 72815 => true, + 72848 => true, + 72849 => true, + 72872 => true, + 72967 => true, + 72970 => true, + 73015 => true, + 73016 => true, + 73017 => true, + 73019 => true, + 73022 => true, + 73032 => true, + 73033 => true, + 73034 => true, + 73035 => true, + 73036 => true, + 73037 => true, + 73038 => true, + 73039 => true, + 73050 => true, + 73051 => true, + 73052 => true, + 73053 => true, + 73054 => true, + 73055 => true, + 73062 => true, + 73065 => true, + 73103 => true, + 73106 => true, + 73113 => true, + 73114 => true, + 73115 => true, + 73116 => true, + 73117 => true, + 73118 => true, + 73119 => true, + 73649 => true, + 73650 => true, + 73651 => true, + 73652 => true, + 73653 => true, + 73654 => true, + 73655 => true, + 73656 => true, + 73657 => true, + 73658 => true, + 73659 => true, + 73660 => true, + 73661 => true, + 73662 => true, + 73663 => true, + 73714 => true, + 73715 => true, + 73716 => true, + 73717 => true, + 73718 => true, + 73719 => true, + 73720 => true, + 73721 => true, + 73722 => true, + 73723 => true, + 73724 => true, + 73725 => true, + 73726 => true, + 74863 => true, + 74869 => true, + 74870 => true, + 74871 => true, + 74872 => true, + 74873 => true, + 74874 => true, + 74875 => true, + 74876 => true, + 74877 => true, + 74878 => true, + 74879 => true, + 78895 => true, + 78896 => true, + 78897 => true, + 78898 => true, + 78899 => true, + 78900 => true, + 78901 => true, + 78902 => true, + 78903 => true, + 78904 => true, + 92729 => true, + 92730 => true, + 92731 => true, + 92732 => true, + 92733 => true, + 92734 => true, + 92735 => true, + 92767 => true, + 92778 => true, + 92779 => true, + 92780 => true, + 92781 => true, + 92910 => true, + 92911 => true, + 92918 => true, + 92919 => true, + 92920 => true, + 92921 => true, + 92922 => true, + 92923 => true, + 92924 => true, + 92925 => true, + 92926 => true, + 92927 => true, + 92998 => true, + 92999 => true, + 93000 => true, + 93001 => true, + 93002 => true, + 93003 => true, + 93004 => true, + 93005 => true, + 93006 => true, + 93007 => true, + 93018 => true, + 93026 => true, + 93048 => true, + 93049 => true, + 93050 => true, + 93051 => true, + 93052 => true, + 94027 => true, + 94028 => true, + 94029 => true, + 94030 => true, + 94088 => true, + 94089 => true, + 94090 => true, + 94091 => true, + 94092 => true, + 94093 => true, + 94094 => true, + 94181 => true, + 94182 => true, + 94183 => true, + 94184 => true, + 94185 => true, + 94186 => true, + 94187 => true, + 94188 => true, + 94189 => true, + 94190 => true, + 94191 => true, + 94194 => true, + 94195 => true, + 94196 => true, + 94197 => true, + 94198 => true, + 94199 => true, + 94200 => true, + 94201 => true, + 94202 => true, + 94203 => true, + 94204 => true, + 94205 => true, + 94206 => true, + 94207 => true, + 100344 => true, + 100345 => true, + 100346 => true, + 100347 => true, + 100348 => true, + 100349 => true, + 100350 => true, + 100351 => true, + 110931 => true, + 110932 => true, + 110933 => true, + 110934 => true, + 110935 => true, + 110936 => true, + 110937 => true, + 110938 => true, + 110939 => true, + 110940 => true, + 110941 => true, + 110942 => true, + 110943 => true, + 110944 => true, + 110945 => true, + 110946 => true, + 110947 => true, + 110952 => true, + 110953 => true, + 110954 => true, + 110955 => true, + 110956 => true, + 110957 => true, + 110958 => true, + 110959 => true, + 113771 => true, + 113772 => true, + 113773 => true, + 113774 => true, + 113775 => true, + 113789 => true, + 113790 => true, + 113791 => true, + 113801 => true, + 113802 => true, + 113803 => true, + 113804 => true, + 113805 => true, + 113806 => true, + 113807 => true, + 113818 => true, + 113819 => true, + 119030 => true, + 119031 => true, + 119032 => true, + 119033 => true, + 119034 => true, + 119035 => true, + 119036 => true, + 119037 => true, + 119038 => true, + 119039 => true, + 119079 => true, + 119080 => true, + 119155 => true, + 119156 => true, + 119157 => true, + 119158 => true, + 119159 => true, + 119160 => true, + 119161 => true, + 119162 => true, + 119273 => true, + 119274 => true, + 119275 => true, + 119276 => true, + 119277 => true, + 119278 => true, + 119279 => true, + 119280 => true, + 119281 => true, + 119282 => true, + 119283 => true, + 119284 => true, + 119285 => true, + 119286 => true, + 119287 => true, + 119288 => true, + 119289 => true, + 119290 => true, + 119291 => true, + 119292 => true, + 119293 => true, + 119294 => true, + 119295 => true, + 119540 => true, + 119541 => true, + 119542 => true, + 119543 => true, + 119544 => true, + 119545 => true, + 119546 => true, + 119547 => true, + 119548 => true, + 119549 => true, + 119550 => true, + 119551 => true, + 119639 => true, + 119640 => true, + 119641 => true, + 119642 => true, + 119643 => true, + 119644 => true, + 119645 => true, + 119646 => true, + 119647 => true, + 119893 => true, + 119965 => true, + 119968 => true, + 119969 => true, + 119971 => true, + 119972 => true, + 119975 => true, + 119976 => true, + 119981 => true, + 119994 => true, + 119996 => true, + 120004 => true, + 120070 => true, + 120075 => true, + 120076 => true, + 120085 => true, + 120093 => true, + 120122 => true, + 120127 => true, + 120133 => true, + 120135 => true, + 120136 => true, + 120137 => true, + 120145 => true, + 120486 => true, + 120487 => true, + 120780 => true, + 120781 => true, + 121484 => true, + 121485 => true, + 121486 => true, + 121487 => true, + 121488 => true, + 121489 => true, + 121490 => true, + 121491 => true, + 121492 => true, + 121493 => true, + 121494 => true, + 121495 => true, + 121496 => true, + 121497 => true, + 121498 => true, + 121504 => true, + 122887 => true, + 122905 => true, + 122906 => true, + 122914 => true, + 122917 => true, + 123181 => true, + 123182 => true, + 123183 => true, + 123198 => true, + 123199 => true, + 123210 => true, + 123211 => true, + 123212 => true, + 123213 => true, + 123642 => true, + 123643 => true, + 123644 => true, + 123645 => true, + 123646 => true, + 125125 => true, + 125126 => true, + 125260 => true, + 125261 => true, + 125262 => true, + 125263 => true, + 125274 => true, + 125275 => true, + 125276 => true, + 125277 => true, + 126468 => true, + 126496 => true, + 126499 => true, + 126501 => true, + 126502 => true, + 126504 => true, + 126515 => true, + 126520 => true, + 126522 => true, + 126524 => true, + 126525 => true, + 126526 => true, + 126527 => true, + 126528 => true, + 126529 => true, + 126531 => true, + 126532 => true, + 126533 => true, + 126534 => true, + 126536 => true, + 126538 => true, + 126540 => true, + 126544 => true, + 126547 => true, + 126549 => true, + 126550 => true, + 126552 => true, + 126554 => true, + 126556 => true, + 126558 => true, + 126560 => true, + 126563 => true, + 126565 => true, + 126566 => true, + 126571 => true, + 126579 => true, + 126584 => true, + 126589 => true, + 126591 => true, + 126602 => true, + 126620 => true, + 126621 => true, + 126622 => true, + 126623 => true, + 126624 => true, + 126628 => true, + 126634 => true, + 127020 => true, + 127021 => true, + 127022 => true, + 127023 => true, + 127124 => true, + 127125 => true, + 127126 => true, + 127127 => true, + 127128 => true, + 127129 => true, + 127130 => true, + 127131 => true, + 127132 => true, + 127133 => true, + 127134 => true, + 127135 => true, + 127151 => true, + 127152 => true, + 127168 => true, + 127184 => true, + 127222 => true, + 127223 => true, + 127224 => true, + 127225 => true, + 127226 => true, + 127227 => true, + 127228 => true, + 127229 => true, + 127230 => true, + 127231 => true, + 127232 => true, + 127491 => true, + 127492 => true, + 127493 => true, + 127494 => true, + 127495 => true, + 127496 => true, + 127497 => true, + 127498 => true, + 127499 => true, + 127500 => true, + 127501 => true, + 127502 => true, + 127503 => true, + 127548 => true, + 127549 => true, + 127550 => true, + 127551 => true, + 127561 => true, + 127562 => true, + 127563 => true, + 127564 => true, + 127565 => true, + 127566 => true, + 127567 => true, + 127570 => true, + 127571 => true, + 127572 => true, + 127573 => true, + 127574 => true, + 127575 => true, + 127576 => true, + 127577 => true, + 127578 => true, + 127579 => true, + 127580 => true, + 127581 => true, + 127582 => true, + 127583 => true, + 128728 => true, + 128729 => true, + 128730 => true, + 128731 => true, + 128732 => true, + 128733 => true, + 128734 => true, + 128735 => true, + 128749 => true, + 128750 => true, + 128751 => true, + 128765 => true, + 128766 => true, + 128767 => true, + 128884 => true, + 128885 => true, + 128886 => true, + 128887 => true, + 128888 => true, + 128889 => true, + 128890 => true, + 128891 => true, + 128892 => true, + 128893 => true, + 128894 => true, + 128895 => true, + 128985 => true, + 128986 => true, + 128987 => true, + 128988 => true, + 128989 => true, + 128990 => true, + 128991 => true, + 129004 => true, + 129005 => true, + 129006 => true, + 129007 => true, + 129008 => true, + 129009 => true, + 129010 => true, + 129011 => true, + 129012 => true, + 129013 => true, + 129014 => true, + 129015 => true, + 129016 => true, + 129017 => true, + 129018 => true, + 129019 => true, + 129020 => true, + 129021 => true, + 129022 => true, + 129023 => true, + 129036 => true, + 129037 => true, + 129038 => true, + 129039 => true, + 129096 => true, + 129097 => true, + 129098 => true, + 129099 => true, + 129100 => true, + 129101 => true, + 129102 => true, + 129103 => true, + 129114 => true, + 129115 => true, + 129116 => true, + 129117 => true, + 129118 => true, + 129119 => true, + 129160 => true, + 129161 => true, + 129162 => true, + 129163 => true, + 129164 => true, + 129165 => true, + 129166 => true, + 129167 => true, + 129198 => true, + 129199 => true, + 129401 => true, + 129484 => true, + 129620 => true, + 129621 => true, + 129622 => true, + 129623 => true, + 129624 => true, + 129625 => true, + 129626 => true, + 129627 => true, + 129628 => true, + 129629 => true, + 129630 => true, + 129631 => true, + 129646 => true, + 129647 => true, + 129653 => true, + 129654 => true, + 129655 => true, + 129659 => true, + 129660 => true, + 129661 => true, + 129662 => true, + 129663 => true, + 129671 => true, + 129672 => true, + 129673 => true, + 129674 => true, + 129675 => true, + 129676 => true, + 129677 => true, + 129678 => true, + 129679 => true, + 129705 => true, + 129706 => true, + 129707 => true, + 129708 => true, + 129709 => true, + 129710 => true, + 129711 => true, + 129719 => true, + 129720 => true, + 129721 => true, + 129722 => true, + 129723 => true, + 129724 => true, + 129725 => true, + 129726 => true, + 129727 => true, + 129731 => true, + 129732 => true, + 129733 => true, + 129734 => true, + 129735 => true, + 129736 => true, + 129737 => true, + 129738 => true, + 129739 => true, + 129740 => true, + 129741 => true, + 129742 => true, + 129743 => true, + 129939 => true, + 131070 => true, + 131071 => true, + 177973 => true, + 177974 => true, + 177975 => true, + 177976 => true, + 177977 => true, + 177978 => true, + 177979 => true, + 177980 => true, + 177981 => true, + 177982 => true, + 177983 => true, + 178206 => true, + 178207 => true, + 183970 => true, + 183971 => true, + 183972 => true, + 183973 => true, + 183974 => true, + 183975 => true, + 183976 => true, + 183977 => true, + 183978 => true, + 183979 => true, + 183980 => true, + 183981 => true, + 183982 => true, + 183983 => true, + 194664 => true, + 194676 => true, + 194847 => true, + 194911 => true, + 195007 => true, + 196606 => true, + 196607 => true, + 262142 => true, + 262143 => true, + 327678 => true, + 327679 => true, + 393214 => true, + 393215 => true, + 458750 => true, + 458751 => true, + 524286 => true, + 524287 => true, + 589822 => true, + 589823 => true, + 655358 => true, + 655359 => true, + 720894 => true, + 720895 => true, + 786430 => true, + 786431 => true, + 851966 => true, + 851967 => true, + 917502 => true, + 917503 => true, + 917504 => true, + 917505 => true, + 917506 => true, + 917507 => true, + 917508 => true, + 917509 => true, + 917510 => true, + 917511 => true, + 917512 => true, + 917513 => true, + 917514 => true, + 917515 => true, + 917516 => true, + 917517 => true, + 917518 => true, + 917519 => true, + 917520 => true, + 917521 => true, + 917522 => true, + 917523 => true, + 917524 => true, + 917525 => true, + 917526 => true, + 917527 => true, + 917528 => true, + 917529 => true, + 917530 => true, + 917531 => true, + 917532 => true, + 917533 => true, + 917534 => true, + 917535 => true, + 983038 => true, + 983039 => true, + 1048574 => true, + 1048575 => true, + 1114110 => true, + 1114111 => true, +); diff --git a/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.php b/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.php new file mode 100644 index 0000000..54f21cc --- /dev/null +++ b/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_mapped.php @@ -0,0 +1,308 @@ + ' ', + 168 => ' ̈', + 175 => ' ̄', + 180 => ' ́', + 184 => ' ̧', + 728 => ' ̆', + 729 => ' ̇', + 730 => ' ̊', + 731 => ' ̨', + 732 => ' ̃', + 733 => ' ̋', + 890 => ' ι', + 894 => ';', + 900 => ' ́', + 901 => ' ̈́', + 8125 => ' ̓', + 8127 => ' ̓', + 8128 => ' ͂', + 8129 => ' ̈͂', + 8141 => ' ̓̀', + 8142 => ' ̓́', + 8143 => ' ̓͂', + 8157 => ' ̔̀', + 8158 => ' ̔́', + 8159 => ' ̔͂', + 8173 => ' ̈̀', + 8174 => ' ̈́', + 8175 => '`', + 8189 => ' ́', + 8190 => ' ̔', + 8192 => ' ', + 8193 => ' ', + 8194 => ' ', + 8195 => ' ', + 8196 => ' ', + 8197 => ' ', + 8198 => ' ', + 8199 => ' ', + 8200 => ' ', + 8201 => ' ', + 8202 => ' ', + 8215 => ' ̳', + 8239 => ' ', + 8252 => '!!', + 8254 => ' ̅', + 8263 => '??', + 8264 => '?!', + 8265 => '!?', + 8287 => ' ', + 8314 => '+', + 8316 => '=', + 8317 => '(', + 8318 => ')', + 8330 => '+', + 8332 => '=', + 8333 => '(', + 8334 => ')', + 8448 => 'a/c', + 8449 => 'a/s', + 8453 => 'c/o', + 8454 => 'c/u', + 9332 => '(1)', + 9333 => '(2)', + 9334 => '(3)', + 9335 => '(4)', + 9336 => '(5)', + 9337 => '(6)', + 9338 => '(7)', + 9339 => '(8)', + 9340 => '(9)', + 9341 => '(10)', + 9342 => '(11)', + 9343 => '(12)', + 9344 => '(13)', + 9345 => '(14)', + 9346 => '(15)', + 9347 => '(16)', + 9348 => '(17)', + 9349 => '(18)', + 9350 => '(19)', + 9351 => '(20)', + 9372 => '(a)', + 9373 => '(b)', + 9374 => '(c)', + 9375 => '(d)', + 9376 => '(e)', + 9377 => '(f)', + 9378 => '(g)', + 9379 => '(h)', + 9380 => '(i)', + 9381 => '(j)', + 9382 => '(k)', + 9383 => '(l)', + 9384 => '(m)', + 9385 => '(n)', + 9386 => '(o)', + 9387 => '(p)', + 9388 => '(q)', + 9389 => '(r)', + 9390 => '(s)', + 9391 => '(t)', + 9392 => '(u)', + 9393 => '(v)', + 9394 => '(w)', + 9395 => '(x)', + 9396 => '(y)', + 9397 => '(z)', + 10868 => '::=', + 10869 => '==', + 10870 => '===', + 12288 => ' ', + 12443 => ' ゙', + 12444 => ' ゚', + 12800 => '(ᄀ)', + 12801 => '(ᄂ)', + 12802 => '(ᄃ)', + 12803 => '(ᄅ)', + 12804 => '(ᄆ)', + 12805 => '(ᄇ)', + 12806 => '(ᄉ)', + 12807 => '(ᄋ)', + 12808 => '(ᄌ)', + 12809 => '(ᄎ)', + 12810 => '(ᄏ)', + 12811 => '(ᄐ)', + 12812 => '(ᄑ)', + 12813 => '(ᄒ)', + 12814 => '(가)', + 12815 => '(나)', + 12816 => '(다)', + 12817 => '(라)', + 12818 => '(마)', + 12819 => '(바)', + 12820 => '(사)', + 12821 => '(아)', + 12822 => '(자)', + 12823 => '(차)', + 12824 => '(카)', + 12825 => '(타)', + 12826 => '(파)', + 12827 => '(하)', + 12828 => '(주)', + 12829 => '(오전)', + 12830 => '(오후)', + 12832 => '(一)', + 12833 => '(二)', + 12834 => '(三)', + 12835 => '(四)', + 12836 => '(五)', + 12837 => '(六)', + 12838 => '(七)', + 12839 => '(八)', + 12840 => '(九)', + 12841 => '(十)', + 12842 => '(月)', + 12843 => '(火)', + 12844 => '(水)', + 12845 => '(木)', + 12846 => '(金)', + 12847 => '(土)', + 12848 => '(日)', + 12849 => '(株)', + 12850 => '(有)', + 12851 => '(社)', + 12852 => '(名)', + 12853 => '(特)', + 12854 => '(財)', + 12855 => '(祝)', + 12856 => '(労)', + 12857 => '(代)', + 12858 => '(呼)', + 12859 => '(学)', + 12860 => '(監)', + 12861 => '(企)', + 12862 => '(資)', + 12863 => '(協)', + 12864 => '(祭)', + 12865 => '(休)', + 12866 => '(自)', + 12867 => '(至)', + 64297 => '+', + 64606 => ' ٌّ', + 64607 => ' ٍّ', + 64608 => ' َّ', + 64609 => ' ُّ', + 64610 => ' ِّ', + 64611 => ' ّٰ', + 65018 => 'صلى الله عليه وسلم', + 65019 => 'جل جلاله', + 65040 => ',', + 65043 => ':', + 65044 => ';', + 65045 => '!', + 65046 => '?', + 65075 => '_', + 65076 => '_', + 65077 => '(', + 65078 => ')', + 65079 => '{', + 65080 => '}', + 65095 => '[', + 65096 => ']', + 65097 => ' ̅', + 65098 => ' ̅', + 65099 => ' ̅', + 65100 => ' ̅', + 65101 => '_', + 65102 => '_', + 65103 => '_', + 65104 => ',', + 65108 => ';', + 65109 => ':', + 65110 => '?', + 65111 => '!', + 65113 => '(', + 65114 => ')', + 65115 => '{', + 65116 => '}', + 65119 => '#', + 65120 => '&', + 65121 => '*', + 65122 => '+', + 65124 => '<', + 65125 => '>', + 65126 => '=', + 65128 => '\\', + 65129 => '$', + 65130 => '%', + 65131 => '@', + 65136 => ' ً', + 65138 => ' ٌ', + 65140 => ' ٍ', + 65142 => ' َ', + 65144 => ' ُ', + 65146 => ' ِ', + 65148 => ' ّ', + 65150 => ' ْ', + 65281 => '!', + 65282 => '"', + 65283 => '#', + 65284 => '$', + 65285 => '%', + 65286 => '&', + 65287 => '\'', + 65288 => '(', + 65289 => ')', + 65290 => '*', + 65291 => '+', + 65292 => ',', + 65295 => '/', + 65306 => ':', + 65307 => ';', + 65308 => '<', + 65309 => '=', + 65310 => '>', + 65311 => '?', + 65312 => '@', + 65339 => '[', + 65340 => '\\', + 65341 => ']', + 65342 => '^', + 65343 => '_', + 65344 => '`', + 65371 => '{', + 65372 => '|', + 65373 => '}', + 65374 => '~', + 65507 => ' ̄', + 127233 => '0,', + 127234 => '1,', + 127235 => '2,', + 127236 => '3,', + 127237 => '4,', + 127238 => '5,', + 127239 => '6,', + 127240 => '7,', + 127241 => '8,', + 127242 => '9,', + 127248 => '(a)', + 127249 => '(b)', + 127250 => '(c)', + 127251 => '(d)', + 127252 => '(e)', + 127253 => '(f)', + 127254 => '(g)', + 127255 => '(h)', + 127256 => '(i)', + 127257 => '(j)', + 127258 => '(k)', + 127259 => '(l)', + 127260 => '(m)', + 127261 => '(n)', + 127262 => '(o)', + 127263 => '(p)', + 127264 => '(q)', + 127265 => '(r)', + 127266 => '(s)', + 127267 => '(t)', + 127268 => '(u)', + 127269 => '(v)', + 127270 => '(w)', + 127271 => '(x)', + 127272 => '(y)', + 127273 => '(z)', +); diff --git a/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php b/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php new file mode 100644 index 0000000..223396e --- /dev/null +++ b/vendor/symfony/polyfill-intl-idn/Resources/unidata/disallowed_STD3_valid.php @@ -0,0 +1,71 @@ + true, + 1 => true, + 2 => true, + 3 => true, + 4 => true, + 5 => true, + 6 => true, + 7 => true, + 8 => true, + 9 => true, + 10 => true, + 11 => true, + 12 => true, + 13 => true, + 14 => true, + 15 => true, + 16 => true, + 17 => true, + 18 => true, + 19 => true, + 20 => true, + 21 => true, + 22 => true, + 23 => true, + 24 => true, + 25 => true, + 26 => true, + 27 => true, + 28 => true, + 29 => true, + 30 => true, + 31 => true, + 32 => true, + 33 => true, + 34 => true, + 35 => true, + 36 => true, + 37 => true, + 38 => true, + 39 => true, + 40 => true, + 41 => true, + 42 => true, + 43 => true, + 44 => true, + 47 => true, + 58 => true, + 59 => true, + 60 => true, + 61 => true, + 62 => true, + 63 => true, + 64 => true, + 91 => true, + 92 => true, + 93 => true, + 94 => true, + 95 => true, + 96 => true, + 123 => true, + 124 => true, + 125 => true, + 126 => true, + 127 => true, + 8800 => true, + 8814 => true, + 8815 => true, +); diff --git a/vendor/symfony/polyfill-intl-idn/Resources/unidata/ignored.php b/vendor/symfony/polyfill-intl-idn/Resources/unidata/ignored.php new file mode 100644 index 0000000..b377844 --- /dev/null +++ b/vendor/symfony/polyfill-intl-idn/Resources/unidata/ignored.php @@ -0,0 +1,273 @@ + true, + 847 => true, + 6155 => true, + 6156 => true, + 6157 => true, + 8203 => true, + 8288 => true, + 8292 => true, + 65024 => true, + 65025 => true, + 65026 => true, + 65027 => true, + 65028 => true, + 65029 => true, + 65030 => true, + 65031 => true, + 65032 => true, + 65033 => true, + 65034 => true, + 65035 => true, + 65036 => true, + 65037 => true, + 65038 => true, + 65039 => true, + 65279 => true, + 113824 => true, + 113825 => true, + 113826 => true, + 113827 => true, + 917760 => true, + 917761 => true, + 917762 => true, + 917763 => true, + 917764 => true, + 917765 => true, + 917766 => true, + 917767 => true, + 917768 => true, + 917769 => true, + 917770 => true, + 917771 => true, + 917772 => true, + 917773 => true, + 917774 => true, + 917775 => true, + 917776 => true, + 917777 => true, + 917778 => true, + 917779 => true, + 917780 => true, + 917781 => true, + 917782 => true, + 917783 => true, + 917784 => true, + 917785 => true, + 917786 => true, + 917787 => true, + 917788 => true, + 917789 => true, + 917790 => true, + 917791 => true, + 917792 => true, + 917793 => true, + 917794 => true, + 917795 => true, + 917796 => true, + 917797 => true, + 917798 => true, + 917799 => true, + 917800 => true, + 917801 => true, + 917802 => true, + 917803 => true, + 917804 => true, + 917805 => true, + 917806 => true, + 917807 => true, + 917808 => true, + 917809 => true, + 917810 => true, + 917811 => true, + 917812 => true, + 917813 => true, + 917814 => true, + 917815 => true, + 917816 => true, + 917817 => true, + 917818 => true, + 917819 => true, + 917820 => true, + 917821 => true, + 917822 => true, + 917823 => true, + 917824 => true, + 917825 => true, + 917826 => true, + 917827 => true, + 917828 => true, + 917829 => true, + 917830 => true, + 917831 => true, + 917832 => true, + 917833 => true, + 917834 => true, + 917835 => true, + 917836 => true, + 917837 => true, + 917838 => true, + 917839 => true, + 917840 => true, + 917841 => true, + 917842 => true, + 917843 => true, + 917844 => true, + 917845 => true, + 917846 => true, + 917847 => true, + 917848 => true, + 917849 => true, + 917850 => true, + 917851 => true, + 917852 => true, + 917853 => true, + 917854 => true, + 917855 => true, + 917856 => true, + 917857 => true, + 917858 => true, + 917859 => true, + 917860 => true, + 917861 => true, + 917862 => true, + 917863 => true, + 917864 => true, + 917865 => true, + 917866 => true, + 917867 => true, + 917868 => true, + 917869 => true, + 917870 => true, + 917871 => true, + 917872 => true, + 917873 => true, + 917874 => true, + 917875 => true, + 917876 => true, + 917877 => true, + 917878 => true, + 917879 => true, + 917880 => true, + 917881 => true, + 917882 => true, + 917883 => true, + 917884 => true, + 917885 => true, + 917886 => true, + 917887 => true, + 917888 => true, + 917889 => true, + 917890 => true, + 917891 => true, + 917892 => true, + 917893 => true, + 917894 => true, + 917895 => true, + 917896 => true, + 917897 => true, + 917898 => true, + 917899 => true, + 917900 => true, + 917901 => true, + 917902 => true, + 917903 => true, + 917904 => true, + 917905 => true, + 917906 => true, + 917907 => true, + 917908 => true, + 917909 => true, + 917910 => true, + 917911 => true, + 917912 => true, + 917913 => true, + 917914 => true, + 917915 => true, + 917916 => true, + 917917 => true, + 917918 => true, + 917919 => true, + 917920 => true, + 917921 => true, + 917922 => true, + 917923 => true, + 917924 => true, + 917925 => true, + 917926 => true, + 917927 => true, + 917928 => true, + 917929 => true, + 917930 => true, + 917931 => true, + 917932 => true, + 917933 => true, + 917934 => true, + 917935 => true, + 917936 => true, + 917937 => true, + 917938 => true, + 917939 => true, + 917940 => true, + 917941 => true, + 917942 => true, + 917943 => true, + 917944 => true, + 917945 => true, + 917946 => true, + 917947 => true, + 917948 => true, + 917949 => true, + 917950 => true, + 917951 => true, + 917952 => true, + 917953 => true, + 917954 => true, + 917955 => true, + 917956 => true, + 917957 => true, + 917958 => true, + 917959 => true, + 917960 => true, + 917961 => true, + 917962 => true, + 917963 => true, + 917964 => true, + 917965 => true, + 917966 => true, + 917967 => true, + 917968 => true, + 917969 => true, + 917970 => true, + 917971 => true, + 917972 => true, + 917973 => true, + 917974 => true, + 917975 => true, + 917976 => true, + 917977 => true, + 917978 => true, + 917979 => true, + 917980 => true, + 917981 => true, + 917982 => true, + 917983 => true, + 917984 => true, + 917985 => true, + 917986 => true, + 917987 => true, + 917988 => true, + 917989 => true, + 917990 => true, + 917991 => true, + 917992 => true, + 917993 => true, + 917994 => true, + 917995 => true, + 917996 => true, + 917997 => true, + 917998 => true, + 917999 => true, +); diff --git a/vendor/symfony/polyfill-intl-idn/Resources/unidata/mapped.php b/vendor/symfony/polyfill-intl-idn/Resources/unidata/mapped.php new file mode 100644 index 0000000..9b85fe9 --- /dev/null +++ b/vendor/symfony/polyfill-intl-idn/Resources/unidata/mapped.php @@ -0,0 +1,5778 @@ + 'a', + 66 => 'b', + 67 => 'c', + 68 => 'd', + 69 => 'e', + 70 => 'f', + 71 => 'g', + 72 => 'h', + 73 => 'i', + 74 => 'j', + 75 => 'k', + 76 => 'l', + 77 => 'm', + 78 => 'n', + 79 => 'o', + 80 => 'p', + 81 => 'q', + 82 => 'r', + 83 => 's', + 84 => 't', + 85 => 'u', + 86 => 'v', + 87 => 'w', + 88 => 'x', + 89 => 'y', + 90 => 'z', + 170 => 'a', + 178 => '2', + 179 => '3', + 181 => 'μ', + 185 => '1', + 186 => 'o', + 188 => '1⁄4', + 189 => '1⁄2', + 190 => '3⁄4', + 192 => 'à', + 193 => 'á', + 194 => 'â', + 195 => 'ã', + 196 => 'ä', + 197 => 'å', + 198 => 'æ', + 199 => 'ç', + 200 => 'è', + 201 => 'é', + 202 => 'ê', + 203 => 'ë', + 204 => 'ì', + 205 => 'í', + 206 => 'î', + 207 => 'ï', + 208 => 'ð', + 209 => 'ñ', + 210 => 'ò', + 211 => 'ó', + 212 => 'ô', + 213 => 'õ', + 214 => 'ö', + 216 => 'ø', + 217 => 'ù', + 218 => 'ú', + 219 => 'û', + 220 => 'ü', + 221 => 'ý', + 222 => 'þ', + 256 => 'ā', + 258 => 'ă', + 260 => 'ą', + 262 => 'ć', + 264 => 'ĉ', + 266 => 'ċ', + 268 => 'č', + 270 => 'ď', + 272 => 'đ', + 274 => 'ē', + 276 => 'ĕ', + 278 => 'ė', + 280 => 'ę', + 282 => 'ě', + 284 => 'ĝ', + 286 => 'ğ', + 288 => 'ġ', + 290 => 'ģ', + 292 => 'ĥ', + 294 => 'ħ', + 296 => 'ĩ', + 298 => 'ī', + 300 => 'ĭ', + 302 => 'į', + 304 => 'i̇', + 306 => 'ij', + 307 => 'ij', + 308 => 'ĵ', + 310 => 'ķ', + 313 => 'ĺ', + 315 => 'ļ', + 317 => 'ľ', + 319 => 'l·', + 320 => 'l·', + 321 => 'ł', + 323 => 'ń', + 325 => 'ņ', + 327 => 'ň', + 329 => 'ʼn', + 330 => 'ŋ', + 332 => 'ō', + 334 => 'ŏ', + 336 => 'ő', + 338 => 'œ', + 340 => 'ŕ', + 342 => 'ŗ', + 344 => 'ř', + 346 => 'ś', + 348 => 'ŝ', + 350 => 'ş', + 352 => 'š', + 354 => 'ţ', + 356 => 'ť', + 358 => 'ŧ', + 360 => 'ũ', + 362 => 'ū', + 364 => 'ŭ', + 366 => 'ů', + 368 => 'ű', + 370 => 'ų', + 372 => 'ŵ', + 374 => 'ŷ', + 376 => 'ÿ', + 377 => 'ź', + 379 => 'ż', + 381 => 'ž', + 383 => 's', + 385 => 'ɓ', + 386 => 'ƃ', + 388 => 'ƅ', + 390 => 'ɔ', + 391 => 'ƈ', + 393 => 'ɖ', + 394 => 'ɗ', + 395 => 'ƌ', + 398 => 'ǝ', + 399 => 'ə', + 400 => 'ɛ', + 401 => 'ƒ', + 403 => 'ɠ', + 404 => 'ɣ', + 406 => 'ɩ', + 407 => 'ɨ', + 408 => 'ƙ', + 412 => 'ɯ', + 413 => 'ɲ', + 415 => 'ɵ', + 416 => 'ơ', + 418 => 'ƣ', + 420 => 'ƥ', + 422 => 'ʀ', + 423 => 'ƨ', + 425 => 'ʃ', + 428 => 'ƭ', + 430 => 'ʈ', + 431 => 'ư', + 433 => 'ʊ', + 434 => 'ʋ', + 435 => 'ƴ', + 437 => 'ƶ', + 439 => 'ʒ', + 440 => 'ƹ', + 444 => 'ƽ', + 452 => 'dž', + 453 => 'dž', + 454 => 'dž', + 455 => 'lj', + 456 => 'lj', + 457 => 'lj', + 458 => 'nj', + 459 => 'nj', + 460 => 'nj', + 461 => 'ǎ', + 463 => 'ǐ', + 465 => 'ǒ', + 467 => 'ǔ', + 469 => 'ǖ', + 471 => 'ǘ', + 473 => 'ǚ', + 475 => 'ǜ', + 478 => 'ǟ', + 480 => 'ǡ', + 482 => 'ǣ', + 484 => 'ǥ', + 486 => 'ǧ', + 488 => 'ǩ', + 490 => 'ǫ', + 492 => 'ǭ', + 494 => 'ǯ', + 497 => 'dz', + 498 => 'dz', + 499 => 'dz', + 500 => 'ǵ', + 502 => 'ƕ', + 503 => 'ƿ', + 504 => 'ǹ', + 506 => 'ǻ', + 508 => 'ǽ', + 510 => 'ǿ', + 512 => 'ȁ', + 514 => 'ȃ', + 516 => 'ȅ', + 518 => 'ȇ', + 520 => 'ȉ', + 522 => 'ȋ', + 524 => 'ȍ', + 526 => 'ȏ', + 528 => 'ȑ', + 530 => 'ȓ', + 532 => 'ȕ', + 534 => 'ȗ', + 536 => 'ș', + 538 => 'ț', + 540 => 'ȝ', + 542 => 'ȟ', + 544 => 'ƞ', + 546 => 'ȣ', + 548 => 'ȥ', + 550 => 'ȧ', + 552 => 'ȩ', + 554 => 'ȫ', + 556 => 'ȭ', + 558 => 'ȯ', + 560 => 'ȱ', + 562 => 'ȳ', + 570 => 'ⱥ', + 571 => 'ȼ', + 573 => 'ƚ', + 574 => 'ⱦ', + 577 => 'ɂ', + 579 => 'ƀ', + 580 => 'ʉ', + 581 => 'ʌ', + 582 => 'ɇ', + 584 => 'ɉ', + 586 => 'ɋ', + 588 => 'ɍ', + 590 => 'ɏ', + 688 => 'h', + 689 => 'ɦ', + 690 => 'j', + 691 => 'r', + 692 => 'ɹ', + 693 => 'ɻ', + 694 => 'ʁ', + 695 => 'w', + 696 => 'y', + 736 => 'ɣ', + 737 => 'l', + 738 => 's', + 739 => 'x', + 740 => 'ʕ', + 832 => '̀', + 833 => '́', + 835 => '̓', + 836 => '̈́', + 837 => 'ι', + 880 => 'ͱ', + 882 => 'ͳ', + 884 => 'ʹ', + 886 => 'ͷ', + 895 => 'ϳ', + 902 => 'ά', + 903 => '·', + 904 => 'έ', + 905 => 'ή', + 906 => 'ί', + 908 => 'ό', + 910 => 'ύ', + 911 => 'ώ', + 913 => 'α', + 914 => 'β', + 915 => 'γ', + 916 => 'δ', + 917 => 'ε', + 918 => 'ζ', + 919 => 'η', + 920 => 'θ', + 921 => 'ι', + 922 => 'κ', + 923 => 'λ', + 924 => 'μ', + 925 => 'ν', + 926 => 'ξ', + 927 => 'ο', + 928 => 'π', + 929 => 'ρ', + 931 => 'σ', + 932 => 'τ', + 933 => 'υ', + 934 => 'φ', + 935 => 'χ', + 936 => 'ψ', + 937 => 'ω', + 938 => 'ϊ', + 939 => 'ϋ', + 975 => 'ϗ', + 976 => 'β', + 977 => 'θ', + 978 => 'υ', + 979 => 'ύ', + 980 => 'ϋ', + 981 => 'φ', + 982 => 'π', + 984 => 'ϙ', + 986 => 'ϛ', + 988 => 'ϝ', + 990 => 'ϟ', + 992 => 'ϡ', + 994 => 'ϣ', + 996 => 'ϥ', + 998 => 'ϧ', + 1000 => 'ϩ', + 1002 => 'ϫ', + 1004 => 'ϭ', + 1006 => 'ϯ', + 1008 => 'κ', + 1009 => 'ρ', + 1010 => 'σ', + 1012 => 'θ', + 1013 => 'ε', + 1015 => 'ϸ', + 1017 => 'σ', + 1018 => 'ϻ', + 1021 => 'ͻ', + 1022 => 'ͼ', + 1023 => 'ͽ', + 1024 => 'ѐ', + 1025 => 'ё', + 1026 => 'ђ', + 1027 => 'ѓ', + 1028 => 'є', + 1029 => 'ѕ', + 1030 => 'і', + 1031 => 'ї', + 1032 => 'ј', + 1033 => 'љ', + 1034 => 'њ', + 1035 => 'ћ', + 1036 => 'ќ', + 1037 => 'ѝ', + 1038 => 'ў', + 1039 => 'џ', + 1040 => 'а', + 1041 => 'б', + 1042 => 'в', + 1043 => 'г', + 1044 => 'д', + 1045 => 'е', + 1046 => 'ж', + 1047 => 'з', + 1048 => 'и', + 1049 => 'й', + 1050 => 'к', + 1051 => 'л', + 1052 => 'м', + 1053 => 'н', + 1054 => 'о', + 1055 => 'п', + 1056 => 'р', + 1057 => 'с', + 1058 => 'т', + 1059 => 'у', + 1060 => 'ф', + 1061 => 'х', + 1062 => 'ц', + 1063 => 'ч', + 1064 => 'ш', + 1065 => 'щ', + 1066 => 'ъ', + 1067 => 'ы', + 1068 => 'ь', + 1069 => 'э', + 1070 => 'ю', + 1071 => 'я', + 1120 => 'ѡ', + 1122 => 'ѣ', + 1124 => 'ѥ', + 1126 => 'ѧ', + 1128 => 'ѩ', + 1130 => 'ѫ', + 1132 => 'ѭ', + 1134 => 'ѯ', + 1136 => 'ѱ', + 1138 => 'ѳ', + 1140 => 'ѵ', + 1142 => 'ѷ', + 1144 => 'ѹ', + 1146 => 'ѻ', + 1148 => 'ѽ', + 1150 => 'ѿ', + 1152 => 'ҁ', + 1162 => 'ҋ', + 1164 => 'ҍ', + 1166 => 'ҏ', + 1168 => 'ґ', + 1170 => 'ғ', + 1172 => 'ҕ', + 1174 => 'җ', + 1176 => 'ҙ', + 1178 => 'қ', + 1180 => 'ҝ', + 1182 => 'ҟ', + 1184 => 'ҡ', + 1186 => 'ң', + 1188 => 'ҥ', + 1190 => 'ҧ', + 1192 => 'ҩ', + 1194 => 'ҫ', + 1196 => 'ҭ', + 1198 => 'ү', + 1200 => 'ұ', + 1202 => 'ҳ', + 1204 => 'ҵ', + 1206 => 'ҷ', + 1208 => 'ҹ', + 1210 => 'һ', + 1212 => 'ҽ', + 1214 => 'ҿ', + 1217 => 'ӂ', + 1219 => 'ӄ', + 1221 => 'ӆ', + 1223 => 'ӈ', + 1225 => 'ӊ', + 1227 => 'ӌ', + 1229 => 'ӎ', + 1232 => 'ӑ', + 1234 => 'ӓ', + 1236 => 'ӕ', + 1238 => 'ӗ', + 1240 => 'ә', + 1242 => 'ӛ', + 1244 => 'ӝ', + 1246 => 'ӟ', + 1248 => 'ӡ', + 1250 => 'ӣ', + 1252 => 'ӥ', + 1254 => 'ӧ', + 1256 => 'ө', + 1258 => 'ӫ', + 1260 => 'ӭ', + 1262 => 'ӯ', + 1264 => 'ӱ', + 1266 => 'ӳ', + 1268 => 'ӵ', + 1270 => 'ӷ', + 1272 => 'ӹ', + 1274 => 'ӻ', + 1276 => 'ӽ', + 1278 => 'ӿ', + 1280 => 'ԁ', + 1282 => 'ԃ', + 1284 => 'ԅ', + 1286 => 'ԇ', + 1288 => 'ԉ', + 1290 => 'ԋ', + 1292 => 'ԍ', + 1294 => 'ԏ', + 1296 => 'ԑ', + 1298 => 'ԓ', + 1300 => 'ԕ', + 1302 => 'ԗ', + 1304 => 'ԙ', + 1306 => 'ԛ', + 1308 => 'ԝ', + 1310 => 'ԟ', + 1312 => 'ԡ', + 1314 => 'ԣ', + 1316 => 'ԥ', + 1318 => 'ԧ', + 1320 => 'ԩ', + 1322 => 'ԫ', + 1324 => 'ԭ', + 1326 => 'ԯ', + 1329 => 'ա', + 1330 => 'բ', + 1331 => 'գ', + 1332 => 'դ', + 1333 => 'ե', + 1334 => 'զ', + 1335 => 'է', + 1336 => 'ը', + 1337 => 'թ', + 1338 => 'ժ', + 1339 => 'ի', + 1340 => 'լ', + 1341 => 'խ', + 1342 => 'ծ', + 1343 => 'կ', + 1344 => 'հ', + 1345 => 'ձ', + 1346 => 'ղ', + 1347 => 'ճ', + 1348 => 'մ', + 1349 => 'յ', + 1350 => 'ն', + 1351 => 'շ', + 1352 => 'ո', + 1353 => 'չ', + 1354 => 'պ', + 1355 => 'ջ', + 1356 => 'ռ', + 1357 => 'ս', + 1358 => 'վ', + 1359 => 'տ', + 1360 => 'ր', + 1361 => 'ց', + 1362 => 'ւ', + 1363 => 'փ', + 1364 => 'ք', + 1365 => 'օ', + 1366 => 'ֆ', + 1415 => 'եւ', + 1653 => 'اٴ', + 1654 => 'وٴ', + 1655 => 'ۇٴ', + 1656 => 'يٴ', + 2392 => 'क़', + 2393 => 'ख़', + 2394 => 'ग़', + 2395 => 'ज़', + 2396 => 'ड़', + 2397 => 'ढ़', + 2398 => 'फ़', + 2399 => 'य़', + 2524 => 'ড়', + 2525 => 'ঢ়', + 2527 => 'য়', + 2611 => 'ਲ਼', + 2614 => 'ਸ਼', + 2649 => 'ਖ਼', + 2650 => 'ਗ਼', + 2651 => 'ਜ਼', + 2654 => 'ਫ਼', + 2908 => 'ଡ଼', + 2909 => 'ଢ଼', + 3635 => 'ํา', + 3763 => 'ໍາ', + 3804 => 'ຫນ', + 3805 => 'ຫມ', + 3852 => '་', + 3907 => 'གྷ', + 3917 => 'ཌྷ', + 3922 => 'དྷ', + 3927 => 'བྷ', + 3932 => 'ཛྷ', + 3945 => 'ཀྵ', + 3955 => 'ཱི', + 3957 => 'ཱུ', + 3958 => 'ྲྀ', + 3959 => 'ྲཱྀ', + 3960 => 'ླྀ', + 3961 => 'ླཱྀ', + 3969 => 'ཱྀ', + 3987 => 'ྒྷ', + 3997 => 'ྜྷ', + 4002 => 'ྡྷ', + 4007 => 'ྦྷ', + 4012 => 'ྫྷ', + 4025 => 'ྐྵ', + 4295 => 'ⴧ', + 4301 => 'ⴭ', + 4348 => 'ნ', + 5112 => 'Ᏸ', + 5113 => 'Ᏹ', + 5114 => 'Ᏺ', + 5115 => 'Ᏻ', + 5116 => 'Ᏼ', + 5117 => 'Ᏽ', + 7296 => 'в', + 7297 => 'д', + 7298 => 'о', + 7299 => 'с', + 7300 => 'т', + 7301 => 'т', + 7302 => 'ъ', + 7303 => 'ѣ', + 7304 => 'ꙋ', + 7312 => 'ა', + 7313 => 'ბ', + 7314 => 'გ', + 7315 => 'დ', + 7316 => 'ე', + 7317 => 'ვ', + 7318 => 'ზ', + 7319 => 'თ', + 7320 => 'ი', + 7321 => 'კ', + 7322 => 'ლ', + 7323 => 'მ', + 7324 => 'ნ', + 7325 => 'ო', + 7326 => 'პ', + 7327 => 'ჟ', + 7328 => 'რ', + 7329 => 'ს', + 7330 => 'ტ', + 7331 => 'უ', + 7332 => 'ფ', + 7333 => 'ქ', + 7334 => 'ღ', + 7335 => 'ყ', + 7336 => 'შ', + 7337 => 'ჩ', + 7338 => 'ც', + 7339 => 'ძ', + 7340 => 'წ', + 7341 => 'ჭ', + 7342 => 'ხ', + 7343 => 'ჯ', + 7344 => 'ჰ', + 7345 => 'ჱ', + 7346 => 'ჲ', + 7347 => 'ჳ', + 7348 => 'ჴ', + 7349 => 'ჵ', + 7350 => 'ჶ', + 7351 => 'ჷ', + 7352 => 'ჸ', + 7353 => 'ჹ', + 7354 => 'ჺ', + 7357 => 'ჽ', + 7358 => 'ჾ', + 7359 => 'ჿ', + 7468 => 'a', + 7469 => 'æ', + 7470 => 'b', + 7472 => 'd', + 7473 => 'e', + 7474 => 'ǝ', + 7475 => 'g', + 7476 => 'h', + 7477 => 'i', + 7478 => 'j', + 7479 => 'k', + 7480 => 'l', + 7481 => 'm', + 7482 => 'n', + 7484 => 'o', + 7485 => 'ȣ', + 7486 => 'p', + 7487 => 'r', + 7488 => 't', + 7489 => 'u', + 7490 => 'w', + 7491 => 'a', + 7492 => 'ɐ', + 7493 => 'ɑ', + 7494 => 'ᴂ', + 7495 => 'b', + 7496 => 'd', + 7497 => 'e', + 7498 => 'ə', + 7499 => 'ɛ', + 7500 => 'ɜ', + 7501 => 'g', + 7503 => 'k', + 7504 => 'm', + 7505 => 'ŋ', + 7506 => 'o', + 7507 => 'ɔ', + 7508 => 'ᴖ', + 7509 => 'ᴗ', + 7510 => 'p', + 7511 => 't', + 7512 => 'u', + 7513 => 'ᴝ', + 7514 => 'ɯ', + 7515 => 'v', + 7516 => 'ᴥ', + 7517 => 'β', + 7518 => 'γ', + 7519 => 'δ', + 7520 => 'φ', + 7521 => 'χ', + 7522 => 'i', + 7523 => 'r', + 7524 => 'u', + 7525 => 'v', + 7526 => 'β', + 7527 => 'γ', + 7528 => 'ρ', + 7529 => 'φ', + 7530 => 'χ', + 7544 => 'н', + 7579 => 'ɒ', + 7580 => 'c', + 7581 => 'ɕ', + 7582 => 'ð', + 7583 => 'ɜ', + 7584 => 'f', + 7585 => 'ɟ', + 7586 => 'ɡ', + 7587 => 'ɥ', + 7588 => 'ɨ', + 7589 => 'ɩ', + 7590 => 'ɪ', + 7591 => 'ᵻ', + 7592 => 'ʝ', + 7593 => 'ɭ', + 7594 => 'ᶅ', + 7595 => 'ʟ', + 7596 => 'ɱ', + 7597 => 'ɰ', + 7598 => 'ɲ', + 7599 => 'ɳ', + 7600 => 'ɴ', + 7601 => 'ɵ', + 7602 => 'ɸ', + 7603 => 'ʂ', + 7604 => 'ʃ', + 7605 => 'ƫ', + 7606 => 'ʉ', + 7607 => 'ʊ', + 7608 => 'ᴜ', + 7609 => 'ʋ', + 7610 => 'ʌ', + 7611 => 'z', + 7612 => 'ʐ', + 7613 => 'ʑ', + 7614 => 'ʒ', + 7615 => 'θ', + 7680 => 'ḁ', + 7682 => 'ḃ', + 7684 => 'ḅ', + 7686 => 'ḇ', + 7688 => 'ḉ', + 7690 => 'ḋ', + 7692 => 'ḍ', + 7694 => 'ḏ', + 7696 => 'ḑ', + 7698 => 'ḓ', + 7700 => 'ḕ', + 7702 => 'ḗ', + 7704 => 'ḙ', + 7706 => 'ḛ', + 7708 => 'ḝ', + 7710 => 'ḟ', + 7712 => 'ḡ', + 7714 => 'ḣ', + 7716 => 'ḥ', + 7718 => 'ḧ', + 7720 => 'ḩ', + 7722 => 'ḫ', + 7724 => 'ḭ', + 7726 => 'ḯ', + 7728 => 'ḱ', + 7730 => 'ḳ', + 7732 => 'ḵ', + 7734 => 'ḷ', + 7736 => 'ḹ', + 7738 => 'ḻ', + 7740 => 'ḽ', + 7742 => 'ḿ', + 7744 => 'ṁ', + 7746 => 'ṃ', + 7748 => 'ṅ', + 7750 => 'ṇ', + 7752 => 'ṉ', + 7754 => 'ṋ', + 7756 => 'ṍ', + 7758 => 'ṏ', + 7760 => 'ṑ', + 7762 => 'ṓ', + 7764 => 'ṕ', + 7766 => 'ṗ', + 7768 => 'ṙ', + 7770 => 'ṛ', + 7772 => 'ṝ', + 7774 => 'ṟ', + 7776 => 'ṡ', + 7778 => 'ṣ', + 7780 => 'ṥ', + 7782 => 'ṧ', + 7784 => 'ṩ', + 7786 => 'ṫ', + 7788 => 'ṭ', + 7790 => 'ṯ', + 7792 => 'ṱ', + 7794 => 'ṳ', + 7796 => 'ṵ', + 7798 => 'ṷ', + 7800 => 'ṹ', + 7802 => 'ṻ', + 7804 => 'ṽ', + 7806 => 'ṿ', + 7808 => 'ẁ', + 7810 => 'ẃ', + 7812 => 'ẅ', + 7814 => 'ẇ', + 7816 => 'ẉ', + 7818 => 'ẋ', + 7820 => 'ẍ', + 7822 => 'ẏ', + 7824 => 'ẑ', + 7826 => 'ẓ', + 7828 => 'ẕ', + 7834 => 'aʾ', + 7835 => 'ṡ', + 7838 => 'ss', + 7840 => 'ạ', + 7842 => 'ả', + 7844 => 'ấ', + 7846 => 'ầ', + 7848 => 'ẩ', + 7850 => 'ẫ', + 7852 => 'ậ', + 7854 => 'ắ', + 7856 => 'ằ', + 7858 => 'ẳ', + 7860 => 'ẵ', + 7862 => 'ặ', + 7864 => 'ẹ', + 7866 => 'ẻ', + 7868 => 'ẽ', + 7870 => 'ế', + 7872 => 'ề', + 7874 => 'ể', + 7876 => 'ễ', + 7878 => 'ệ', + 7880 => 'ỉ', + 7882 => 'ị', + 7884 => 'ọ', + 7886 => 'ỏ', + 7888 => 'ố', + 7890 => 'ồ', + 7892 => 'ổ', + 7894 => 'ỗ', + 7896 => 'ộ', + 7898 => 'ớ', + 7900 => 'ờ', + 7902 => 'ở', + 7904 => 'ỡ', + 7906 => 'ợ', + 7908 => 'ụ', + 7910 => 'ủ', + 7912 => 'ứ', + 7914 => 'ừ', + 7916 => 'ử', + 7918 => 'ữ', + 7920 => 'ự', + 7922 => 'ỳ', + 7924 => 'ỵ', + 7926 => 'ỷ', + 7928 => 'ỹ', + 7930 => 'ỻ', + 7932 => 'ỽ', + 7934 => 'ỿ', + 7944 => 'ἀ', + 7945 => 'ἁ', + 7946 => 'ἂ', + 7947 => 'ἃ', + 7948 => 'ἄ', + 7949 => 'ἅ', + 7950 => 'ἆ', + 7951 => 'ἇ', + 7960 => 'ἐ', + 7961 => 'ἑ', + 7962 => 'ἒ', + 7963 => 'ἓ', + 7964 => 'ἔ', + 7965 => 'ἕ', + 7976 => 'ἠ', + 7977 => 'ἡ', + 7978 => 'ἢ', + 7979 => 'ἣ', + 7980 => 'ἤ', + 7981 => 'ἥ', + 7982 => 'ἦ', + 7983 => 'ἧ', + 7992 => 'ἰ', + 7993 => 'ἱ', + 7994 => 'ἲ', + 7995 => 'ἳ', + 7996 => 'ἴ', + 7997 => 'ἵ', + 7998 => 'ἶ', + 7999 => 'ἷ', + 8008 => 'ὀ', + 8009 => 'ὁ', + 8010 => 'ὂ', + 8011 => 'ὃ', + 8012 => 'ὄ', + 8013 => 'ὅ', + 8025 => 'ὑ', + 8027 => 'ὓ', + 8029 => 'ὕ', + 8031 => 'ὗ', + 8040 => 'ὠ', + 8041 => 'ὡ', + 8042 => 'ὢ', + 8043 => 'ὣ', + 8044 => 'ὤ', + 8045 => 'ὥ', + 8046 => 'ὦ', + 8047 => 'ὧ', + 8049 => 'ά', + 8051 => 'έ', + 8053 => 'ή', + 8055 => 'ί', + 8057 => 'ό', + 8059 => 'ύ', + 8061 => 'ώ', + 8064 => 'ἀι', + 8065 => 'ἁι', + 8066 => 'ἂι', + 8067 => 'ἃι', + 8068 => 'ἄι', + 8069 => 'ἅι', + 8070 => 'ἆι', + 8071 => 'ἇι', + 8072 => 'ἀι', + 8073 => 'ἁι', + 8074 => 'ἂι', + 8075 => 'ἃι', + 8076 => 'ἄι', + 8077 => 'ἅι', + 8078 => 'ἆι', + 8079 => 'ἇι', + 8080 => 'ἠι', + 8081 => 'ἡι', + 8082 => 'ἢι', + 8083 => 'ἣι', + 8084 => 'ἤι', + 8085 => 'ἥι', + 8086 => 'ἦι', + 8087 => 'ἧι', + 8088 => 'ἠι', + 8089 => 'ἡι', + 8090 => 'ἢι', + 8091 => 'ἣι', + 8092 => 'ἤι', + 8093 => 'ἥι', + 8094 => 'ἦι', + 8095 => 'ἧι', + 8096 => 'ὠι', + 8097 => 'ὡι', + 8098 => 'ὢι', + 8099 => 'ὣι', + 8100 => 'ὤι', + 8101 => 'ὥι', + 8102 => 'ὦι', + 8103 => 'ὧι', + 8104 => 'ὠι', + 8105 => 'ὡι', + 8106 => 'ὢι', + 8107 => 'ὣι', + 8108 => 'ὤι', + 8109 => 'ὥι', + 8110 => 'ὦι', + 8111 => 'ὧι', + 8114 => 'ὰι', + 8115 => 'αι', + 8116 => 'άι', + 8119 => 'ᾶι', + 8120 => 'ᾰ', + 8121 => 'ᾱ', + 8122 => 'ὰ', + 8123 => 'ά', + 8124 => 'αι', + 8126 => 'ι', + 8130 => 'ὴι', + 8131 => 'ηι', + 8132 => 'ήι', + 8135 => 'ῆι', + 8136 => 'ὲ', + 8137 => 'έ', + 8138 => 'ὴ', + 8139 => 'ή', + 8140 => 'ηι', + 8147 => 'ΐ', + 8152 => 'ῐ', + 8153 => 'ῑ', + 8154 => 'ὶ', + 8155 => 'ί', + 8163 => 'ΰ', + 8168 => 'ῠ', + 8169 => 'ῡ', + 8170 => 'ὺ', + 8171 => 'ύ', + 8172 => 'ῥ', + 8178 => 'ὼι', + 8179 => 'ωι', + 8180 => 'ώι', + 8183 => 'ῶι', + 8184 => 'ὸ', + 8185 => 'ό', + 8186 => 'ὼ', + 8187 => 'ώ', + 8188 => 'ωι', + 8209 => '‐', + 8243 => '′′', + 8244 => '′′′', + 8246 => '‵‵', + 8247 => '‵‵‵', + 8279 => '′′′′', + 8304 => '0', + 8305 => 'i', + 8308 => '4', + 8309 => '5', + 8310 => '6', + 8311 => '7', + 8312 => '8', + 8313 => '9', + 8315 => '−', + 8319 => 'n', + 8320 => '0', + 8321 => '1', + 8322 => '2', + 8323 => '3', + 8324 => '4', + 8325 => '5', + 8326 => '6', + 8327 => '7', + 8328 => '8', + 8329 => '9', + 8331 => '−', + 8336 => 'a', + 8337 => 'e', + 8338 => 'o', + 8339 => 'x', + 8340 => 'ə', + 8341 => 'h', + 8342 => 'k', + 8343 => 'l', + 8344 => 'm', + 8345 => 'n', + 8346 => 'p', + 8347 => 's', + 8348 => 't', + 8360 => 'rs', + 8450 => 'c', + 8451 => '°c', + 8455 => 'ɛ', + 8457 => '°f', + 8458 => 'g', + 8459 => 'h', + 8460 => 'h', + 8461 => 'h', + 8462 => 'h', + 8463 => 'ħ', + 8464 => 'i', + 8465 => 'i', + 8466 => 'l', + 8467 => 'l', + 8469 => 'n', + 8470 => 'no', + 8473 => 'p', + 8474 => 'q', + 8475 => 'r', + 8476 => 'r', + 8477 => 'r', + 8480 => 'sm', + 8481 => 'tel', + 8482 => 'tm', + 8484 => 'z', + 8486 => 'ω', + 8488 => 'z', + 8490 => 'k', + 8491 => 'å', + 8492 => 'b', + 8493 => 'c', + 8495 => 'e', + 8496 => 'e', + 8497 => 'f', + 8499 => 'm', + 8500 => 'o', + 8501 => 'א', + 8502 => 'ב', + 8503 => 'ג', + 8504 => 'ד', + 8505 => 'i', + 8507 => 'fax', + 8508 => 'π', + 8509 => 'γ', + 8510 => 'γ', + 8511 => 'π', + 8512 => '∑', + 8517 => 'd', + 8518 => 'd', + 8519 => 'e', + 8520 => 'i', + 8521 => 'j', + 8528 => '1⁄7', + 8529 => '1⁄9', + 8530 => '1⁄10', + 8531 => '1⁄3', + 8532 => '2⁄3', + 8533 => '1⁄5', + 8534 => '2⁄5', + 8535 => '3⁄5', + 8536 => '4⁄5', + 8537 => '1⁄6', + 8538 => '5⁄6', + 8539 => '1⁄8', + 8540 => '3⁄8', + 8541 => '5⁄8', + 8542 => '7⁄8', + 8543 => '1⁄', + 8544 => 'i', + 8545 => 'ii', + 8546 => 'iii', + 8547 => 'iv', + 8548 => 'v', + 8549 => 'vi', + 8550 => 'vii', + 8551 => 'viii', + 8552 => 'ix', + 8553 => 'x', + 8554 => 'xi', + 8555 => 'xii', + 8556 => 'l', + 8557 => 'c', + 8558 => 'd', + 8559 => 'm', + 8560 => 'i', + 8561 => 'ii', + 8562 => 'iii', + 8563 => 'iv', + 8564 => 'v', + 8565 => 'vi', + 8566 => 'vii', + 8567 => 'viii', + 8568 => 'ix', + 8569 => 'x', + 8570 => 'xi', + 8571 => 'xii', + 8572 => 'l', + 8573 => 'c', + 8574 => 'd', + 8575 => 'm', + 8585 => '0⁄3', + 8748 => '∫∫', + 8749 => '∫∫∫', + 8751 => '∮∮', + 8752 => '∮∮∮', + 9001 => '〈', + 9002 => '〉', + 9312 => '1', + 9313 => '2', + 9314 => '3', + 9315 => '4', + 9316 => '5', + 9317 => '6', + 9318 => '7', + 9319 => '8', + 9320 => '9', + 9321 => '10', + 9322 => '11', + 9323 => '12', + 9324 => '13', + 9325 => '14', + 9326 => '15', + 9327 => '16', + 9328 => '17', + 9329 => '18', + 9330 => '19', + 9331 => '20', + 9398 => 'a', + 9399 => 'b', + 9400 => 'c', + 9401 => 'd', + 9402 => 'e', + 9403 => 'f', + 9404 => 'g', + 9405 => 'h', + 9406 => 'i', + 9407 => 'j', + 9408 => 'k', + 9409 => 'l', + 9410 => 'm', + 9411 => 'n', + 9412 => 'o', + 9413 => 'p', + 9414 => 'q', + 9415 => 'r', + 9416 => 's', + 9417 => 't', + 9418 => 'u', + 9419 => 'v', + 9420 => 'w', + 9421 => 'x', + 9422 => 'y', + 9423 => 'z', + 9424 => 'a', + 9425 => 'b', + 9426 => 'c', + 9427 => 'd', + 9428 => 'e', + 9429 => 'f', + 9430 => 'g', + 9431 => 'h', + 9432 => 'i', + 9433 => 'j', + 9434 => 'k', + 9435 => 'l', + 9436 => 'm', + 9437 => 'n', + 9438 => 'o', + 9439 => 'p', + 9440 => 'q', + 9441 => 'r', + 9442 => 's', + 9443 => 't', + 9444 => 'u', + 9445 => 'v', + 9446 => 'w', + 9447 => 'x', + 9448 => 'y', + 9449 => 'z', + 9450 => '0', + 10764 => '∫∫∫∫', + 10972 => '⫝̸', + 11264 => 'ⰰ', + 11265 => 'ⰱ', + 11266 => 'ⰲ', + 11267 => 'ⰳ', + 11268 => 'ⰴ', + 11269 => 'ⰵ', + 11270 => 'ⰶ', + 11271 => 'ⰷ', + 11272 => 'ⰸ', + 11273 => 'ⰹ', + 11274 => 'ⰺ', + 11275 => 'ⰻ', + 11276 => 'ⰼ', + 11277 => 'ⰽ', + 11278 => 'ⰾ', + 11279 => 'ⰿ', + 11280 => 'ⱀ', + 11281 => 'ⱁ', + 11282 => 'ⱂ', + 11283 => 'ⱃ', + 11284 => 'ⱄ', + 11285 => 'ⱅ', + 11286 => 'ⱆ', + 11287 => 'ⱇ', + 11288 => 'ⱈ', + 11289 => 'ⱉ', + 11290 => 'ⱊ', + 11291 => 'ⱋ', + 11292 => 'ⱌ', + 11293 => 'ⱍ', + 11294 => 'ⱎ', + 11295 => 'ⱏ', + 11296 => 'ⱐ', + 11297 => 'ⱑ', + 11298 => 'ⱒ', + 11299 => 'ⱓ', + 11300 => 'ⱔ', + 11301 => 'ⱕ', + 11302 => 'ⱖ', + 11303 => 'ⱗ', + 11304 => 'ⱘ', + 11305 => 'ⱙ', + 11306 => 'ⱚ', + 11307 => 'ⱛ', + 11308 => 'ⱜ', + 11309 => 'ⱝ', + 11310 => 'ⱞ', + 11360 => 'ⱡ', + 11362 => 'ɫ', + 11363 => 'ᵽ', + 11364 => 'ɽ', + 11367 => 'ⱨ', + 11369 => 'ⱪ', + 11371 => 'ⱬ', + 11373 => 'ɑ', + 11374 => 'ɱ', + 11375 => 'ɐ', + 11376 => 'ɒ', + 11378 => 'ⱳ', + 11381 => 'ⱶ', + 11388 => 'j', + 11389 => 'v', + 11390 => 'ȿ', + 11391 => 'ɀ', + 11392 => 'ⲁ', + 11394 => 'ⲃ', + 11396 => 'ⲅ', + 11398 => 'ⲇ', + 11400 => 'ⲉ', + 11402 => 'ⲋ', + 11404 => 'ⲍ', + 11406 => 'ⲏ', + 11408 => 'ⲑ', + 11410 => 'ⲓ', + 11412 => 'ⲕ', + 11414 => 'ⲗ', + 11416 => 'ⲙ', + 11418 => 'ⲛ', + 11420 => 'ⲝ', + 11422 => 'ⲟ', + 11424 => 'ⲡ', + 11426 => 'ⲣ', + 11428 => 'ⲥ', + 11430 => 'ⲧ', + 11432 => 'ⲩ', + 11434 => 'ⲫ', + 11436 => 'ⲭ', + 11438 => 'ⲯ', + 11440 => 'ⲱ', + 11442 => 'ⲳ', + 11444 => 'ⲵ', + 11446 => 'ⲷ', + 11448 => 'ⲹ', + 11450 => 'ⲻ', + 11452 => 'ⲽ', + 11454 => 'ⲿ', + 11456 => 'ⳁ', + 11458 => 'ⳃ', + 11460 => 'ⳅ', + 11462 => 'ⳇ', + 11464 => 'ⳉ', + 11466 => 'ⳋ', + 11468 => 'ⳍ', + 11470 => 'ⳏ', + 11472 => 'ⳑ', + 11474 => 'ⳓ', + 11476 => 'ⳕ', + 11478 => 'ⳗ', + 11480 => 'ⳙ', + 11482 => 'ⳛ', + 11484 => 'ⳝ', + 11486 => 'ⳟ', + 11488 => 'ⳡ', + 11490 => 'ⳣ', + 11499 => 'ⳬ', + 11501 => 'ⳮ', + 11506 => 'ⳳ', + 11631 => 'ⵡ', + 11935 => '母', + 12019 => '龟', + 12032 => '一', + 12033 => '丨', + 12034 => '丶', + 12035 => '丿', + 12036 => '乙', + 12037 => '亅', + 12038 => '二', + 12039 => '亠', + 12040 => '人', + 12041 => '儿', + 12042 => '入', + 12043 => '八', + 12044 => '冂', + 12045 => '冖', + 12046 => '冫', + 12047 => '几', + 12048 => '凵', + 12049 => '刀', + 12050 => '力', + 12051 => '勹', + 12052 => '匕', + 12053 => '匚', + 12054 => '匸', + 12055 => '十', + 12056 => '卜', + 12057 => '卩', + 12058 => '厂', + 12059 => '厶', + 12060 => '又', + 12061 => '口', + 12062 => '囗', + 12063 => '土', + 12064 => '士', + 12065 => '夂', + 12066 => '夊', + 12067 => '夕', + 12068 => '大', + 12069 => '女', + 12070 => '子', + 12071 => '宀', + 12072 => '寸', + 12073 => '小', + 12074 => '尢', + 12075 => '尸', + 12076 => '屮', + 12077 => '山', + 12078 => '巛', + 12079 => '工', + 12080 => '己', + 12081 => '巾', + 12082 => '干', + 12083 => '幺', + 12084 => '广', + 12085 => '廴', + 12086 => '廾', + 12087 => '弋', + 12088 => '弓', + 12089 => '彐', + 12090 => '彡', + 12091 => '彳', + 12092 => '心', + 12093 => '戈', + 12094 => '戶', + 12095 => '手', + 12096 => '支', + 12097 => '攴', + 12098 => '文', + 12099 => '斗', + 12100 => '斤', + 12101 => '方', + 12102 => '无', + 12103 => '日', + 12104 => '曰', + 12105 => '月', + 12106 => '木', + 12107 => '欠', + 12108 => '止', + 12109 => '歹', + 12110 => '殳', + 12111 => '毋', + 12112 => '比', + 12113 => '毛', + 12114 => '氏', + 12115 => '气', + 12116 => '水', + 12117 => '火', + 12118 => '爪', + 12119 => '父', + 12120 => '爻', + 12121 => '爿', + 12122 => '片', + 12123 => '牙', + 12124 => '牛', + 12125 => '犬', + 12126 => '玄', + 12127 => '玉', + 12128 => '瓜', + 12129 => '瓦', + 12130 => '甘', + 12131 => '生', + 12132 => '用', + 12133 => '田', + 12134 => '疋', + 12135 => '疒', + 12136 => '癶', + 12137 => '白', + 12138 => '皮', + 12139 => '皿', + 12140 => '目', + 12141 => '矛', + 12142 => '矢', + 12143 => '石', + 12144 => '示', + 12145 => '禸', + 12146 => '禾', + 12147 => '穴', + 12148 => '立', + 12149 => '竹', + 12150 => '米', + 12151 => '糸', + 12152 => '缶', + 12153 => '网', + 12154 => '羊', + 12155 => '羽', + 12156 => '老', + 12157 => '而', + 12158 => '耒', + 12159 => '耳', + 12160 => '聿', + 12161 => '肉', + 12162 => '臣', + 12163 => '自', + 12164 => '至', + 12165 => '臼', + 12166 => '舌', + 12167 => '舛', + 12168 => '舟', + 12169 => '艮', + 12170 => '色', + 12171 => '艸', + 12172 => '虍', + 12173 => '虫', + 12174 => '血', + 12175 => '行', + 12176 => '衣', + 12177 => '襾', + 12178 => '見', + 12179 => '角', + 12180 => '言', + 12181 => '谷', + 12182 => '豆', + 12183 => '豕', + 12184 => '豸', + 12185 => '貝', + 12186 => '赤', + 12187 => '走', + 12188 => '足', + 12189 => '身', + 12190 => '車', + 12191 => '辛', + 12192 => '辰', + 12193 => '辵', + 12194 => '邑', + 12195 => '酉', + 12196 => '釆', + 12197 => '里', + 12198 => '金', + 12199 => '長', + 12200 => '門', + 12201 => '阜', + 12202 => '隶', + 12203 => '隹', + 12204 => '雨', + 12205 => '靑', + 12206 => '非', + 12207 => '面', + 12208 => '革', + 12209 => '韋', + 12210 => '韭', + 12211 => '音', + 12212 => '頁', + 12213 => '風', + 12214 => '飛', + 12215 => '食', + 12216 => '首', + 12217 => '香', + 12218 => '馬', + 12219 => '骨', + 12220 => '高', + 12221 => '髟', + 12222 => '鬥', + 12223 => '鬯', + 12224 => '鬲', + 12225 => '鬼', + 12226 => '魚', + 12227 => '鳥', + 12228 => '鹵', + 12229 => '鹿', + 12230 => '麥', + 12231 => '麻', + 12232 => '黃', + 12233 => '黍', + 12234 => '黑', + 12235 => '黹', + 12236 => '黽', + 12237 => '鼎', + 12238 => '鼓', + 12239 => '鼠', + 12240 => '鼻', + 12241 => '齊', + 12242 => '齒', + 12243 => '龍', + 12244 => '龜', + 12245 => '龠', + 12290 => '.', + 12342 => '〒', + 12344 => '十', + 12345 => '卄', + 12346 => '卅', + 12447 => 'より', + 12543 => 'コト', + 12593 => 'ᄀ', + 12594 => 'ᄁ', + 12595 => 'ᆪ', + 12596 => 'ᄂ', + 12597 => 'ᆬ', + 12598 => 'ᆭ', + 12599 => 'ᄃ', + 12600 => 'ᄄ', + 12601 => 'ᄅ', + 12602 => 'ᆰ', + 12603 => 'ᆱ', + 12604 => 'ᆲ', + 12605 => 'ᆳ', + 12606 => 'ᆴ', + 12607 => 'ᆵ', + 12608 => 'ᄚ', + 12609 => 'ᄆ', + 12610 => 'ᄇ', + 12611 => 'ᄈ', + 12612 => 'ᄡ', + 12613 => 'ᄉ', + 12614 => 'ᄊ', + 12615 => 'ᄋ', + 12616 => 'ᄌ', + 12617 => 'ᄍ', + 12618 => 'ᄎ', + 12619 => 'ᄏ', + 12620 => 'ᄐ', + 12621 => 'ᄑ', + 12622 => 'ᄒ', + 12623 => 'ᅡ', + 12624 => 'ᅢ', + 12625 => 'ᅣ', + 12626 => 'ᅤ', + 12627 => 'ᅥ', + 12628 => 'ᅦ', + 12629 => 'ᅧ', + 12630 => 'ᅨ', + 12631 => 'ᅩ', + 12632 => 'ᅪ', + 12633 => 'ᅫ', + 12634 => 'ᅬ', + 12635 => 'ᅭ', + 12636 => 'ᅮ', + 12637 => 'ᅯ', + 12638 => 'ᅰ', + 12639 => 'ᅱ', + 12640 => 'ᅲ', + 12641 => 'ᅳ', + 12642 => 'ᅴ', + 12643 => 'ᅵ', + 12645 => 'ᄔ', + 12646 => 'ᄕ', + 12647 => 'ᇇ', + 12648 => 'ᇈ', + 12649 => 'ᇌ', + 12650 => 'ᇎ', + 12651 => 'ᇓ', + 12652 => 'ᇗ', + 12653 => 'ᇙ', + 12654 => 'ᄜ', + 12655 => 'ᇝ', + 12656 => 'ᇟ', + 12657 => 'ᄝ', + 12658 => 'ᄞ', + 12659 => 'ᄠ', + 12660 => 'ᄢ', + 12661 => 'ᄣ', + 12662 => 'ᄧ', + 12663 => 'ᄩ', + 12664 => 'ᄫ', + 12665 => 'ᄬ', + 12666 => 'ᄭ', + 12667 => 'ᄮ', + 12668 => 'ᄯ', + 12669 => 'ᄲ', + 12670 => 'ᄶ', + 12671 => 'ᅀ', + 12672 => 'ᅇ', + 12673 => 'ᅌ', + 12674 => 'ᇱ', + 12675 => 'ᇲ', + 12676 => 'ᅗ', + 12677 => 'ᅘ', + 12678 => 'ᅙ', + 12679 => 'ᆄ', + 12680 => 'ᆅ', + 12681 => 'ᆈ', + 12682 => 'ᆑ', + 12683 => 'ᆒ', + 12684 => 'ᆔ', + 12685 => 'ᆞ', + 12686 => 'ᆡ', + 12690 => '一', + 12691 => '二', + 12692 => '三', + 12693 => '四', + 12694 => '上', + 12695 => '中', + 12696 => '下', + 12697 => '甲', + 12698 => '乙', + 12699 => '丙', + 12700 => '丁', + 12701 => '天', + 12702 => '地', + 12703 => '人', + 12868 => '問', + 12869 => '幼', + 12870 => '文', + 12871 => '箏', + 12880 => 'pte', + 12881 => '21', + 12882 => '22', + 12883 => '23', + 12884 => '24', + 12885 => '25', + 12886 => '26', + 12887 => '27', + 12888 => '28', + 12889 => '29', + 12890 => '30', + 12891 => '31', + 12892 => '32', + 12893 => '33', + 12894 => '34', + 12895 => '35', + 12896 => 'ᄀ', + 12897 => 'ᄂ', + 12898 => 'ᄃ', + 12899 => 'ᄅ', + 12900 => 'ᄆ', + 12901 => 'ᄇ', + 12902 => 'ᄉ', + 12903 => 'ᄋ', + 12904 => 'ᄌ', + 12905 => 'ᄎ', + 12906 => 'ᄏ', + 12907 => 'ᄐ', + 12908 => 'ᄑ', + 12909 => 'ᄒ', + 12910 => '가', + 12911 => '나', + 12912 => '다', + 12913 => '라', + 12914 => '마', + 12915 => '바', + 12916 => '사', + 12917 => '아', + 12918 => '자', + 12919 => '차', + 12920 => '카', + 12921 => '타', + 12922 => '파', + 12923 => '하', + 12924 => '참고', + 12925 => '주의', + 12926 => '우', + 12928 => '一', + 12929 => '二', + 12930 => '三', + 12931 => '四', + 12932 => '五', + 12933 => '六', + 12934 => '七', + 12935 => '八', + 12936 => '九', + 12937 => '十', + 12938 => '月', + 12939 => '火', + 12940 => '水', + 12941 => '木', + 12942 => '金', + 12943 => '土', + 12944 => '日', + 12945 => '株', + 12946 => '有', + 12947 => '社', + 12948 => '名', + 12949 => '特', + 12950 => '財', + 12951 => '祝', + 12952 => '労', + 12953 => '秘', + 12954 => '男', + 12955 => '女', + 12956 => '適', + 12957 => '優', + 12958 => '印', + 12959 => '注', + 12960 => '項', + 12961 => '休', + 12962 => '写', + 12963 => '正', + 12964 => '上', + 12965 => '中', + 12966 => '下', + 12967 => '左', + 12968 => '右', + 12969 => '医', + 12970 => '宗', + 12971 => '学', + 12972 => '監', + 12973 => '企', + 12974 => '資', + 12975 => '協', + 12976 => '夜', + 12977 => '36', + 12978 => '37', + 12979 => '38', + 12980 => '39', + 12981 => '40', + 12982 => '41', + 12983 => '42', + 12984 => '43', + 12985 => '44', + 12986 => '45', + 12987 => '46', + 12988 => '47', + 12989 => '48', + 12990 => '49', + 12991 => '50', + 12992 => '1月', + 12993 => '2月', + 12994 => '3月', + 12995 => '4月', + 12996 => '5月', + 12997 => '6月', + 12998 => '7月', + 12999 => '8月', + 13000 => '9月', + 13001 => '10月', + 13002 => '11月', + 13003 => '12月', + 13004 => 'hg', + 13005 => 'erg', + 13006 => 'ev', + 13007 => 'ltd', + 13008 => 'ア', + 13009 => 'イ', + 13010 => 'ウ', + 13011 => 'エ', + 13012 => 'オ', + 13013 => 'カ', + 13014 => 'キ', + 13015 => 'ク', + 13016 => 'ケ', + 13017 => 'コ', + 13018 => 'サ', + 13019 => 'シ', + 13020 => 'ス', + 13021 => 'セ', + 13022 => 'ソ', + 13023 => 'タ', + 13024 => 'チ', + 13025 => 'ツ', + 13026 => 'テ', + 13027 => 'ト', + 13028 => 'ナ', + 13029 => 'ニ', + 13030 => 'ヌ', + 13031 => 'ネ', + 13032 => 'ノ', + 13033 => 'ハ', + 13034 => 'ヒ', + 13035 => 'フ', + 13036 => 'ヘ', + 13037 => 'ホ', + 13038 => 'マ', + 13039 => 'ミ', + 13040 => 'ム', + 13041 => 'メ', + 13042 => 'モ', + 13043 => 'ヤ', + 13044 => 'ユ', + 13045 => 'ヨ', + 13046 => 'ラ', + 13047 => 'リ', + 13048 => 'ル', + 13049 => 'レ', + 13050 => 'ロ', + 13051 => 'ワ', + 13052 => 'ヰ', + 13053 => 'ヱ', + 13054 => 'ヲ', + 13055 => '令和', + 13056 => 'アパート', + 13057 => 'アルファ', + 13058 => 'アンペア', + 13059 => 'アール', + 13060 => 'イニング', + 13061 => 'インチ', + 13062 => 'ウォン', + 13063 => 'エスクード', + 13064 => 'エーカー', + 13065 => 'オンス', + 13066 => 'オーム', + 13067 => 'カイリ', + 13068 => 'カラット', + 13069 => 'カロリー', + 13070 => 'ガロン', + 13071 => 'ガンマ', + 13072 => 'ギガ', + 13073 => 'ギニー', + 13074 => 'キュリー', + 13075 => 'ギルダー', + 13076 => 'キロ', + 13077 => 'キログラム', + 13078 => 'キロメートル', + 13079 => 'キロワット', + 13080 => 'グラム', + 13081 => 'グラムトン', + 13082 => 'クルゼイロ', + 13083 => 'クローネ', + 13084 => 'ケース', + 13085 => 'コルナ', + 13086 => 'コーポ', + 13087 => 'サイクル', + 13088 => 'サンチーム', + 13089 => 'シリング', + 13090 => 'センチ', + 13091 => 'セント', + 13092 => 'ダース', + 13093 => 'デシ', + 13094 => 'ドル', + 13095 => 'トン', + 13096 => 'ナノ', + 13097 => 'ノット', + 13098 => 'ハイツ', + 13099 => 'パーセント', + 13100 => 'パーツ', + 13101 => 'バーレル', + 13102 => 'ピアストル', + 13103 => 'ピクル', + 13104 => 'ピコ', + 13105 => 'ビル', + 13106 => 'ファラッド', + 13107 => 'フィート', + 13108 => 'ブッシェル', + 13109 => 'フラン', + 13110 => 'ヘクタール', + 13111 => 'ペソ', + 13112 => 'ペニヒ', + 13113 => 'ヘルツ', + 13114 => 'ペンス', + 13115 => 'ページ', + 13116 => 'ベータ', + 13117 => 'ポイント', + 13118 => 'ボルト', + 13119 => 'ホン', + 13120 => 'ポンド', + 13121 => 'ホール', + 13122 => 'ホーン', + 13123 => 'マイクロ', + 13124 => 'マイル', + 13125 => 'マッハ', + 13126 => 'マルク', + 13127 => 'マンション', + 13128 => 'ミクロン', + 13129 => 'ミリ', + 13130 => 'ミリバール', + 13131 => 'メガ', + 13132 => 'メガトン', + 13133 => 'メートル', + 13134 => 'ヤード', + 13135 => 'ヤール', + 13136 => 'ユアン', + 13137 => 'リットル', + 13138 => 'リラ', + 13139 => 'ルピー', + 13140 => 'ルーブル', + 13141 => 'レム', + 13142 => 'レントゲン', + 13143 => 'ワット', + 13144 => '0点', + 13145 => '1点', + 13146 => '2点', + 13147 => '3点', + 13148 => '4点', + 13149 => '5点', + 13150 => '6点', + 13151 => '7点', + 13152 => '8点', + 13153 => '9点', + 13154 => '10点', + 13155 => '11点', + 13156 => '12点', + 13157 => '13点', + 13158 => '14点', + 13159 => '15点', + 13160 => '16点', + 13161 => '17点', + 13162 => '18点', + 13163 => '19点', + 13164 => '20点', + 13165 => '21点', + 13166 => '22点', + 13167 => '23点', + 13168 => '24点', + 13169 => 'hpa', + 13170 => 'da', + 13171 => 'au', + 13172 => 'bar', + 13173 => 'ov', + 13174 => 'pc', + 13175 => 'dm', + 13176 => 'dm2', + 13177 => 'dm3', + 13178 => 'iu', + 13179 => '平成', + 13180 => '昭和', + 13181 => '大正', + 13182 => '明治', + 13183 => '株式会社', + 13184 => 'pa', + 13185 => 'na', + 13186 => 'μa', + 13187 => 'ma', + 13188 => 'ka', + 13189 => 'kb', + 13190 => 'mb', + 13191 => 'gb', + 13192 => 'cal', + 13193 => 'kcal', + 13194 => 'pf', + 13195 => 'nf', + 13196 => 'μf', + 13197 => 'μg', + 13198 => 'mg', + 13199 => 'kg', + 13200 => 'hz', + 13201 => 'khz', + 13202 => 'mhz', + 13203 => 'ghz', + 13204 => 'thz', + 13205 => 'μl', + 13206 => 'ml', + 13207 => 'dl', + 13208 => 'kl', + 13209 => 'fm', + 13210 => 'nm', + 13211 => 'μm', + 13212 => 'mm', + 13213 => 'cm', + 13214 => 'km', + 13215 => 'mm2', + 13216 => 'cm2', + 13217 => 'm2', + 13218 => 'km2', + 13219 => 'mm3', + 13220 => 'cm3', + 13221 => 'm3', + 13222 => 'km3', + 13223 => 'm∕s', + 13224 => 'm∕s2', + 13225 => 'pa', + 13226 => 'kpa', + 13227 => 'mpa', + 13228 => 'gpa', + 13229 => 'rad', + 13230 => 'rad∕s', + 13231 => 'rad∕s2', + 13232 => 'ps', + 13233 => 'ns', + 13234 => 'μs', + 13235 => 'ms', + 13236 => 'pv', + 13237 => 'nv', + 13238 => 'μv', + 13239 => 'mv', + 13240 => 'kv', + 13241 => 'mv', + 13242 => 'pw', + 13243 => 'nw', + 13244 => 'μw', + 13245 => 'mw', + 13246 => 'kw', + 13247 => 'mw', + 13248 => 'kω', + 13249 => 'mω', + 13251 => 'bq', + 13252 => 'cc', + 13253 => 'cd', + 13254 => 'c∕kg', + 13256 => 'db', + 13257 => 'gy', + 13258 => 'ha', + 13259 => 'hp', + 13260 => 'in', + 13261 => 'kk', + 13262 => 'km', + 13263 => 'kt', + 13264 => 'lm', + 13265 => 'ln', + 13266 => 'log', + 13267 => 'lx', + 13268 => 'mb', + 13269 => 'mil', + 13270 => 'mol', + 13271 => 'ph', + 13273 => 'ppm', + 13274 => 'pr', + 13275 => 'sr', + 13276 => 'sv', + 13277 => 'wb', + 13278 => 'v∕m', + 13279 => 'a∕m', + 13280 => '1日', + 13281 => '2日', + 13282 => '3日', + 13283 => '4日', + 13284 => '5日', + 13285 => '6日', + 13286 => '7日', + 13287 => '8日', + 13288 => '9日', + 13289 => '10日', + 13290 => '11日', + 13291 => '12日', + 13292 => '13日', + 13293 => '14日', + 13294 => '15日', + 13295 => '16日', + 13296 => '17日', + 13297 => '18日', + 13298 => '19日', + 13299 => '20日', + 13300 => '21日', + 13301 => '22日', + 13302 => '23日', + 13303 => '24日', + 13304 => '25日', + 13305 => '26日', + 13306 => '27日', + 13307 => '28日', + 13308 => '29日', + 13309 => '30日', + 13310 => '31日', + 13311 => 'gal', + 42560 => 'ꙁ', + 42562 => 'ꙃ', + 42564 => 'ꙅ', + 42566 => 'ꙇ', + 42568 => 'ꙉ', + 42570 => 'ꙋ', + 42572 => 'ꙍ', + 42574 => 'ꙏ', + 42576 => 'ꙑ', + 42578 => 'ꙓ', + 42580 => 'ꙕ', + 42582 => 'ꙗ', + 42584 => 'ꙙ', + 42586 => 'ꙛ', + 42588 => 'ꙝ', + 42590 => 'ꙟ', + 42592 => 'ꙡ', + 42594 => 'ꙣ', + 42596 => 'ꙥ', + 42598 => 'ꙧ', + 42600 => 'ꙩ', + 42602 => 'ꙫ', + 42604 => 'ꙭ', + 42624 => 'ꚁ', + 42626 => 'ꚃ', + 42628 => 'ꚅ', + 42630 => 'ꚇ', + 42632 => 'ꚉ', + 42634 => 'ꚋ', + 42636 => 'ꚍ', + 42638 => 'ꚏ', + 42640 => 'ꚑ', + 42642 => 'ꚓ', + 42644 => 'ꚕ', + 42646 => 'ꚗ', + 42648 => 'ꚙ', + 42650 => 'ꚛ', + 42652 => 'ъ', + 42653 => 'ь', + 42786 => 'ꜣ', + 42788 => 'ꜥ', + 42790 => 'ꜧ', + 42792 => 'ꜩ', + 42794 => 'ꜫ', + 42796 => 'ꜭ', + 42798 => 'ꜯ', + 42802 => 'ꜳ', + 42804 => 'ꜵ', + 42806 => 'ꜷ', + 42808 => 'ꜹ', + 42810 => 'ꜻ', + 42812 => 'ꜽ', + 42814 => 'ꜿ', + 42816 => 'ꝁ', + 42818 => 'ꝃ', + 42820 => 'ꝅ', + 42822 => 'ꝇ', + 42824 => 'ꝉ', + 42826 => 'ꝋ', + 42828 => 'ꝍ', + 42830 => 'ꝏ', + 42832 => 'ꝑ', + 42834 => 'ꝓ', + 42836 => 'ꝕ', + 42838 => 'ꝗ', + 42840 => 'ꝙ', + 42842 => 'ꝛ', + 42844 => 'ꝝ', + 42846 => 'ꝟ', + 42848 => 'ꝡ', + 42850 => 'ꝣ', + 42852 => 'ꝥ', + 42854 => 'ꝧ', + 42856 => 'ꝩ', + 42858 => 'ꝫ', + 42860 => 'ꝭ', + 42862 => 'ꝯ', + 42864 => 'ꝯ', + 42873 => 'ꝺ', + 42875 => 'ꝼ', + 42877 => 'ᵹ', + 42878 => 'ꝿ', + 42880 => 'ꞁ', + 42882 => 'ꞃ', + 42884 => 'ꞅ', + 42886 => 'ꞇ', + 42891 => 'ꞌ', + 42893 => 'ɥ', + 42896 => 'ꞑ', + 42898 => 'ꞓ', + 42902 => 'ꞗ', + 42904 => 'ꞙ', + 42906 => 'ꞛ', + 42908 => 'ꞝ', + 42910 => 'ꞟ', + 42912 => 'ꞡ', + 42914 => 'ꞣ', + 42916 => 'ꞥ', + 42918 => 'ꞧ', + 42920 => 'ꞩ', + 42922 => 'ɦ', + 42923 => 'ɜ', + 42924 => 'ɡ', + 42925 => 'ɬ', + 42926 => 'ɪ', + 42928 => 'ʞ', + 42929 => 'ʇ', + 42930 => 'ʝ', + 42931 => 'ꭓ', + 42932 => 'ꞵ', + 42934 => 'ꞷ', + 42936 => 'ꞹ', + 42938 => 'ꞻ', + 42940 => 'ꞽ', + 42942 => 'ꞿ', + 42946 => 'ꟃ', + 42948 => 'ꞔ', + 42949 => 'ʂ', + 42950 => 'ᶎ', + 42951 => 'ꟈ', + 42953 => 'ꟊ', + 42997 => 'ꟶ', + 43000 => 'ħ', + 43001 => 'œ', + 43868 => 'ꜧ', + 43869 => 'ꬷ', + 43870 => 'ɫ', + 43871 => 'ꭒ', + 43881 => 'ʍ', + 43888 => 'Ꭰ', + 43889 => 'Ꭱ', + 43890 => 'Ꭲ', + 43891 => 'Ꭳ', + 43892 => 'Ꭴ', + 43893 => 'Ꭵ', + 43894 => 'Ꭶ', + 43895 => 'Ꭷ', + 43896 => 'Ꭸ', + 43897 => 'Ꭹ', + 43898 => 'Ꭺ', + 43899 => 'Ꭻ', + 43900 => 'Ꭼ', + 43901 => 'Ꭽ', + 43902 => 'Ꭾ', + 43903 => 'Ꭿ', + 43904 => 'Ꮀ', + 43905 => 'Ꮁ', + 43906 => 'Ꮂ', + 43907 => 'Ꮃ', + 43908 => 'Ꮄ', + 43909 => 'Ꮅ', + 43910 => 'Ꮆ', + 43911 => 'Ꮇ', + 43912 => 'Ꮈ', + 43913 => 'Ꮉ', + 43914 => 'Ꮊ', + 43915 => 'Ꮋ', + 43916 => 'Ꮌ', + 43917 => 'Ꮍ', + 43918 => 'Ꮎ', + 43919 => 'Ꮏ', + 43920 => 'Ꮐ', + 43921 => 'Ꮑ', + 43922 => 'Ꮒ', + 43923 => 'Ꮓ', + 43924 => 'Ꮔ', + 43925 => 'Ꮕ', + 43926 => 'Ꮖ', + 43927 => 'Ꮗ', + 43928 => 'Ꮘ', + 43929 => 'Ꮙ', + 43930 => 'Ꮚ', + 43931 => 'Ꮛ', + 43932 => 'Ꮜ', + 43933 => 'Ꮝ', + 43934 => 'Ꮞ', + 43935 => 'Ꮟ', + 43936 => 'Ꮠ', + 43937 => 'Ꮡ', + 43938 => 'Ꮢ', + 43939 => 'Ꮣ', + 43940 => 'Ꮤ', + 43941 => 'Ꮥ', + 43942 => 'Ꮦ', + 43943 => 'Ꮧ', + 43944 => 'Ꮨ', + 43945 => 'Ꮩ', + 43946 => 'Ꮪ', + 43947 => 'Ꮫ', + 43948 => 'Ꮬ', + 43949 => 'Ꮭ', + 43950 => 'Ꮮ', + 43951 => 'Ꮯ', + 43952 => 'Ꮰ', + 43953 => 'Ꮱ', + 43954 => 'Ꮲ', + 43955 => 'Ꮳ', + 43956 => 'Ꮴ', + 43957 => 'Ꮵ', + 43958 => 'Ꮶ', + 43959 => 'Ꮷ', + 43960 => 'Ꮸ', + 43961 => 'Ꮹ', + 43962 => 'Ꮺ', + 43963 => 'Ꮻ', + 43964 => 'Ꮼ', + 43965 => 'Ꮽ', + 43966 => 'Ꮾ', + 43967 => 'Ꮿ', + 63744 => '豈', + 63745 => '更', + 63746 => '車', + 63747 => '賈', + 63748 => '滑', + 63749 => '串', + 63750 => '句', + 63751 => '龜', + 63752 => '龜', + 63753 => '契', + 63754 => '金', + 63755 => '喇', + 63756 => '奈', + 63757 => '懶', + 63758 => '癩', + 63759 => '羅', + 63760 => '蘿', + 63761 => '螺', + 63762 => '裸', + 63763 => '邏', + 63764 => '樂', + 63765 => '洛', + 63766 => '烙', + 63767 => '珞', + 63768 => '落', + 63769 => '酪', + 63770 => '駱', + 63771 => '亂', + 63772 => '卵', + 63773 => '欄', + 63774 => '爛', + 63775 => '蘭', + 63776 => '鸞', + 63777 => '嵐', + 63778 => '濫', + 63779 => '藍', + 63780 => '襤', + 63781 => '拉', + 63782 => '臘', + 63783 => '蠟', + 63784 => '廊', + 63785 => '朗', + 63786 => '浪', + 63787 => '狼', + 63788 => '郎', + 63789 => '來', + 63790 => '冷', + 63791 => '勞', + 63792 => '擄', + 63793 => '櫓', + 63794 => '爐', + 63795 => '盧', + 63796 => '老', + 63797 => '蘆', + 63798 => '虜', + 63799 => '路', + 63800 => '露', + 63801 => '魯', + 63802 => '鷺', + 63803 => '碌', + 63804 => '祿', + 63805 => '綠', + 63806 => '菉', + 63807 => '錄', + 63808 => '鹿', + 63809 => '論', + 63810 => '壟', + 63811 => '弄', + 63812 => '籠', + 63813 => '聾', + 63814 => '牢', + 63815 => '磊', + 63816 => '賂', + 63817 => '雷', + 63818 => '壘', + 63819 => '屢', + 63820 => '樓', + 63821 => '淚', + 63822 => '漏', + 63823 => '累', + 63824 => '縷', + 63825 => '陋', + 63826 => '勒', + 63827 => '肋', + 63828 => '凜', + 63829 => '凌', + 63830 => '稜', + 63831 => '綾', + 63832 => '菱', + 63833 => '陵', + 63834 => '讀', + 63835 => '拏', + 63836 => '樂', + 63837 => '諾', + 63838 => '丹', + 63839 => '寧', + 63840 => '怒', + 63841 => '率', + 63842 => '異', + 63843 => '北', + 63844 => '磻', + 63845 => '便', + 63846 => '復', + 63847 => '不', + 63848 => '泌', + 63849 => '數', + 63850 => '索', + 63851 => '參', + 63852 => '塞', + 63853 => '省', + 63854 => '葉', + 63855 => '說', + 63856 => '殺', + 63857 => '辰', + 63858 => '沈', + 63859 => '拾', + 63860 => '若', + 63861 => '掠', + 63862 => '略', + 63863 => '亮', + 63864 => '兩', + 63865 => '凉', + 63866 => '梁', + 63867 => '糧', + 63868 => '良', + 63869 => '諒', + 63870 => '量', + 63871 => '勵', + 63872 => '呂', + 63873 => '女', + 63874 => '廬', + 63875 => '旅', + 63876 => '濾', + 63877 => '礪', + 63878 => '閭', + 63879 => '驪', + 63880 => '麗', + 63881 => '黎', + 63882 => '力', + 63883 => '曆', + 63884 => '歷', + 63885 => '轢', + 63886 => '年', + 63887 => '憐', + 63888 => '戀', + 63889 => '撚', + 63890 => '漣', + 63891 => '煉', + 63892 => '璉', + 63893 => '秊', + 63894 => '練', + 63895 => '聯', + 63896 => '輦', + 63897 => '蓮', + 63898 => '連', + 63899 => '鍊', + 63900 => '列', + 63901 => '劣', + 63902 => '咽', + 63903 => '烈', + 63904 => '裂', + 63905 => '說', + 63906 => '廉', + 63907 => '念', + 63908 => '捻', + 63909 => '殮', + 63910 => '簾', + 63911 => '獵', + 63912 => '令', + 63913 => '囹', + 63914 => '寧', + 63915 => '嶺', + 63916 => '怜', + 63917 => '玲', + 63918 => '瑩', + 63919 => '羚', + 63920 => '聆', + 63921 => '鈴', + 63922 => '零', + 63923 => '靈', + 63924 => '領', + 63925 => '例', + 63926 => '禮', + 63927 => '醴', + 63928 => '隸', + 63929 => '惡', + 63930 => '了', + 63931 => '僚', + 63932 => '寮', + 63933 => '尿', + 63934 => '料', + 63935 => '樂', + 63936 => '燎', + 63937 => '療', + 63938 => '蓼', + 63939 => '遼', + 63940 => '龍', + 63941 => '暈', + 63942 => '阮', + 63943 => '劉', + 63944 => '杻', + 63945 => '柳', + 63946 => '流', + 63947 => '溜', + 63948 => '琉', + 63949 => '留', + 63950 => '硫', + 63951 => '紐', + 63952 => '類', + 63953 => '六', + 63954 => '戮', + 63955 => '陸', + 63956 => '倫', + 63957 => '崙', + 63958 => '淪', + 63959 => '輪', + 63960 => '律', + 63961 => '慄', + 63962 => '栗', + 63963 => '率', + 63964 => '隆', + 63965 => '利', + 63966 => '吏', + 63967 => '履', + 63968 => '易', + 63969 => '李', + 63970 => '梨', + 63971 => '泥', + 63972 => '理', + 63973 => '痢', + 63974 => '罹', + 63975 => '裏', + 63976 => '裡', + 63977 => '里', + 63978 => '離', + 63979 => '匿', + 63980 => '溺', + 63981 => '吝', + 63982 => '燐', + 63983 => '璘', + 63984 => '藺', + 63985 => '隣', + 63986 => '鱗', + 63987 => '麟', + 63988 => '林', + 63989 => '淋', + 63990 => '臨', + 63991 => '立', + 63992 => '笠', + 63993 => '粒', + 63994 => '狀', + 63995 => '炙', + 63996 => '識', + 63997 => '什', + 63998 => '茶', + 63999 => '刺', + 64000 => '切', + 64001 => '度', + 64002 => '拓', + 64003 => '糖', + 64004 => '宅', + 64005 => '洞', + 64006 => '暴', + 64007 => '輻', + 64008 => '行', + 64009 => '降', + 64010 => '見', + 64011 => '廓', + 64012 => '兀', + 64013 => '嗀', + 64016 => '塚', + 64018 => '晴', + 64021 => '凞', + 64022 => '猪', + 64023 => '益', + 64024 => '礼', + 64025 => '神', + 64026 => '祥', + 64027 => '福', + 64028 => '靖', + 64029 => '精', + 64030 => '羽', + 64032 => '蘒', + 64034 => '諸', + 64037 => '逸', + 64038 => '都', + 64042 => '飯', + 64043 => '飼', + 64044 => '館', + 64045 => '鶴', + 64046 => '郞', + 64047 => '隷', + 64048 => '侮', + 64049 => '僧', + 64050 => '免', + 64051 => '勉', + 64052 => '勤', + 64053 => '卑', + 64054 => '喝', + 64055 => '嘆', + 64056 => '器', + 64057 => '塀', + 64058 => '墨', + 64059 => '層', + 64060 => '屮', + 64061 => '悔', + 64062 => '慨', + 64063 => '憎', + 64064 => '懲', + 64065 => '敏', + 64066 => '既', + 64067 => '暑', + 64068 => '梅', + 64069 => '海', + 64070 => '渚', + 64071 => '漢', + 64072 => '煮', + 64073 => '爫', + 64074 => '琢', + 64075 => '碑', + 64076 => '社', + 64077 => '祉', + 64078 => '祈', + 64079 => '祐', + 64080 => '祖', + 64081 => '祝', + 64082 => '禍', + 64083 => '禎', + 64084 => '穀', + 64085 => '突', + 64086 => '節', + 64087 => '練', + 64088 => '縉', + 64089 => '繁', + 64090 => '署', + 64091 => '者', + 64092 => '臭', + 64093 => '艹', + 64094 => '艹', + 64095 => '著', + 64096 => '褐', + 64097 => '視', + 64098 => '謁', + 64099 => '謹', + 64100 => '賓', + 64101 => '贈', + 64102 => '辶', + 64103 => '逸', + 64104 => '難', + 64105 => '響', + 64106 => '頻', + 64107 => '恵', + 64108 => '𤋮', + 64109 => '舘', + 64112 => '並', + 64113 => '况', + 64114 => '全', + 64115 => '侀', + 64116 => '充', + 64117 => '冀', + 64118 => '勇', + 64119 => '勺', + 64120 => '喝', + 64121 => '啕', + 64122 => '喙', + 64123 => '嗢', + 64124 => '塚', + 64125 => '墳', + 64126 => '奄', + 64127 => '奔', + 64128 => '婢', + 64129 => '嬨', + 64130 => '廒', + 64131 => '廙', + 64132 => '彩', + 64133 => '徭', + 64134 => '惘', + 64135 => '慎', + 64136 => '愈', + 64137 => '憎', + 64138 => '慠', + 64139 => '懲', + 64140 => '戴', + 64141 => '揄', + 64142 => '搜', + 64143 => '摒', + 64144 => '敖', + 64145 => '晴', + 64146 => '朗', + 64147 => '望', + 64148 => '杖', + 64149 => '歹', + 64150 => '殺', + 64151 => '流', + 64152 => '滛', + 64153 => '滋', + 64154 => '漢', + 64155 => '瀞', + 64156 => '煮', + 64157 => '瞧', + 64158 => '爵', + 64159 => '犯', + 64160 => '猪', + 64161 => '瑱', + 64162 => '甆', + 64163 => '画', + 64164 => '瘝', + 64165 => '瘟', + 64166 => '益', + 64167 => '盛', + 64168 => '直', + 64169 => '睊', + 64170 => '着', + 64171 => '磌', + 64172 => '窱', + 64173 => '節', + 64174 => '类', + 64175 => '絛', + 64176 => '練', + 64177 => '缾', + 64178 => '者', + 64179 => '荒', + 64180 => '華', + 64181 => '蝹', + 64182 => '襁', + 64183 => '覆', + 64184 => '視', + 64185 => '調', + 64186 => '諸', + 64187 => '請', + 64188 => '謁', + 64189 => '諾', + 64190 => '諭', + 64191 => '謹', + 64192 => '變', + 64193 => '贈', + 64194 => '輸', + 64195 => '遲', + 64196 => '醙', + 64197 => '鉶', + 64198 => '陼', + 64199 => '難', + 64200 => '靖', + 64201 => '韛', + 64202 => '響', + 64203 => '頋', + 64204 => '頻', + 64205 => '鬒', + 64206 => '龜', + 64207 => '𢡊', + 64208 => '𢡄', + 64209 => '𣏕', + 64210 => '㮝', + 64211 => '䀘', + 64212 => '䀹', + 64213 => '𥉉', + 64214 => '𥳐', + 64215 => '𧻓', + 64216 => '齃', + 64217 => '龎', + 64256 => 'ff', + 64257 => 'fi', + 64258 => 'fl', + 64259 => 'ffi', + 64260 => 'ffl', + 64261 => 'st', + 64262 => 'st', + 64275 => 'մն', + 64276 => 'մե', + 64277 => 'մի', + 64278 => 'վն', + 64279 => 'մխ', + 64285 => 'יִ', + 64287 => 'ײַ', + 64288 => 'ע', + 64289 => 'א', + 64290 => 'ד', + 64291 => 'ה', + 64292 => 'כ', + 64293 => 'ל', + 64294 => 'ם', + 64295 => 'ר', + 64296 => 'ת', + 64298 => 'שׁ', + 64299 => 'שׂ', + 64300 => 'שּׁ', + 64301 => 'שּׂ', + 64302 => 'אַ', + 64303 => 'אָ', + 64304 => 'אּ', + 64305 => 'בּ', + 64306 => 'גּ', + 64307 => 'דּ', + 64308 => 'הּ', + 64309 => 'וּ', + 64310 => 'זּ', + 64312 => 'טּ', + 64313 => 'יּ', + 64314 => 'ךּ', + 64315 => 'כּ', + 64316 => 'לּ', + 64318 => 'מּ', + 64320 => 'נּ', + 64321 => 'סּ', + 64323 => 'ףּ', + 64324 => 'פּ', + 64326 => 'צּ', + 64327 => 'קּ', + 64328 => 'רּ', + 64329 => 'שּ', + 64330 => 'תּ', + 64331 => 'וֹ', + 64332 => 'בֿ', + 64333 => 'כֿ', + 64334 => 'פֿ', + 64335 => 'אל', + 64336 => 'ٱ', + 64337 => 'ٱ', + 64338 => 'ٻ', + 64339 => 'ٻ', + 64340 => 'ٻ', + 64341 => 'ٻ', + 64342 => 'پ', + 64343 => 'پ', + 64344 => 'پ', + 64345 => 'پ', + 64346 => 'ڀ', + 64347 => 'ڀ', + 64348 => 'ڀ', + 64349 => 'ڀ', + 64350 => 'ٺ', + 64351 => 'ٺ', + 64352 => 'ٺ', + 64353 => 'ٺ', + 64354 => 'ٿ', + 64355 => 'ٿ', + 64356 => 'ٿ', + 64357 => 'ٿ', + 64358 => 'ٹ', + 64359 => 'ٹ', + 64360 => 'ٹ', + 64361 => 'ٹ', + 64362 => 'ڤ', + 64363 => 'ڤ', + 64364 => 'ڤ', + 64365 => 'ڤ', + 64366 => 'ڦ', + 64367 => 'ڦ', + 64368 => 'ڦ', + 64369 => 'ڦ', + 64370 => 'ڄ', + 64371 => 'ڄ', + 64372 => 'ڄ', + 64373 => 'ڄ', + 64374 => 'ڃ', + 64375 => 'ڃ', + 64376 => 'ڃ', + 64377 => 'ڃ', + 64378 => 'چ', + 64379 => 'چ', + 64380 => 'چ', + 64381 => 'چ', + 64382 => 'ڇ', + 64383 => 'ڇ', + 64384 => 'ڇ', + 64385 => 'ڇ', + 64386 => 'ڍ', + 64387 => 'ڍ', + 64388 => 'ڌ', + 64389 => 'ڌ', + 64390 => 'ڎ', + 64391 => 'ڎ', + 64392 => 'ڈ', + 64393 => 'ڈ', + 64394 => 'ژ', + 64395 => 'ژ', + 64396 => 'ڑ', + 64397 => 'ڑ', + 64398 => 'ک', + 64399 => 'ک', + 64400 => 'ک', + 64401 => 'ک', + 64402 => 'گ', + 64403 => 'گ', + 64404 => 'گ', + 64405 => 'گ', + 64406 => 'ڳ', + 64407 => 'ڳ', + 64408 => 'ڳ', + 64409 => 'ڳ', + 64410 => 'ڱ', + 64411 => 'ڱ', + 64412 => 'ڱ', + 64413 => 'ڱ', + 64414 => 'ں', + 64415 => 'ں', + 64416 => 'ڻ', + 64417 => 'ڻ', + 64418 => 'ڻ', + 64419 => 'ڻ', + 64420 => 'ۀ', + 64421 => 'ۀ', + 64422 => 'ہ', + 64423 => 'ہ', + 64424 => 'ہ', + 64425 => 'ہ', + 64426 => 'ھ', + 64427 => 'ھ', + 64428 => 'ھ', + 64429 => 'ھ', + 64430 => 'ے', + 64431 => 'ے', + 64432 => 'ۓ', + 64433 => 'ۓ', + 64467 => 'ڭ', + 64468 => 'ڭ', + 64469 => 'ڭ', + 64470 => 'ڭ', + 64471 => 'ۇ', + 64472 => 'ۇ', + 64473 => 'ۆ', + 64474 => 'ۆ', + 64475 => 'ۈ', + 64476 => 'ۈ', + 64477 => 'ۇٴ', + 64478 => 'ۋ', + 64479 => 'ۋ', + 64480 => 'ۅ', + 64481 => 'ۅ', + 64482 => 'ۉ', + 64483 => 'ۉ', + 64484 => 'ې', + 64485 => 'ې', + 64486 => 'ې', + 64487 => 'ې', + 64488 => 'ى', + 64489 => 'ى', + 64490 => 'ئا', + 64491 => 'ئا', + 64492 => 'ئە', + 64493 => 'ئە', + 64494 => 'ئو', + 64495 => 'ئو', + 64496 => 'ئۇ', + 64497 => 'ئۇ', + 64498 => 'ئۆ', + 64499 => 'ئۆ', + 64500 => 'ئۈ', + 64501 => 'ئۈ', + 64502 => 'ئې', + 64503 => 'ئې', + 64504 => 'ئې', + 64505 => 'ئى', + 64506 => 'ئى', + 64507 => 'ئى', + 64508 => 'ی', + 64509 => 'ی', + 64510 => 'ی', + 64511 => 'ی', + 64512 => 'ئج', + 64513 => 'ئح', + 64514 => 'ئم', + 64515 => 'ئى', + 64516 => 'ئي', + 64517 => 'بج', + 64518 => 'بح', + 64519 => 'بخ', + 64520 => 'بم', + 64521 => 'بى', + 64522 => 'بي', + 64523 => 'تج', + 64524 => 'تح', + 64525 => 'تخ', + 64526 => 'تم', + 64527 => 'تى', + 64528 => 'تي', + 64529 => 'ثج', + 64530 => 'ثم', + 64531 => 'ثى', + 64532 => 'ثي', + 64533 => 'جح', + 64534 => 'جم', + 64535 => 'حج', + 64536 => 'حم', + 64537 => 'خج', + 64538 => 'خح', + 64539 => 'خم', + 64540 => 'سج', + 64541 => 'سح', + 64542 => 'سخ', + 64543 => 'سم', + 64544 => 'صح', + 64545 => 'صم', + 64546 => 'ضج', + 64547 => 'ضح', + 64548 => 'ضخ', + 64549 => 'ضم', + 64550 => 'طح', + 64551 => 'طم', + 64552 => 'ظم', + 64553 => 'عج', + 64554 => 'عم', + 64555 => 'غج', + 64556 => 'غم', + 64557 => 'فج', + 64558 => 'فح', + 64559 => 'فخ', + 64560 => 'فم', + 64561 => 'فى', + 64562 => 'في', + 64563 => 'قح', + 64564 => 'قم', + 64565 => 'قى', + 64566 => 'قي', + 64567 => 'كا', + 64568 => 'كج', + 64569 => 'كح', + 64570 => 'كخ', + 64571 => 'كل', + 64572 => 'كم', + 64573 => 'كى', + 64574 => 'كي', + 64575 => 'لج', + 64576 => 'لح', + 64577 => 'لخ', + 64578 => 'لم', + 64579 => 'لى', + 64580 => 'لي', + 64581 => 'مج', + 64582 => 'مح', + 64583 => 'مخ', + 64584 => 'مم', + 64585 => 'مى', + 64586 => 'مي', + 64587 => 'نج', + 64588 => 'نح', + 64589 => 'نخ', + 64590 => 'نم', + 64591 => 'نى', + 64592 => 'ني', + 64593 => 'هج', + 64594 => 'هم', + 64595 => 'هى', + 64596 => 'هي', + 64597 => 'يج', + 64598 => 'يح', + 64599 => 'يخ', + 64600 => 'يم', + 64601 => 'يى', + 64602 => 'يي', + 64603 => 'ذٰ', + 64604 => 'رٰ', + 64605 => 'ىٰ', + 64612 => 'ئر', + 64613 => 'ئز', + 64614 => 'ئم', + 64615 => 'ئن', + 64616 => 'ئى', + 64617 => 'ئي', + 64618 => 'بر', + 64619 => 'بز', + 64620 => 'بم', + 64621 => 'بن', + 64622 => 'بى', + 64623 => 'بي', + 64624 => 'تر', + 64625 => 'تز', + 64626 => 'تم', + 64627 => 'تن', + 64628 => 'تى', + 64629 => 'تي', + 64630 => 'ثر', + 64631 => 'ثز', + 64632 => 'ثم', + 64633 => 'ثن', + 64634 => 'ثى', + 64635 => 'ثي', + 64636 => 'فى', + 64637 => 'في', + 64638 => 'قى', + 64639 => 'قي', + 64640 => 'كا', + 64641 => 'كل', + 64642 => 'كم', + 64643 => 'كى', + 64644 => 'كي', + 64645 => 'لم', + 64646 => 'لى', + 64647 => 'لي', + 64648 => 'ما', + 64649 => 'مم', + 64650 => 'نر', + 64651 => 'نز', + 64652 => 'نم', + 64653 => 'نن', + 64654 => 'نى', + 64655 => 'ني', + 64656 => 'ىٰ', + 64657 => 'ير', + 64658 => 'يز', + 64659 => 'يم', + 64660 => 'ين', + 64661 => 'يى', + 64662 => 'يي', + 64663 => 'ئج', + 64664 => 'ئح', + 64665 => 'ئخ', + 64666 => 'ئم', + 64667 => 'ئه', + 64668 => 'بج', + 64669 => 'بح', + 64670 => 'بخ', + 64671 => 'بم', + 64672 => 'به', + 64673 => 'تج', + 64674 => 'تح', + 64675 => 'تخ', + 64676 => 'تم', + 64677 => 'ته', + 64678 => 'ثم', + 64679 => 'جح', + 64680 => 'جم', + 64681 => 'حج', + 64682 => 'حم', + 64683 => 'خج', + 64684 => 'خم', + 64685 => 'سج', + 64686 => 'سح', + 64687 => 'سخ', + 64688 => 'سم', + 64689 => 'صح', + 64690 => 'صخ', + 64691 => 'صم', + 64692 => 'ضج', + 64693 => 'ضح', + 64694 => 'ضخ', + 64695 => 'ضم', + 64696 => 'طح', + 64697 => 'ظم', + 64698 => 'عج', + 64699 => 'عم', + 64700 => 'غج', + 64701 => 'غم', + 64702 => 'فج', + 64703 => 'فح', + 64704 => 'فخ', + 64705 => 'فم', + 64706 => 'قح', + 64707 => 'قم', + 64708 => 'كج', + 64709 => 'كح', + 64710 => 'كخ', + 64711 => 'كل', + 64712 => 'كم', + 64713 => 'لج', + 64714 => 'لح', + 64715 => 'لخ', + 64716 => 'لم', + 64717 => 'له', + 64718 => 'مج', + 64719 => 'مح', + 64720 => 'مخ', + 64721 => 'مم', + 64722 => 'نج', + 64723 => 'نح', + 64724 => 'نخ', + 64725 => 'نم', + 64726 => 'نه', + 64727 => 'هج', + 64728 => 'هم', + 64729 => 'هٰ', + 64730 => 'يج', + 64731 => 'يح', + 64732 => 'يخ', + 64733 => 'يم', + 64734 => 'يه', + 64735 => 'ئم', + 64736 => 'ئه', + 64737 => 'بم', + 64738 => 'به', + 64739 => 'تم', + 64740 => 'ته', + 64741 => 'ثم', + 64742 => 'ثه', + 64743 => 'سم', + 64744 => 'سه', + 64745 => 'شم', + 64746 => 'شه', + 64747 => 'كل', + 64748 => 'كم', + 64749 => 'لم', + 64750 => 'نم', + 64751 => 'نه', + 64752 => 'يم', + 64753 => 'يه', + 64754 => 'ـَّ', + 64755 => 'ـُّ', + 64756 => 'ـِّ', + 64757 => 'طى', + 64758 => 'طي', + 64759 => 'عى', + 64760 => 'عي', + 64761 => 'غى', + 64762 => 'غي', + 64763 => 'سى', + 64764 => 'سي', + 64765 => 'شى', + 64766 => 'شي', + 64767 => 'حى', + 64768 => 'حي', + 64769 => 'جى', + 64770 => 'جي', + 64771 => 'خى', + 64772 => 'خي', + 64773 => 'صى', + 64774 => 'صي', + 64775 => 'ضى', + 64776 => 'ضي', + 64777 => 'شج', + 64778 => 'شح', + 64779 => 'شخ', + 64780 => 'شم', + 64781 => 'شر', + 64782 => 'سر', + 64783 => 'صر', + 64784 => 'ضر', + 64785 => 'طى', + 64786 => 'طي', + 64787 => 'عى', + 64788 => 'عي', + 64789 => 'غى', + 64790 => 'غي', + 64791 => 'سى', + 64792 => 'سي', + 64793 => 'شى', + 64794 => 'شي', + 64795 => 'حى', + 64796 => 'حي', + 64797 => 'جى', + 64798 => 'جي', + 64799 => 'خى', + 64800 => 'خي', + 64801 => 'صى', + 64802 => 'صي', + 64803 => 'ضى', + 64804 => 'ضي', + 64805 => 'شج', + 64806 => 'شح', + 64807 => 'شخ', + 64808 => 'شم', + 64809 => 'شر', + 64810 => 'سر', + 64811 => 'صر', + 64812 => 'ضر', + 64813 => 'شج', + 64814 => 'شح', + 64815 => 'شخ', + 64816 => 'شم', + 64817 => 'سه', + 64818 => 'شه', + 64819 => 'طم', + 64820 => 'سج', + 64821 => 'سح', + 64822 => 'سخ', + 64823 => 'شج', + 64824 => 'شح', + 64825 => 'شخ', + 64826 => 'طم', + 64827 => 'ظم', + 64828 => 'اً', + 64829 => 'اً', + 64848 => 'تجم', + 64849 => 'تحج', + 64850 => 'تحج', + 64851 => 'تحم', + 64852 => 'تخم', + 64853 => 'تمج', + 64854 => 'تمح', + 64855 => 'تمخ', + 64856 => 'جمح', + 64857 => 'جمح', + 64858 => 'حمي', + 64859 => 'حمى', + 64860 => 'سحج', + 64861 => 'سجح', + 64862 => 'سجى', + 64863 => 'سمح', + 64864 => 'سمح', + 64865 => 'سمج', + 64866 => 'سمم', + 64867 => 'سمم', + 64868 => 'صحح', + 64869 => 'صحح', + 64870 => 'صمم', + 64871 => 'شحم', + 64872 => 'شحم', + 64873 => 'شجي', + 64874 => 'شمخ', + 64875 => 'شمخ', + 64876 => 'شمم', + 64877 => 'شمم', + 64878 => 'ضحى', + 64879 => 'ضخم', + 64880 => 'ضخم', + 64881 => 'طمح', + 64882 => 'طمح', + 64883 => 'طمم', + 64884 => 'طمي', + 64885 => 'عجم', + 64886 => 'عمم', + 64887 => 'عمم', + 64888 => 'عمى', + 64889 => 'غمم', + 64890 => 'غمي', + 64891 => 'غمى', + 64892 => 'فخم', + 64893 => 'فخم', + 64894 => 'قمح', + 64895 => 'قمم', + 64896 => 'لحم', + 64897 => 'لحي', + 64898 => 'لحى', + 64899 => 'لجج', + 64900 => 'لجج', + 64901 => 'لخم', + 64902 => 'لخم', + 64903 => 'لمح', + 64904 => 'لمح', + 64905 => 'محج', + 64906 => 'محم', + 64907 => 'محي', + 64908 => 'مجح', + 64909 => 'مجم', + 64910 => 'مخج', + 64911 => 'مخم', + 64914 => 'مجخ', + 64915 => 'همج', + 64916 => 'همم', + 64917 => 'نحم', + 64918 => 'نحى', + 64919 => 'نجم', + 64920 => 'نجم', + 64921 => 'نجى', + 64922 => 'نمي', + 64923 => 'نمى', + 64924 => 'يمم', + 64925 => 'يمم', + 64926 => 'بخي', + 64927 => 'تجي', + 64928 => 'تجى', + 64929 => 'تخي', + 64930 => 'تخى', + 64931 => 'تمي', + 64932 => 'تمى', + 64933 => 'جمي', + 64934 => 'جحى', + 64935 => 'جمى', + 64936 => 'سخى', + 64937 => 'صحي', + 64938 => 'شحي', + 64939 => 'ضحي', + 64940 => 'لجي', + 64941 => 'لمي', + 64942 => 'يحي', + 64943 => 'يجي', + 64944 => 'يمي', + 64945 => 'ممي', + 64946 => 'قمي', + 64947 => 'نحي', + 64948 => 'قمح', + 64949 => 'لحم', + 64950 => 'عمي', + 64951 => 'كمي', + 64952 => 'نجح', + 64953 => 'مخي', + 64954 => 'لجم', + 64955 => 'كمم', + 64956 => 'لجم', + 64957 => 'نجح', + 64958 => 'جحي', + 64959 => 'حجي', + 64960 => 'مجي', + 64961 => 'فمي', + 64962 => 'بحي', + 64963 => 'كمم', + 64964 => 'عجم', + 64965 => 'صمم', + 64966 => 'سخي', + 64967 => 'نجي', + 65008 => 'صلے', + 65009 => 'قلے', + 65010 => 'الله', + 65011 => 'اكبر', + 65012 => 'محمد', + 65013 => 'صلعم', + 65014 => 'رسول', + 65015 => 'عليه', + 65016 => 'وسلم', + 65017 => 'صلى', + 65020 => 'ریال', + 65041 => '、', + 65047 => '〖', + 65048 => '〗', + 65073 => '—', + 65074 => '–', + 65081 => '〔', + 65082 => '〕', + 65083 => '【', + 65084 => '】', + 65085 => '《', + 65086 => '》', + 65087 => '〈', + 65088 => '〉', + 65089 => '「', + 65090 => '」', + 65091 => '『', + 65092 => '』', + 65105 => '、', + 65112 => '—', + 65117 => '〔', + 65118 => '〕', + 65123 => '-', + 65137 => 'ـً', + 65143 => 'ـَ', + 65145 => 'ـُ', + 65147 => 'ـِ', + 65149 => 'ـّ', + 65151 => 'ـْ', + 65152 => 'ء', + 65153 => 'آ', + 65154 => 'آ', + 65155 => 'أ', + 65156 => 'أ', + 65157 => 'ؤ', + 65158 => 'ؤ', + 65159 => 'إ', + 65160 => 'إ', + 65161 => 'ئ', + 65162 => 'ئ', + 65163 => 'ئ', + 65164 => 'ئ', + 65165 => 'ا', + 65166 => 'ا', + 65167 => 'ب', + 65168 => 'ب', + 65169 => 'ب', + 65170 => 'ب', + 65171 => 'ة', + 65172 => 'ة', + 65173 => 'ت', + 65174 => 'ت', + 65175 => 'ت', + 65176 => 'ت', + 65177 => 'ث', + 65178 => 'ث', + 65179 => 'ث', + 65180 => 'ث', + 65181 => 'ج', + 65182 => 'ج', + 65183 => 'ج', + 65184 => 'ج', + 65185 => 'ح', + 65186 => 'ح', + 65187 => 'ح', + 65188 => 'ح', + 65189 => 'خ', + 65190 => 'خ', + 65191 => 'خ', + 65192 => 'خ', + 65193 => 'د', + 65194 => 'د', + 65195 => 'ذ', + 65196 => 'ذ', + 65197 => 'ر', + 65198 => 'ر', + 65199 => 'ز', + 65200 => 'ز', + 65201 => 'س', + 65202 => 'س', + 65203 => 'س', + 65204 => 'س', + 65205 => 'ش', + 65206 => 'ش', + 65207 => 'ش', + 65208 => 'ش', + 65209 => 'ص', + 65210 => 'ص', + 65211 => 'ص', + 65212 => 'ص', + 65213 => 'ض', + 65214 => 'ض', + 65215 => 'ض', + 65216 => 'ض', + 65217 => 'ط', + 65218 => 'ط', + 65219 => 'ط', + 65220 => 'ط', + 65221 => 'ظ', + 65222 => 'ظ', + 65223 => 'ظ', + 65224 => 'ظ', + 65225 => 'ع', + 65226 => 'ع', + 65227 => 'ع', + 65228 => 'ع', + 65229 => 'غ', + 65230 => 'غ', + 65231 => 'غ', + 65232 => 'غ', + 65233 => 'ف', + 65234 => 'ف', + 65235 => 'ف', + 65236 => 'ف', + 65237 => 'ق', + 65238 => 'ق', + 65239 => 'ق', + 65240 => 'ق', + 65241 => 'ك', + 65242 => 'ك', + 65243 => 'ك', + 65244 => 'ك', + 65245 => 'ل', + 65246 => 'ل', + 65247 => 'ل', + 65248 => 'ل', + 65249 => 'م', + 65250 => 'م', + 65251 => 'م', + 65252 => 'م', + 65253 => 'ن', + 65254 => 'ن', + 65255 => 'ن', + 65256 => 'ن', + 65257 => 'ه', + 65258 => 'ه', + 65259 => 'ه', + 65260 => 'ه', + 65261 => 'و', + 65262 => 'و', + 65263 => 'ى', + 65264 => 'ى', + 65265 => 'ي', + 65266 => 'ي', + 65267 => 'ي', + 65268 => 'ي', + 65269 => 'لآ', + 65270 => 'لآ', + 65271 => 'لأ', + 65272 => 'لأ', + 65273 => 'لإ', + 65274 => 'لإ', + 65275 => 'لا', + 65276 => 'لا', + 65293 => '-', + 65294 => '.', + 65296 => '0', + 65297 => '1', + 65298 => '2', + 65299 => '3', + 65300 => '4', + 65301 => '5', + 65302 => '6', + 65303 => '7', + 65304 => '8', + 65305 => '9', + 65313 => 'a', + 65314 => 'b', + 65315 => 'c', + 65316 => 'd', + 65317 => 'e', + 65318 => 'f', + 65319 => 'g', + 65320 => 'h', + 65321 => 'i', + 65322 => 'j', + 65323 => 'k', + 65324 => 'l', + 65325 => 'm', + 65326 => 'n', + 65327 => 'o', + 65328 => 'p', + 65329 => 'q', + 65330 => 'r', + 65331 => 's', + 65332 => 't', + 65333 => 'u', + 65334 => 'v', + 65335 => 'w', + 65336 => 'x', + 65337 => 'y', + 65338 => 'z', + 65345 => 'a', + 65346 => 'b', + 65347 => 'c', + 65348 => 'd', + 65349 => 'e', + 65350 => 'f', + 65351 => 'g', + 65352 => 'h', + 65353 => 'i', + 65354 => 'j', + 65355 => 'k', + 65356 => 'l', + 65357 => 'm', + 65358 => 'n', + 65359 => 'o', + 65360 => 'p', + 65361 => 'q', + 65362 => 'r', + 65363 => 's', + 65364 => 't', + 65365 => 'u', + 65366 => 'v', + 65367 => 'w', + 65368 => 'x', + 65369 => 'y', + 65370 => 'z', + 65375 => '⦅', + 65376 => '⦆', + 65377 => '.', + 65378 => '「', + 65379 => '」', + 65380 => '、', + 65381 => '・', + 65382 => 'ヲ', + 65383 => 'ァ', + 65384 => 'ィ', + 65385 => 'ゥ', + 65386 => 'ェ', + 65387 => 'ォ', + 65388 => 'ャ', + 65389 => 'ュ', + 65390 => 'ョ', + 65391 => 'ッ', + 65392 => 'ー', + 65393 => 'ア', + 65394 => 'イ', + 65395 => 'ウ', + 65396 => 'エ', + 65397 => 'オ', + 65398 => 'カ', + 65399 => 'キ', + 65400 => 'ク', + 65401 => 'ケ', + 65402 => 'コ', + 65403 => 'サ', + 65404 => 'シ', + 65405 => 'ス', + 65406 => 'セ', + 65407 => 'ソ', + 65408 => 'タ', + 65409 => 'チ', + 65410 => 'ツ', + 65411 => 'テ', + 65412 => 'ト', + 65413 => 'ナ', + 65414 => 'ニ', + 65415 => 'ヌ', + 65416 => 'ネ', + 65417 => 'ノ', + 65418 => 'ハ', + 65419 => 'ヒ', + 65420 => 'フ', + 65421 => 'ヘ', + 65422 => 'ホ', + 65423 => 'マ', + 65424 => 'ミ', + 65425 => 'ム', + 65426 => 'メ', + 65427 => 'モ', + 65428 => 'ヤ', + 65429 => 'ユ', + 65430 => 'ヨ', + 65431 => 'ラ', + 65432 => 'リ', + 65433 => 'ル', + 65434 => 'レ', + 65435 => 'ロ', + 65436 => 'ワ', + 65437 => 'ン', + 65438 => '゙', + 65439 => '゚', + 65441 => 'ᄀ', + 65442 => 'ᄁ', + 65443 => 'ᆪ', + 65444 => 'ᄂ', + 65445 => 'ᆬ', + 65446 => 'ᆭ', + 65447 => 'ᄃ', + 65448 => 'ᄄ', + 65449 => 'ᄅ', + 65450 => 'ᆰ', + 65451 => 'ᆱ', + 65452 => 'ᆲ', + 65453 => 'ᆳ', + 65454 => 'ᆴ', + 65455 => 'ᆵ', + 65456 => 'ᄚ', + 65457 => 'ᄆ', + 65458 => 'ᄇ', + 65459 => 'ᄈ', + 65460 => 'ᄡ', + 65461 => 'ᄉ', + 65462 => 'ᄊ', + 65463 => 'ᄋ', + 65464 => 'ᄌ', + 65465 => 'ᄍ', + 65466 => 'ᄎ', + 65467 => 'ᄏ', + 65468 => 'ᄐ', + 65469 => 'ᄑ', + 65470 => 'ᄒ', + 65474 => 'ᅡ', + 65475 => 'ᅢ', + 65476 => 'ᅣ', + 65477 => 'ᅤ', + 65478 => 'ᅥ', + 65479 => 'ᅦ', + 65482 => 'ᅧ', + 65483 => 'ᅨ', + 65484 => 'ᅩ', + 65485 => 'ᅪ', + 65486 => 'ᅫ', + 65487 => 'ᅬ', + 65490 => 'ᅭ', + 65491 => 'ᅮ', + 65492 => 'ᅯ', + 65493 => 'ᅰ', + 65494 => 'ᅱ', + 65495 => 'ᅲ', + 65498 => 'ᅳ', + 65499 => 'ᅴ', + 65500 => 'ᅵ', + 65504 => '¢', + 65505 => '£', + 65506 => '¬', + 65508 => '¦', + 65509 => '¥', + 65510 => '₩', + 65512 => '│', + 65513 => '←', + 65514 => '↑', + 65515 => '→', + 65516 => '↓', + 65517 => '■', + 65518 => '○', + 66560 => '𐐨', + 66561 => '𐐩', + 66562 => '𐐪', + 66563 => '𐐫', + 66564 => '𐐬', + 66565 => '𐐭', + 66566 => '𐐮', + 66567 => '𐐯', + 66568 => '𐐰', + 66569 => '𐐱', + 66570 => '𐐲', + 66571 => '𐐳', + 66572 => '𐐴', + 66573 => '𐐵', + 66574 => '𐐶', + 66575 => '𐐷', + 66576 => '𐐸', + 66577 => '𐐹', + 66578 => '𐐺', + 66579 => '𐐻', + 66580 => '𐐼', + 66581 => '𐐽', + 66582 => '𐐾', + 66583 => '𐐿', + 66584 => '𐑀', + 66585 => '𐑁', + 66586 => '𐑂', + 66587 => '𐑃', + 66588 => '𐑄', + 66589 => '𐑅', + 66590 => '𐑆', + 66591 => '𐑇', + 66592 => '𐑈', + 66593 => '𐑉', + 66594 => '𐑊', + 66595 => '𐑋', + 66596 => '𐑌', + 66597 => '𐑍', + 66598 => '𐑎', + 66599 => '𐑏', + 66736 => '𐓘', + 66737 => '𐓙', + 66738 => '𐓚', + 66739 => '𐓛', + 66740 => '𐓜', + 66741 => '𐓝', + 66742 => '𐓞', + 66743 => '𐓟', + 66744 => '𐓠', + 66745 => '𐓡', + 66746 => '𐓢', + 66747 => '𐓣', + 66748 => '𐓤', + 66749 => '𐓥', + 66750 => '𐓦', + 66751 => '𐓧', + 66752 => '𐓨', + 66753 => '𐓩', + 66754 => '𐓪', + 66755 => '𐓫', + 66756 => '𐓬', + 66757 => '𐓭', + 66758 => '𐓮', + 66759 => '𐓯', + 66760 => '𐓰', + 66761 => '𐓱', + 66762 => '𐓲', + 66763 => '𐓳', + 66764 => '𐓴', + 66765 => '𐓵', + 66766 => '𐓶', + 66767 => '𐓷', + 66768 => '𐓸', + 66769 => '𐓹', + 66770 => '𐓺', + 66771 => '𐓻', + 68736 => '𐳀', + 68737 => '𐳁', + 68738 => '𐳂', + 68739 => '𐳃', + 68740 => '𐳄', + 68741 => '𐳅', + 68742 => '𐳆', + 68743 => '𐳇', + 68744 => '𐳈', + 68745 => '𐳉', + 68746 => '𐳊', + 68747 => '𐳋', + 68748 => '𐳌', + 68749 => '𐳍', + 68750 => '𐳎', + 68751 => '𐳏', + 68752 => '𐳐', + 68753 => '𐳑', + 68754 => '𐳒', + 68755 => '𐳓', + 68756 => '𐳔', + 68757 => '𐳕', + 68758 => '𐳖', + 68759 => '𐳗', + 68760 => '𐳘', + 68761 => '𐳙', + 68762 => '𐳚', + 68763 => '𐳛', + 68764 => '𐳜', + 68765 => '𐳝', + 68766 => '𐳞', + 68767 => '𐳟', + 68768 => '𐳠', + 68769 => '𐳡', + 68770 => '𐳢', + 68771 => '𐳣', + 68772 => '𐳤', + 68773 => '𐳥', + 68774 => '𐳦', + 68775 => '𐳧', + 68776 => '𐳨', + 68777 => '𐳩', + 68778 => '𐳪', + 68779 => '𐳫', + 68780 => '𐳬', + 68781 => '𐳭', + 68782 => '𐳮', + 68783 => '𐳯', + 68784 => '𐳰', + 68785 => '𐳱', + 68786 => '𐳲', + 71840 => '𑣀', + 71841 => '𑣁', + 71842 => '𑣂', + 71843 => '𑣃', + 71844 => '𑣄', + 71845 => '𑣅', + 71846 => '𑣆', + 71847 => '𑣇', + 71848 => '𑣈', + 71849 => '𑣉', + 71850 => '𑣊', + 71851 => '𑣋', + 71852 => '𑣌', + 71853 => '𑣍', + 71854 => '𑣎', + 71855 => '𑣏', + 71856 => '𑣐', + 71857 => '𑣑', + 71858 => '𑣒', + 71859 => '𑣓', + 71860 => '𑣔', + 71861 => '𑣕', + 71862 => '𑣖', + 71863 => '𑣗', + 71864 => '𑣘', + 71865 => '𑣙', + 71866 => '𑣚', + 71867 => '𑣛', + 71868 => '𑣜', + 71869 => '𑣝', + 71870 => '𑣞', + 71871 => '𑣟', + 93760 => '𖹠', + 93761 => '𖹡', + 93762 => '𖹢', + 93763 => '𖹣', + 93764 => '𖹤', + 93765 => '𖹥', + 93766 => '𖹦', + 93767 => '𖹧', + 93768 => '𖹨', + 93769 => '𖹩', + 93770 => '𖹪', + 93771 => '𖹫', + 93772 => '𖹬', + 93773 => '𖹭', + 93774 => '𖹮', + 93775 => '𖹯', + 93776 => '𖹰', + 93777 => '𖹱', + 93778 => '𖹲', + 93779 => '𖹳', + 93780 => '𖹴', + 93781 => '𖹵', + 93782 => '𖹶', + 93783 => '𖹷', + 93784 => '𖹸', + 93785 => '𖹹', + 93786 => '𖹺', + 93787 => '𖹻', + 93788 => '𖹼', + 93789 => '𖹽', + 93790 => '𖹾', + 93791 => '𖹿', + 119134 => '𝅗𝅥', + 119135 => '𝅘𝅥', + 119136 => '𝅘𝅥𝅮', + 119137 => '𝅘𝅥𝅯', + 119138 => '𝅘𝅥𝅰', + 119139 => '𝅘𝅥𝅱', + 119140 => '𝅘𝅥𝅲', + 119227 => '𝆹𝅥', + 119228 => '𝆺𝅥', + 119229 => '𝆹𝅥𝅮', + 119230 => '𝆺𝅥𝅮', + 119231 => '𝆹𝅥𝅯', + 119232 => '𝆺𝅥𝅯', + 119808 => 'a', + 119809 => 'b', + 119810 => 'c', + 119811 => 'd', + 119812 => 'e', + 119813 => 'f', + 119814 => 'g', + 119815 => 'h', + 119816 => 'i', + 119817 => 'j', + 119818 => 'k', + 119819 => 'l', + 119820 => 'm', + 119821 => 'n', + 119822 => 'o', + 119823 => 'p', + 119824 => 'q', + 119825 => 'r', + 119826 => 's', + 119827 => 't', + 119828 => 'u', + 119829 => 'v', + 119830 => 'w', + 119831 => 'x', + 119832 => 'y', + 119833 => 'z', + 119834 => 'a', + 119835 => 'b', + 119836 => 'c', + 119837 => 'd', + 119838 => 'e', + 119839 => 'f', + 119840 => 'g', + 119841 => 'h', + 119842 => 'i', + 119843 => 'j', + 119844 => 'k', + 119845 => 'l', + 119846 => 'm', + 119847 => 'n', + 119848 => 'o', + 119849 => 'p', + 119850 => 'q', + 119851 => 'r', + 119852 => 's', + 119853 => 't', + 119854 => 'u', + 119855 => 'v', + 119856 => 'w', + 119857 => 'x', + 119858 => 'y', + 119859 => 'z', + 119860 => 'a', + 119861 => 'b', + 119862 => 'c', + 119863 => 'd', + 119864 => 'e', + 119865 => 'f', + 119866 => 'g', + 119867 => 'h', + 119868 => 'i', + 119869 => 'j', + 119870 => 'k', + 119871 => 'l', + 119872 => 'm', + 119873 => 'n', + 119874 => 'o', + 119875 => 'p', + 119876 => 'q', + 119877 => 'r', + 119878 => 's', + 119879 => 't', + 119880 => 'u', + 119881 => 'v', + 119882 => 'w', + 119883 => 'x', + 119884 => 'y', + 119885 => 'z', + 119886 => 'a', + 119887 => 'b', + 119888 => 'c', + 119889 => 'd', + 119890 => 'e', + 119891 => 'f', + 119892 => 'g', + 119894 => 'i', + 119895 => 'j', + 119896 => 'k', + 119897 => 'l', + 119898 => 'm', + 119899 => 'n', + 119900 => 'o', + 119901 => 'p', + 119902 => 'q', + 119903 => 'r', + 119904 => 's', + 119905 => 't', + 119906 => 'u', + 119907 => 'v', + 119908 => 'w', + 119909 => 'x', + 119910 => 'y', + 119911 => 'z', + 119912 => 'a', + 119913 => 'b', + 119914 => 'c', + 119915 => 'd', + 119916 => 'e', + 119917 => 'f', + 119918 => 'g', + 119919 => 'h', + 119920 => 'i', + 119921 => 'j', + 119922 => 'k', + 119923 => 'l', + 119924 => 'm', + 119925 => 'n', + 119926 => 'o', + 119927 => 'p', + 119928 => 'q', + 119929 => 'r', + 119930 => 's', + 119931 => 't', + 119932 => 'u', + 119933 => 'v', + 119934 => 'w', + 119935 => 'x', + 119936 => 'y', + 119937 => 'z', + 119938 => 'a', + 119939 => 'b', + 119940 => 'c', + 119941 => 'd', + 119942 => 'e', + 119943 => 'f', + 119944 => 'g', + 119945 => 'h', + 119946 => 'i', + 119947 => 'j', + 119948 => 'k', + 119949 => 'l', + 119950 => 'm', + 119951 => 'n', + 119952 => 'o', + 119953 => 'p', + 119954 => 'q', + 119955 => 'r', + 119956 => 's', + 119957 => 't', + 119958 => 'u', + 119959 => 'v', + 119960 => 'w', + 119961 => 'x', + 119962 => 'y', + 119963 => 'z', + 119964 => 'a', + 119966 => 'c', + 119967 => 'd', + 119970 => 'g', + 119973 => 'j', + 119974 => 'k', + 119977 => 'n', + 119978 => 'o', + 119979 => 'p', + 119980 => 'q', + 119982 => 's', + 119983 => 't', + 119984 => 'u', + 119985 => 'v', + 119986 => 'w', + 119987 => 'x', + 119988 => 'y', + 119989 => 'z', + 119990 => 'a', + 119991 => 'b', + 119992 => 'c', + 119993 => 'd', + 119995 => 'f', + 119997 => 'h', + 119998 => 'i', + 119999 => 'j', + 120000 => 'k', + 120001 => 'l', + 120002 => 'm', + 120003 => 'n', + 120005 => 'p', + 120006 => 'q', + 120007 => 'r', + 120008 => 's', + 120009 => 't', + 120010 => 'u', + 120011 => 'v', + 120012 => 'w', + 120013 => 'x', + 120014 => 'y', + 120015 => 'z', + 120016 => 'a', + 120017 => 'b', + 120018 => 'c', + 120019 => 'd', + 120020 => 'e', + 120021 => 'f', + 120022 => 'g', + 120023 => 'h', + 120024 => 'i', + 120025 => 'j', + 120026 => 'k', + 120027 => 'l', + 120028 => 'm', + 120029 => 'n', + 120030 => 'o', + 120031 => 'p', + 120032 => 'q', + 120033 => 'r', + 120034 => 's', + 120035 => 't', + 120036 => 'u', + 120037 => 'v', + 120038 => 'w', + 120039 => 'x', + 120040 => 'y', + 120041 => 'z', + 120042 => 'a', + 120043 => 'b', + 120044 => 'c', + 120045 => 'd', + 120046 => 'e', + 120047 => 'f', + 120048 => 'g', + 120049 => 'h', + 120050 => 'i', + 120051 => 'j', + 120052 => 'k', + 120053 => 'l', + 120054 => 'm', + 120055 => 'n', + 120056 => 'o', + 120057 => 'p', + 120058 => 'q', + 120059 => 'r', + 120060 => 's', + 120061 => 't', + 120062 => 'u', + 120063 => 'v', + 120064 => 'w', + 120065 => 'x', + 120066 => 'y', + 120067 => 'z', + 120068 => 'a', + 120069 => 'b', + 120071 => 'd', + 120072 => 'e', + 120073 => 'f', + 120074 => 'g', + 120077 => 'j', + 120078 => 'k', + 120079 => 'l', + 120080 => 'm', + 120081 => 'n', + 120082 => 'o', + 120083 => 'p', + 120084 => 'q', + 120086 => 's', + 120087 => 't', + 120088 => 'u', + 120089 => 'v', + 120090 => 'w', + 120091 => 'x', + 120092 => 'y', + 120094 => 'a', + 120095 => 'b', + 120096 => 'c', + 120097 => 'd', + 120098 => 'e', + 120099 => 'f', + 120100 => 'g', + 120101 => 'h', + 120102 => 'i', + 120103 => 'j', + 120104 => 'k', + 120105 => 'l', + 120106 => 'm', + 120107 => 'n', + 120108 => 'o', + 120109 => 'p', + 120110 => 'q', + 120111 => 'r', + 120112 => 's', + 120113 => 't', + 120114 => 'u', + 120115 => 'v', + 120116 => 'w', + 120117 => 'x', + 120118 => 'y', + 120119 => 'z', + 120120 => 'a', + 120121 => 'b', + 120123 => 'd', + 120124 => 'e', + 120125 => 'f', + 120126 => 'g', + 120128 => 'i', + 120129 => 'j', + 120130 => 'k', + 120131 => 'l', + 120132 => 'm', + 120134 => 'o', + 120138 => 's', + 120139 => 't', + 120140 => 'u', + 120141 => 'v', + 120142 => 'w', + 120143 => 'x', + 120144 => 'y', + 120146 => 'a', + 120147 => 'b', + 120148 => 'c', + 120149 => 'd', + 120150 => 'e', + 120151 => 'f', + 120152 => 'g', + 120153 => 'h', + 120154 => 'i', + 120155 => 'j', + 120156 => 'k', + 120157 => 'l', + 120158 => 'm', + 120159 => 'n', + 120160 => 'o', + 120161 => 'p', + 120162 => 'q', + 120163 => 'r', + 120164 => 's', + 120165 => 't', + 120166 => 'u', + 120167 => 'v', + 120168 => 'w', + 120169 => 'x', + 120170 => 'y', + 120171 => 'z', + 120172 => 'a', + 120173 => 'b', + 120174 => 'c', + 120175 => 'd', + 120176 => 'e', + 120177 => 'f', + 120178 => 'g', + 120179 => 'h', + 120180 => 'i', + 120181 => 'j', + 120182 => 'k', + 120183 => 'l', + 120184 => 'm', + 120185 => 'n', + 120186 => 'o', + 120187 => 'p', + 120188 => 'q', + 120189 => 'r', + 120190 => 's', + 120191 => 't', + 120192 => 'u', + 120193 => 'v', + 120194 => 'w', + 120195 => 'x', + 120196 => 'y', + 120197 => 'z', + 120198 => 'a', + 120199 => 'b', + 120200 => 'c', + 120201 => 'd', + 120202 => 'e', + 120203 => 'f', + 120204 => 'g', + 120205 => 'h', + 120206 => 'i', + 120207 => 'j', + 120208 => 'k', + 120209 => 'l', + 120210 => 'm', + 120211 => 'n', + 120212 => 'o', + 120213 => 'p', + 120214 => 'q', + 120215 => 'r', + 120216 => 's', + 120217 => 't', + 120218 => 'u', + 120219 => 'v', + 120220 => 'w', + 120221 => 'x', + 120222 => 'y', + 120223 => 'z', + 120224 => 'a', + 120225 => 'b', + 120226 => 'c', + 120227 => 'd', + 120228 => 'e', + 120229 => 'f', + 120230 => 'g', + 120231 => 'h', + 120232 => 'i', + 120233 => 'j', + 120234 => 'k', + 120235 => 'l', + 120236 => 'm', + 120237 => 'n', + 120238 => 'o', + 120239 => 'p', + 120240 => 'q', + 120241 => 'r', + 120242 => 's', + 120243 => 't', + 120244 => 'u', + 120245 => 'v', + 120246 => 'w', + 120247 => 'x', + 120248 => 'y', + 120249 => 'z', + 120250 => 'a', + 120251 => 'b', + 120252 => 'c', + 120253 => 'd', + 120254 => 'e', + 120255 => 'f', + 120256 => 'g', + 120257 => 'h', + 120258 => 'i', + 120259 => 'j', + 120260 => 'k', + 120261 => 'l', + 120262 => 'm', + 120263 => 'n', + 120264 => 'o', + 120265 => 'p', + 120266 => 'q', + 120267 => 'r', + 120268 => 's', + 120269 => 't', + 120270 => 'u', + 120271 => 'v', + 120272 => 'w', + 120273 => 'x', + 120274 => 'y', + 120275 => 'z', + 120276 => 'a', + 120277 => 'b', + 120278 => 'c', + 120279 => 'd', + 120280 => 'e', + 120281 => 'f', + 120282 => 'g', + 120283 => 'h', + 120284 => 'i', + 120285 => 'j', + 120286 => 'k', + 120287 => 'l', + 120288 => 'm', + 120289 => 'n', + 120290 => 'o', + 120291 => 'p', + 120292 => 'q', + 120293 => 'r', + 120294 => 's', + 120295 => 't', + 120296 => 'u', + 120297 => 'v', + 120298 => 'w', + 120299 => 'x', + 120300 => 'y', + 120301 => 'z', + 120302 => 'a', + 120303 => 'b', + 120304 => 'c', + 120305 => 'd', + 120306 => 'e', + 120307 => 'f', + 120308 => 'g', + 120309 => 'h', + 120310 => 'i', + 120311 => 'j', + 120312 => 'k', + 120313 => 'l', + 120314 => 'm', + 120315 => 'n', + 120316 => 'o', + 120317 => 'p', + 120318 => 'q', + 120319 => 'r', + 120320 => 's', + 120321 => 't', + 120322 => 'u', + 120323 => 'v', + 120324 => 'w', + 120325 => 'x', + 120326 => 'y', + 120327 => 'z', + 120328 => 'a', + 120329 => 'b', + 120330 => 'c', + 120331 => 'd', + 120332 => 'e', + 120333 => 'f', + 120334 => 'g', + 120335 => 'h', + 120336 => 'i', + 120337 => 'j', + 120338 => 'k', + 120339 => 'l', + 120340 => 'm', + 120341 => 'n', + 120342 => 'o', + 120343 => 'p', + 120344 => 'q', + 120345 => 'r', + 120346 => 's', + 120347 => 't', + 120348 => 'u', + 120349 => 'v', + 120350 => 'w', + 120351 => 'x', + 120352 => 'y', + 120353 => 'z', + 120354 => 'a', + 120355 => 'b', + 120356 => 'c', + 120357 => 'd', + 120358 => 'e', + 120359 => 'f', + 120360 => 'g', + 120361 => 'h', + 120362 => 'i', + 120363 => 'j', + 120364 => 'k', + 120365 => 'l', + 120366 => 'm', + 120367 => 'n', + 120368 => 'o', + 120369 => 'p', + 120370 => 'q', + 120371 => 'r', + 120372 => 's', + 120373 => 't', + 120374 => 'u', + 120375 => 'v', + 120376 => 'w', + 120377 => 'x', + 120378 => 'y', + 120379 => 'z', + 120380 => 'a', + 120381 => 'b', + 120382 => 'c', + 120383 => 'd', + 120384 => 'e', + 120385 => 'f', + 120386 => 'g', + 120387 => 'h', + 120388 => 'i', + 120389 => 'j', + 120390 => 'k', + 120391 => 'l', + 120392 => 'm', + 120393 => 'n', + 120394 => 'o', + 120395 => 'p', + 120396 => 'q', + 120397 => 'r', + 120398 => 's', + 120399 => 't', + 120400 => 'u', + 120401 => 'v', + 120402 => 'w', + 120403 => 'x', + 120404 => 'y', + 120405 => 'z', + 120406 => 'a', + 120407 => 'b', + 120408 => 'c', + 120409 => 'd', + 120410 => 'e', + 120411 => 'f', + 120412 => 'g', + 120413 => 'h', + 120414 => 'i', + 120415 => 'j', + 120416 => 'k', + 120417 => 'l', + 120418 => 'm', + 120419 => 'n', + 120420 => 'o', + 120421 => 'p', + 120422 => 'q', + 120423 => 'r', + 120424 => 's', + 120425 => 't', + 120426 => 'u', + 120427 => 'v', + 120428 => 'w', + 120429 => 'x', + 120430 => 'y', + 120431 => 'z', + 120432 => 'a', + 120433 => 'b', + 120434 => 'c', + 120435 => 'd', + 120436 => 'e', + 120437 => 'f', + 120438 => 'g', + 120439 => 'h', + 120440 => 'i', + 120441 => 'j', + 120442 => 'k', + 120443 => 'l', + 120444 => 'm', + 120445 => 'n', + 120446 => 'o', + 120447 => 'p', + 120448 => 'q', + 120449 => 'r', + 120450 => 's', + 120451 => 't', + 120452 => 'u', + 120453 => 'v', + 120454 => 'w', + 120455 => 'x', + 120456 => 'y', + 120457 => 'z', + 120458 => 'a', + 120459 => 'b', + 120460 => 'c', + 120461 => 'd', + 120462 => 'e', + 120463 => 'f', + 120464 => 'g', + 120465 => 'h', + 120466 => 'i', + 120467 => 'j', + 120468 => 'k', + 120469 => 'l', + 120470 => 'm', + 120471 => 'n', + 120472 => 'o', + 120473 => 'p', + 120474 => 'q', + 120475 => 'r', + 120476 => 's', + 120477 => 't', + 120478 => 'u', + 120479 => 'v', + 120480 => 'w', + 120481 => 'x', + 120482 => 'y', + 120483 => 'z', + 120484 => 'ı', + 120485 => 'ȷ', + 120488 => 'α', + 120489 => 'β', + 120490 => 'γ', + 120491 => 'δ', + 120492 => 'ε', + 120493 => 'ζ', + 120494 => 'η', + 120495 => 'θ', + 120496 => 'ι', + 120497 => 'κ', + 120498 => 'λ', + 120499 => 'μ', + 120500 => 'ν', + 120501 => 'ξ', + 120502 => 'ο', + 120503 => 'π', + 120504 => 'ρ', + 120505 => 'θ', + 120506 => 'σ', + 120507 => 'τ', + 120508 => 'υ', + 120509 => 'φ', + 120510 => 'χ', + 120511 => 'ψ', + 120512 => 'ω', + 120513 => '∇', + 120514 => 'α', + 120515 => 'β', + 120516 => 'γ', + 120517 => 'δ', + 120518 => 'ε', + 120519 => 'ζ', + 120520 => 'η', + 120521 => 'θ', + 120522 => 'ι', + 120523 => 'κ', + 120524 => 'λ', + 120525 => 'μ', + 120526 => 'ν', + 120527 => 'ξ', + 120528 => 'ο', + 120529 => 'π', + 120530 => 'ρ', + 120531 => 'σ', + 120532 => 'σ', + 120533 => 'τ', + 120534 => 'υ', + 120535 => 'φ', + 120536 => 'χ', + 120537 => 'ψ', + 120538 => 'ω', + 120539 => '∂', + 120540 => 'ε', + 120541 => 'θ', + 120542 => 'κ', + 120543 => 'φ', + 120544 => 'ρ', + 120545 => 'π', + 120546 => 'α', + 120547 => 'β', + 120548 => 'γ', + 120549 => 'δ', + 120550 => 'ε', + 120551 => 'ζ', + 120552 => 'η', + 120553 => 'θ', + 120554 => 'ι', + 120555 => 'κ', + 120556 => 'λ', + 120557 => 'μ', + 120558 => 'ν', + 120559 => 'ξ', + 120560 => 'ο', + 120561 => 'π', + 120562 => 'ρ', + 120563 => 'θ', + 120564 => 'σ', + 120565 => 'τ', + 120566 => 'υ', + 120567 => 'φ', + 120568 => 'χ', + 120569 => 'ψ', + 120570 => 'ω', + 120571 => '∇', + 120572 => 'α', + 120573 => 'β', + 120574 => 'γ', + 120575 => 'δ', + 120576 => 'ε', + 120577 => 'ζ', + 120578 => 'η', + 120579 => 'θ', + 120580 => 'ι', + 120581 => 'κ', + 120582 => 'λ', + 120583 => 'μ', + 120584 => 'ν', + 120585 => 'ξ', + 120586 => 'ο', + 120587 => 'π', + 120588 => 'ρ', + 120589 => 'σ', + 120590 => 'σ', + 120591 => 'τ', + 120592 => 'υ', + 120593 => 'φ', + 120594 => 'χ', + 120595 => 'ψ', + 120596 => 'ω', + 120597 => '∂', + 120598 => 'ε', + 120599 => 'θ', + 120600 => 'κ', + 120601 => 'φ', + 120602 => 'ρ', + 120603 => 'π', + 120604 => 'α', + 120605 => 'β', + 120606 => 'γ', + 120607 => 'δ', + 120608 => 'ε', + 120609 => 'ζ', + 120610 => 'η', + 120611 => 'θ', + 120612 => 'ι', + 120613 => 'κ', + 120614 => 'λ', + 120615 => 'μ', + 120616 => 'ν', + 120617 => 'ξ', + 120618 => 'ο', + 120619 => 'π', + 120620 => 'ρ', + 120621 => 'θ', + 120622 => 'σ', + 120623 => 'τ', + 120624 => 'υ', + 120625 => 'φ', + 120626 => 'χ', + 120627 => 'ψ', + 120628 => 'ω', + 120629 => '∇', + 120630 => 'α', + 120631 => 'β', + 120632 => 'γ', + 120633 => 'δ', + 120634 => 'ε', + 120635 => 'ζ', + 120636 => 'η', + 120637 => 'θ', + 120638 => 'ι', + 120639 => 'κ', + 120640 => 'λ', + 120641 => 'μ', + 120642 => 'ν', + 120643 => 'ξ', + 120644 => 'ο', + 120645 => 'π', + 120646 => 'ρ', + 120647 => 'σ', + 120648 => 'σ', + 120649 => 'τ', + 120650 => 'υ', + 120651 => 'φ', + 120652 => 'χ', + 120653 => 'ψ', + 120654 => 'ω', + 120655 => '∂', + 120656 => 'ε', + 120657 => 'θ', + 120658 => 'κ', + 120659 => 'φ', + 120660 => 'ρ', + 120661 => 'π', + 120662 => 'α', + 120663 => 'β', + 120664 => 'γ', + 120665 => 'δ', + 120666 => 'ε', + 120667 => 'ζ', + 120668 => 'η', + 120669 => 'θ', + 120670 => 'ι', + 120671 => 'κ', + 120672 => 'λ', + 120673 => 'μ', + 120674 => 'ν', + 120675 => 'ξ', + 120676 => 'ο', + 120677 => 'π', + 120678 => 'ρ', + 120679 => 'θ', + 120680 => 'σ', + 120681 => 'τ', + 120682 => 'υ', + 120683 => 'φ', + 120684 => 'χ', + 120685 => 'ψ', + 120686 => 'ω', + 120687 => '∇', + 120688 => 'α', + 120689 => 'β', + 120690 => 'γ', + 120691 => 'δ', + 120692 => 'ε', + 120693 => 'ζ', + 120694 => 'η', + 120695 => 'θ', + 120696 => 'ι', + 120697 => 'κ', + 120698 => 'λ', + 120699 => 'μ', + 120700 => 'ν', + 120701 => 'ξ', + 120702 => 'ο', + 120703 => 'π', + 120704 => 'ρ', + 120705 => 'σ', + 120706 => 'σ', + 120707 => 'τ', + 120708 => 'υ', + 120709 => 'φ', + 120710 => 'χ', + 120711 => 'ψ', + 120712 => 'ω', + 120713 => '∂', + 120714 => 'ε', + 120715 => 'θ', + 120716 => 'κ', + 120717 => 'φ', + 120718 => 'ρ', + 120719 => 'π', + 120720 => 'α', + 120721 => 'β', + 120722 => 'γ', + 120723 => 'δ', + 120724 => 'ε', + 120725 => 'ζ', + 120726 => 'η', + 120727 => 'θ', + 120728 => 'ι', + 120729 => 'κ', + 120730 => 'λ', + 120731 => 'μ', + 120732 => 'ν', + 120733 => 'ξ', + 120734 => 'ο', + 120735 => 'π', + 120736 => 'ρ', + 120737 => 'θ', + 120738 => 'σ', + 120739 => 'τ', + 120740 => 'υ', + 120741 => 'φ', + 120742 => 'χ', + 120743 => 'ψ', + 120744 => 'ω', + 120745 => '∇', + 120746 => 'α', + 120747 => 'β', + 120748 => 'γ', + 120749 => 'δ', + 120750 => 'ε', + 120751 => 'ζ', + 120752 => 'η', + 120753 => 'θ', + 120754 => 'ι', + 120755 => 'κ', + 120756 => 'λ', + 120757 => 'μ', + 120758 => 'ν', + 120759 => 'ξ', + 120760 => 'ο', + 120761 => 'π', + 120762 => 'ρ', + 120763 => 'σ', + 120764 => 'σ', + 120765 => 'τ', + 120766 => 'υ', + 120767 => 'φ', + 120768 => 'χ', + 120769 => 'ψ', + 120770 => 'ω', + 120771 => '∂', + 120772 => 'ε', + 120773 => 'θ', + 120774 => 'κ', + 120775 => 'φ', + 120776 => 'ρ', + 120777 => 'π', + 120778 => 'ϝ', + 120779 => 'ϝ', + 120782 => '0', + 120783 => '1', + 120784 => '2', + 120785 => '3', + 120786 => '4', + 120787 => '5', + 120788 => '6', + 120789 => '7', + 120790 => '8', + 120791 => '9', + 120792 => '0', + 120793 => '1', + 120794 => '2', + 120795 => '3', + 120796 => '4', + 120797 => '5', + 120798 => '6', + 120799 => '7', + 120800 => '8', + 120801 => '9', + 120802 => '0', + 120803 => '1', + 120804 => '2', + 120805 => '3', + 120806 => '4', + 120807 => '5', + 120808 => '6', + 120809 => '7', + 120810 => '8', + 120811 => '9', + 120812 => '0', + 120813 => '1', + 120814 => '2', + 120815 => '3', + 120816 => '4', + 120817 => '5', + 120818 => '6', + 120819 => '7', + 120820 => '8', + 120821 => '9', + 120822 => '0', + 120823 => '1', + 120824 => '2', + 120825 => '3', + 120826 => '4', + 120827 => '5', + 120828 => '6', + 120829 => '7', + 120830 => '8', + 120831 => '9', + 125184 => '𞤢', + 125185 => '𞤣', + 125186 => '𞤤', + 125187 => '𞤥', + 125188 => '𞤦', + 125189 => '𞤧', + 125190 => '𞤨', + 125191 => '𞤩', + 125192 => '𞤪', + 125193 => '𞤫', + 125194 => '𞤬', + 125195 => '𞤭', + 125196 => '𞤮', + 125197 => '𞤯', + 125198 => '𞤰', + 125199 => '𞤱', + 125200 => '𞤲', + 125201 => '𞤳', + 125202 => '𞤴', + 125203 => '𞤵', + 125204 => '𞤶', + 125205 => '𞤷', + 125206 => '𞤸', + 125207 => '𞤹', + 125208 => '𞤺', + 125209 => '𞤻', + 125210 => '𞤼', + 125211 => '𞤽', + 125212 => '𞤾', + 125213 => '𞤿', + 125214 => '𞥀', + 125215 => '𞥁', + 125216 => '𞥂', + 125217 => '𞥃', + 126464 => 'ا', + 126465 => 'ب', + 126466 => 'ج', + 126467 => 'د', + 126469 => 'و', + 126470 => 'ز', + 126471 => 'ح', + 126472 => 'ط', + 126473 => 'ي', + 126474 => 'ك', + 126475 => 'ل', + 126476 => 'م', + 126477 => 'ن', + 126478 => 'س', + 126479 => 'ع', + 126480 => 'ف', + 126481 => 'ص', + 126482 => 'ق', + 126483 => 'ر', + 126484 => 'ش', + 126485 => 'ت', + 126486 => 'ث', + 126487 => 'خ', + 126488 => 'ذ', + 126489 => 'ض', + 126490 => 'ظ', + 126491 => 'غ', + 126492 => 'ٮ', + 126493 => 'ں', + 126494 => 'ڡ', + 126495 => 'ٯ', + 126497 => 'ب', + 126498 => 'ج', + 126500 => 'ه', + 126503 => 'ح', + 126505 => 'ي', + 126506 => 'ك', + 126507 => 'ل', + 126508 => 'م', + 126509 => 'ن', + 126510 => 'س', + 126511 => 'ع', + 126512 => 'ف', + 126513 => 'ص', + 126514 => 'ق', + 126516 => 'ش', + 126517 => 'ت', + 126518 => 'ث', + 126519 => 'خ', + 126521 => 'ض', + 126523 => 'غ', + 126530 => 'ج', + 126535 => 'ح', + 126537 => 'ي', + 126539 => 'ل', + 126541 => 'ن', + 126542 => 'س', + 126543 => 'ع', + 126545 => 'ص', + 126546 => 'ق', + 126548 => 'ش', + 126551 => 'خ', + 126553 => 'ض', + 126555 => 'غ', + 126557 => 'ں', + 126559 => 'ٯ', + 126561 => 'ب', + 126562 => 'ج', + 126564 => 'ه', + 126567 => 'ح', + 126568 => 'ط', + 126569 => 'ي', + 126570 => 'ك', + 126572 => 'م', + 126573 => 'ن', + 126574 => 'س', + 126575 => 'ع', + 126576 => 'ف', + 126577 => 'ص', + 126578 => 'ق', + 126580 => 'ش', + 126581 => 'ت', + 126582 => 'ث', + 126583 => 'خ', + 126585 => 'ض', + 126586 => 'ظ', + 126587 => 'غ', + 126588 => 'ٮ', + 126590 => 'ڡ', + 126592 => 'ا', + 126593 => 'ب', + 126594 => 'ج', + 126595 => 'د', + 126596 => 'ه', + 126597 => 'و', + 126598 => 'ز', + 126599 => 'ح', + 126600 => 'ط', + 126601 => 'ي', + 126603 => 'ل', + 126604 => 'م', + 126605 => 'ن', + 126606 => 'س', + 126607 => 'ع', + 126608 => 'ف', + 126609 => 'ص', + 126610 => 'ق', + 126611 => 'ر', + 126612 => 'ش', + 126613 => 'ت', + 126614 => 'ث', + 126615 => 'خ', + 126616 => 'ذ', + 126617 => 'ض', + 126618 => 'ظ', + 126619 => 'غ', + 126625 => 'ب', + 126626 => 'ج', + 126627 => 'د', + 126629 => 'و', + 126630 => 'ز', + 126631 => 'ح', + 126632 => 'ط', + 126633 => 'ي', + 126635 => 'ل', + 126636 => 'م', + 126637 => 'ن', + 126638 => 'س', + 126639 => 'ع', + 126640 => 'ف', + 126641 => 'ص', + 126642 => 'ق', + 126643 => 'ر', + 126644 => 'ش', + 126645 => 'ت', + 126646 => 'ث', + 126647 => 'خ', + 126648 => 'ذ', + 126649 => 'ض', + 126650 => 'ظ', + 126651 => 'غ', + 127274 => '〔s〕', + 127275 => 'c', + 127276 => 'r', + 127277 => 'cd', + 127278 => 'wz', + 127280 => 'a', + 127281 => 'b', + 127282 => 'c', + 127283 => 'd', + 127284 => 'e', + 127285 => 'f', + 127286 => 'g', + 127287 => 'h', + 127288 => 'i', + 127289 => 'j', + 127290 => 'k', + 127291 => 'l', + 127292 => 'm', + 127293 => 'n', + 127294 => 'o', + 127295 => 'p', + 127296 => 'q', + 127297 => 'r', + 127298 => 's', + 127299 => 't', + 127300 => 'u', + 127301 => 'v', + 127302 => 'w', + 127303 => 'x', + 127304 => 'y', + 127305 => 'z', + 127306 => 'hv', + 127307 => 'mv', + 127308 => 'sd', + 127309 => 'ss', + 127310 => 'ppv', + 127311 => 'wc', + 127338 => 'mc', + 127339 => 'md', + 127340 => 'mr', + 127376 => 'dj', + 127488 => 'ほか', + 127489 => 'ココ', + 127490 => 'サ', + 127504 => '手', + 127505 => '字', + 127506 => '双', + 127507 => 'デ', + 127508 => '二', + 127509 => '多', + 127510 => '解', + 127511 => '天', + 127512 => '交', + 127513 => '映', + 127514 => '無', + 127515 => '料', + 127516 => '前', + 127517 => '後', + 127518 => '再', + 127519 => '新', + 127520 => '初', + 127521 => '終', + 127522 => '生', + 127523 => '販', + 127524 => '声', + 127525 => '吹', + 127526 => '演', + 127527 => '投', + 127528 => '捕', + 127529 => '一', + 127530 => '三', + 127531 => '遊', + 127532 => '左', + 127533 => '中', + 127534 => '右', + 127535 => '指', + 127536 => '走', + 127537 => '打', + 127538 => '禁', + 127539 => '空', + 127540 => '合', + 127541 => '満', + 127542 => '有', + 127543 => '月', + 127544 => '申', + 127545 => '割', + 127546 => '営', + 127547 => '配', + 127552 => '〔本〕', + 127553 => '〔三〕', + 127554 => '〔二〕', + 127555 => '〔安〕', + 127556 => '〔点〕', + 127557 => '〔打〕', + 127558 => '〔盗〕', + 127559 => '〔勝〕', + 127560 => '〔敗〕', + 127568 => '得', + 127569 => '可', + 130032 => '0', + 130033 => '1', + 130034 => '2', + 130035 => '3', + 130036 => '4', + 130037 => '5', + 130038 => '6', + 130039 => '7', + 130040 => '8', + 130041 => '9', + 194560 => '丽', + 194561 => '丸', + 194562 => '乁', + 194563 => '𠄢', + 194564 => '你', + 194565 => '侮', + 194566 => '侻', + 194567 => '倂', + 194568 => '偺', + 194569 => '備', + 194570 => '僧', + 194571 => '像', + 194572 => '㒞', + 194573 => '𠘺', + 194574 => '免', + 194575 => '兔', + 194576 => '兤', + 194577 => '具', + 194578 => '𠔜', + 194579 => '㒹', + 194580 => '內', + 194581 => '再', + 194582 => '𠕋', + 194583 => '冗', + 194584 => '冤', + 194585 => '仌', + 194586 => '冬', + 194587 => '况', + 194588 => '𩇟', + 194589 => '凵', + 194590 => '刃', + 194591 => '㓟', + 194592 => '刻', + 194593 => '剆', + 194594 => '割', + 194595 => '剷', + 194596 => '㔕', + 194597 => '勇', + 194598 => '勉', + 194599 => '勤', + 194600 => '勺', + 194601 => '包', + 194602 => '匆', + 194603 => '北', + 194604 => '卉', + 194605 => '卑', + 194606 => '博', + 194607 => '即', + 194608 => '卽', + 194609 => '卿', + 194610 => '卿', + 194611 => '卿', + 194612 => '𠨬', + 194613 => '灰', + 194614 => '及', + 194615 => '叟', + 194616 => '𠭣', + 194617 => '叫', + 194618 => '叱', + 194619 => '吆', + 194620 => '咞', + 194621 => '吸', + 194622 => '呈', + 194623 => '周', + 194624 => '咢', + 194625 => '哶', + 194626 => '唐', + 194627 => '啓', + 194628 => '啣', + 194629 => '善', + 194630 => '善', + 194631 => '喙', + 194632 => '喫', + 194633 => '喳', + 194634 => '嗂', + 194635 => '圖', + 194636 => '嘆', + 194637 => '圗', + 194638 => '噑', + 194639 => '噴', + 194640 => '切', + 194641 => '壮', + 194642 => '城', + 194643 => '埴', + 194644 => '堍', + 194645 => '型', + 194646 => '堲', + 194647 => '報', + 194648 => '墬', + 194649 => '𡓤', + 194650 => '売', + 194651 => '壷', + 194652 => '夆', + 194653 => '多', + 194654 => '夢', + 194655 => '奢', + 194656 => '𡚨', + 194657 => '𡛪', + 194658 => '姬', + 194659 => '娛', + 194660 => '娧', + 194661 => '姘', + 194662 => '婦', + 194663 => '㛮', + 194665 => '嬈', + 194666 => '嬾', + 194667 => '嬾', + 194668 => '𡧈', + 194669 => '寃', + 194670 => '寘', + 194671 => '寧', + 194672 => '寳', + 194673 => '𡬘', + 194674 => '寿', + 194675 => '将', + 194677 => '尢', + 194678 => '㞁', + 194679 => '屠', + 194680 => '屮', + 194681 => '峀', + 194682 => '岍', + 194683 => '𡷤', + 194684 => '嵃', + 194685 => '𡷦', + 194686 => '嵮', + 194687 => '嵫', + 194688 => '嵼', + 194689 => '巡', + 194690 => '巢', + 194691 => '㠯', + 194692 => '巽', + 194693 => '帨', + 194694 => '帽', + 194695 => '幩', + 194696 => '㡢', + 194697 => '𢆃', + 194698 => '㡼', + 194699 => '庰', + 194700 => '庳', + 194701 => '庶', + 194702 => '廊', + 194703 => '𪎒', + 194704 => '廾', + 194705 => '𢌱', + 194706 => '𢌱', + 194707 => '舁', + 194708 => '弢', + 194709 => '弢', + 194710 => '㣇', + 194711 => '𣊸', + 194712 => '𦇚', + 194713 => '形', + 194714 => '彫', + 194715 => '㣣', + 194716 => '徚', + 194717 => '忍', + 194718 => '志', + 194719 => '忹', + 194720 => '悁', + 194721 => '㤺', + 194722 => '㤜', + 194723 => '悔', + 194724 => '𢛔', + 194725 => '惇', + 194726 => '慈', + 194727 => '慌', + 194728 => '慎', + 194729 => '慌', + 194730 => '慺', + 194731 => '憎', + 194732 => '憲', + 194733 => '憤', + 194734 => '憯', + 194735 => '懞', + 194736 => '懲', + 194737 => '懶', + 194738 => '成', + 194739 => '戛', + 194740 => '扝', + 194741 => '抱', + 194742 => '拔', + 194743 => '捐', + 194744 => '𢬌', + 194745 => '挽', + 194746 => '拼', + 194747 => '捨', + 194748 => '掃', + 194749 => '揤', + 194750 => '𢯱', + 194751 => '搢', + 194752 => '揅', + 194753 => '掩', + 194754 => '㨮', + 194755 => '摩', + 194756 => '摾', + 194757 => '撝', + 194758 => '摷', + 194759 => '㩬', + 194760 => '敏', + 194761 => '敬', + 194762 => '𣀊', + 194763 => '旣', + 194764 => '書', + 194765 => '晉', + 194766 => '㬙', + 194767 => '暑', + 194768 => '㬈', + 194769 => '㫤', + 194770 => '冒', + 194771 => '冕', + 194772 => '最', + 194773 => '暜', + 194774 => '肭', + 194775 => '䏙', + 194776 => '朗', + 194777 => '望', + 194778 => '朡', + 194779 => '杞', + 194780 => '杓', + 194781 => '𣏃', + 194782 => '㭉', + 194783 => '柺', + 194784 => '枅', + 194785 => '桒', + 194786 => '梅', + 194787 => '𣑭', + 194788 => '梎', + 194789 => '栟', + 194790 => '椔', + 194791 => '㮝', + 194792 => '楂', + 194793 => '榣', + 194794 => '槪', + 194795 => '檨', + 194796 => '𣚣', + 194797 => '櫛', + 194798 => '㰘', + 194799 => '次', + 194800 => '𣢧', + 194801 => '歔', + 194802 => '㱎', + 194803 => '歲', + 194804 => '殟', + 194805 => '殺', + 194806 => '殻', + 194807 => '𣪍', + 194808 => '𡴋', + 194809 => '𣫺', + 194810 => '汎', + 194811 => '𣲼', + 194812 => '沿', + 194813 => '泍', + 194814 => '汧', + 194815 => '洖', + 194816 => '派', + 194817 => '海', + 194818 => '流', + 194819 => '浩', + 194820 => '浸', + 194821 => '涅', + 194822 => '𣴞', + 194823 => '洴', + 194824 => '港', + 194825 => '湮', + 194826 => '㴳', + 194827 => '滋', + 194828 => '滇', + 194829 => '𣻑', + 194830 => '淹', + 194831 => '潮', + 194832 => '𣽞', + 194833 => '𣾎', + 194834 => '濆', + 194835 => '瀹', + 194836 => '瀞', + 194837 => '瀛', + 194838 => '㶖', + 194839 => '灊', + 194840 => '災', + 194841 => '灷', + 194842 => '炭', + 194843 => '𠔥', + 194844 => '煅', + 194845 => '𤉣', + 194846 => '熜', + 194848 => '爨', + 194849 => '爵', + 194850 => '牐', + 194851 => '𤘈', + 194852 => '犀', + 194853 => '犕', + 194854 => '𤜵', + 194855 => '𤠔', + 194856 => '獺', + 194857 => '王', + 194858 => '㺬', + 194859 => '玥', + 194860 => '㺸', + 194861 => '㺸', + 194862 => '瑇', + 194863 => '瑜', + 194864 => '瑱', + 194865 => '璅', + 194866 => '瓊', + 194867 => '㼛', + 194868 => '甤', + 194869 => '𤰶', + 194870 => '甾', + 194871 => '𤲒', + 194872 => '異', + 194873 => '𢆟', + 194874 => '瘐', + 194875 => '𤾡', + 194876 => '𤾸', + 194877 => '𥁄', + 194878 => '㿼', + 194879 => '䀈', + 194880 => '直', + 194881 => '𥃳', + 194882 => '𥃲', + 194883 => '𥄙', + 194884 => '𥄳', + 194885 => '眞', + 194886 => '真', + 194887 => '真', + 194888 => '睊', + 194889 => '䀹', + 194890 => '瞋', + 194891 => '䁆', + 194892 => '䂖', + 194893 => '𥐝', + 194894 => '硎', + 194895 => '碌', + 194896 => '磌', + 194897 => '䃣', + 194898 => '𥘦', + 194899 => '祖', + 194900 => '𥚚', + 194901 => '𥛅', + 194902 => '福', + 194903 => '秫', + 194904 => '䄯', + 194905 => '穀', + 194906 => '穊', + 194907 => '穏', + 194908 => '𥥼', + 194909 => '𥪧', + 194910 => '𥪧', + 194912 => '䈂', + 194913 => '𥮫', + 194914 => '篆', + 194915 => '築', + 194916 => '䈧', + 194917 => '𥲀', + 194918 => '糒', + 194919 => '䊠', + 194920 => '糨', + 194921 => '糣', + 194922 => '紀', + 194923 => '𥾆', + 194924 => '絣', + 194925 => '䌁', + 194926 => '緇', + 194927 => '縂', + 194928 => '繅', + 194929 => '䌴', + 194930 => '𦈨', + 194931 => '𦉇', + 194932 => '䍙', + 194933 => '𦋙', + 194934 => '罺', + 194935 => '𦌾', + 194936 => '羕', + 194937 => '翺', + 194938 => '者', + 194939 => '𦓚', + 194940 => '𦔣', + 194941 => '聠', + 194942 => '𦖨', + 194943 => '聰', + 194944 => '𣍟', + 194945 => '䏕', + 194946 => '育', + 194947 => '脃', + 194948 => '䐋', + 194949 => '脾', + 194950 => '媵', + 194951 => '𦞧', + 194952 => '𦞵', + 194953 => '𣎓', + 194954 => '𣎜', + 194955 => '舁', + 194956 => '舄', + 194957 => '辞', + 194958 => '䑫', + 194959 => '芑', + 194960 => '芋', + 194961 => '芝', + 194962 => '劳', + 194963 => '花', + 194964 => '芳', + 194965 => '芽', + 194966 => '苦', + 194967 => '𦬼', + 194968 => '若', + 194969 => '茝', + 194970 => '荣', + 194971 => '莭', + 194972 => '茣', + 194973 => '莽', + 194974 => '菧', + 194975 => '著', + 194976 => '荓', + 194977 => '菊', + 194978 => '菌', + 194979 => '菜', + 194980 => '𦰶', + 194981 => '𦵫', + 194982 => '𦳕', + 194983 => '䔫', + 194984 => '蓱', + 194985 => '蓳', + 194986 => '蔖', + 194987 => '𧏊', + 194988 => '蕤', + 194989 => '𦼬', + 194990 => '䕝', + 194991 => '䕡', + 194992 => '𦾱', + 194993 => '𧃒', + 194994 => '䕫', + 194995 => '虐', + 194996 => '虜', + 194997 => '虧', + 194998 => '虩', + 194999 => '蚩', + 195000 => '蚈', + 195001 => '蜎', + 195002 => '蛢', + 195003 => '蝹', + 195004 => '蜨', + 195005 => '蝫', + 195006 => '螆', + 195008 => '蟡', + 195009 => '蠁', + 195010 => '䗹', + 195011 => '衠', + 195012 => '衣', + 195013 => '𧙧', + 195014 => '裗', + 195015 => '裞', + 195016 => '䘵', + 195017 => '裺', + 195018 => '㒻', + 195019 => '𧢮', + 195020 => '𧥦', + 195021 => '䚾', + 195022 => '䛇', + 195023 => '誠', + 195024 => '諭', + 195025 => '變', + 195026 => '豕', + 195027 => '𧲨', + 195028 => '貫', + 195029 => '賁', + 195030 => '贛', + 195031 => '起', + 195032 => '𧼯', + 195033 => '𠠄', + 195034 => '跋', + 195035 => '趼', + 195036 => '跰', + 195037 => '𠣞', + 195038 => '軔', + 195039 => '輸', + 195040 => '𨗒', + 195041 => '𨗭', + 195042 => '邔', + 195043 => '郱', + 195044 => '鄑', + 195045 => '𨜮', + 195046 => '鄛', + 195047 => '鈸', + 195048 => '鋗', + 195049 => '鋘', + 195050 => '鉼', + 195051 => '鏹', + 195052 => '鐕', + 195053 => '𨯺', + 195054 => '開', + 195055 => '䦕', + 195056 => '閷', + 195057 => '𨵷', + 195058 => '䧦', + 195059 => '雃', + 195060 => '嶲', + 195061 => '霣', + 195062 => '𩅅', + 195063 => '𩈚', + 195064 => '䩮', + 195065 => '䩶', + 195066 => '韠', + 195067 => '𩐊', + 195068 => '䪲', + 195069 => '𩒖', + 195070 => '頋', + 195071 => '頋', + 195072 => '頩', + 195073 => '𩖶', + 195074 => '飢', + 195075 => '䬳', + 195076 => '餩', + 195077 => '馧', + 195078 => '駂', + 195079 => '駾', + 195080 => '䯎', + 195081 => '𩬰', + 195082 => '鬒', + 195083 => '鱀', + 195084 => '鳽', + 195085 => '䳎', + 195086 => '䳭', + 195087 => '鵧', + 195088 => '𪃎', + 195089 => '䳸', + 195090 => '𪄅', + 195091 => '𪈎', + 195092 => '𪊑', + 195093 => '麻', + 195094 => '䵖', + 195095 => '黹', + 195096 => '黾', + 195097 => '鼅', + 195098 => '鼏', + 195099 => '鼖', + 195100 => '鼻', + 195101 => '𪘀', +); diff --git a/vendor/symfony/polyfill-intl-idn/Resources/unidata/virama.php b/vendor/symfony/polyfill-intl-idn/Resources/unidata/virama.php new file mode 100644 index 0000000..1958e37 --- /dev/null +++ b/vendor/symfony/polyfill-intl-idn/Resources/unidata/virama.php @@ -0,0 +1,65 @@ + 9, + 2509 => 9, + 2637 => 9, + 2765 => 9, + 2893 => 9, + 3021 => 9, + 3149 => 9, + 3277 => 9, + 3387 => 9, + 3388 => 9, + 3405 => 9, + 3530 => 9, + 3642 => 9, + 3770 => 9, + 3972 => 9, + 4153 => 9, + 4154 => 9, + 5908 => 9, + 5940 => 9, + 6098 => 9, + 6752 => 9, + 6980 => 9, + 7082 => 9, + 7083 => 9, + 7154 => 9, + 7155 => 9, + 11647 => 9, + 43014 => 9, + 43052 => 9, + 43204 => 9, + 43347 => 9, + 43456 => 9, + 43766 => 9, + 44013 => 9, + 68159 => 9, + 69702 => 9, + 69759 => 9, + 69817 => 9, + 69939 => 9, + 69940 => 9, + 70080 => 9, + 70197 => 9, + 70378 => 9, + 70477 => 9, + 70722 => 9, + 70850 => 9, + 71103 => 9, + 71231 => 9, + 71350 => 9, + 71467 => 9, + 71737 => 9, + 71997 => 9, + 71998 => 9, + 72160 => 9, + 72244 => 9, + 72263 => 9, + 72345 => 9, + 72767 => 9, + 73028 => 9, + 73029 => 9, + 73111 => 9, +); diff --git a/vendor/symfony/polyfill-intl-idn/bootstrap.php b/vendor/symfony/polyfill-intl-idn/bootstrap.php new file mode 100644 index 0000000..f02d5de --- /dev/null +++ b/vendor/symfony/polyfill-intl-idn/bootstrap.php @@ -0,0 +1,141 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Intl\Idn as p; + +if (extension_loaded('intl')) { + return; +} + +if (!defined('U_IDNA_PROHIBITED_ERROR')) { + define('U_IDNA_PROHIBITED_ERROR', 66560); +} +if (!defined('U_IDNA_ERROR_START')) { + define('U_IDNA_ERROR_START', 66560); +} +if (!defined('U_IDNA_UNASSIGNED_ERROR')) { + define('U_IDNA_UNASSIGNED_ERROR', 66561); +} +if (!defined('U_IDNA_CHECK_BIDI_ERROR')) { + define('U_IDNA_CHECK_BIDI_ERROR', 66562); +} +if (!defined('U_IDNA_STD3_ASCII_RULES_ERROR')) { + define('U_IDNA_STD3_ASCII_RULES_ERROR', 66563); +} +if (!defined('U_IDNA_ACE_PREFIX_ERROR')) { + define('U_IDNA_ACE_PREFIX_ERROR', 66564); +} +if (!defined('U_IDNA_VERIFICATION_ERROR')) { + define('U_IDNA_VERIFICATION_ERROR', 66565); +} +if (!defined('U_IDNA_LABEL_TOO_LONG_ERROR')) { + define('U_IDNA_LABEL_TOO_LONG_ERROR', 66566); +} +if (!defined('U_IDNA_ZERO_LENGTH_LABEL_ERROR')) { + define('U_IDNA_ZERO_LENGTH_LABEL_ERROR', 66567); +} +if (!defined('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR')) { + define('U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR', 66568); +} +if (!defined('U_IDNA_ERROR_LIMIT')) { + define('U_IDNA_ERROR_LIMIT', 66569); +} +if (!defined('U_STRINGPREP_PROHIBITED_ERROR')) { + define('U_STRINGPREP_PROHIBITED_ERROR', 66560); +} +if (!defined('U_STRINGPREP_UNASSIGNED_ERROR')) { + define('U_STRINGPREP_UNASSIGNED_ERROR', 66561); +} +if (!defined('U_STRINGPREP_CHECK_BIDI_ERROR')) { + define('U_STRINGPREP_CHECK_BIDI_ERROR', 66562); +} +if (!defined('IDNA_DEFAULT')) { + define('IDNA_DEFAULT', 0); +} +if (!defined('IDNA_ALLOW_UNASSIGNED')) { + define('IDNA_ALLOW_UNASSIGNED', 1); +} +if (!defined('IDNA_USE_STD3_RULES')) { + define('IDNA_USE_STD3_RULES', 2); +} +if (!defined('IDNA_CHECK_BIDI')) { + define('IDNA_CHECK_BIDI', 4); +} +if (!defined('IDNA_CHECK_CONTEXTJ')) { + define('IDNA_CHECK_CONTEXTJ', 8); +} +if (!defined('IDNA_NONTRANSITIONAL_TO_ASCII')) { + define('IDNA_NONTRANSITIONAL_TO_ASCII', 16); +} +if (!defined('IDNA_NONTRANSITIONAL_TO_UNICODE')) { + define('IDNA_NONTRANSITIONAL_TO_UNICODE', 32); +} +if (!defined('INTL_IDNA_VARIANT_2003')) { + define('INTL_IDNA_VARIANT_2003', 0); +} +if (!defined('INTL_IDNA_VARIANT_UTS46')) { + define('INTL_IDNA_VARIANT_UTS46', 1); +} +if (!defined('IDNA_ERROR_EMPTY_LABEL')) { + define('IDNA_ERROR_EMPTY_LABEL', 1); +} +if (!defined('IDNA_ERROR_LABEL_TOO_LONG')) { + define('IDNA_ERROR_LABEL_TOO_LONG', 2); +} +if (!defined('IDNA_ERROR_DOMAIN_NAME_TOO_LONG')) { + define('IDNA_ERROR_DOMAIN_NAME_TOO_LONG', 4); +} +if (!defined('IDNA_ERROR_LEADING_HYPHEN')) { + define('IDNA_ERROR_LEADING_HYPHEN', 8); +} +if (!defined('IDNA_ERROR_TRAILING_HYPHEN')) { + define('IDNA_ERROR_TRAILING_HYPHEN', 16); +} +if (!defined('IDNA_ERROR_HYPHEN_3_4')) { + define('IDNA_ERROR_HYPHEN_3_4', 32); +} +if (!defined('IDNA_ERROR_LEADING_COMBINING_MARK')) { + define('IDNA_ERROR_LEADING_COMBINING_MARK', 64); +} +if (!defined('IDNA_ERROR_DISALLOWED')) { + define('IDNA_ERROR_DISALLOWED', 128); +} +if (!defined('IDNA_ERROR_PUNYCODE')) { + define('IDNA_ERROR_PUNYCODE', 256); +} +if (!defined('IDNA_ERROR_LABEL_HAS_DOT')) { + define('IDNA_ERROR_LABEL_HAS_DOT', 512); +} +if (!defined('IDNA_ERROR_INVALID_ACE_LABEL')) { + define('IDNA_ERROR_INVALID_ACE_LABEL', 1024); +} +if (!defined('IDNA_ERROR_BIDI')) { + define('IDNA_ERROR_BIDI', 2048); +} +if (!defined('IDNA_ERROR_CONTEXTJ')) { + define('IDNA_ERROR_CONTEXTJ', 4096); +} + +if (PHP_VERSION_ID < 70400) { + if (!function_exists('idn_to_ascii')) { + function idn_to_ascii($domain, $options = IDNA_DEFAULT, $variant = INTL_IDNA_VARIANT_2003, &$idna_info = array()) { return p\Idn::idn_to_ascii($domain, $options, $variant, $idna_info); } + } + if (!function_exists('idn_to_utf8')) { + function idn_to_utf8($domain, $options = IDNA_DEFAULT, $variant = INTL_IDNA_VARIANT_2003, &$idna_info = array()) { return p\Idn::idn_to_utf8($domain, $options, $variant, $idna_info); } + } +} else { + if (!function_exists('idn_to_ascii')) { + function idn_to_ascii($domain, $options = IDNA_DEFAULT, $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = array()) { return p\Idn::idn_to_ascii($domain, $options, $variant, $idna_info); } + } + if (!function_exists('idn_to_utf8')) { + function idn_to_utf8($domain, $options = IDNA_DEFAULT, $variant = INTL_IDNA_VARIANT_UTS46, &$idna_info = array()) { return p\Idn::idn_to_utf8($domain, $options, $variant, $idna_info); } + } +} diff --git a/vendor/symfony/polyfill-intl-idn/composer.json b/vendor/symfony/polyfill-intl-idn/composer.json new file mode 100644 index 0000000..af34193 --- /dev/null +++ b/vendor/symfony/polyfill-intl-idn/composer.json @@ -0,0 +1,45 @@ +{ + "name": "symfony/polyfill-intl-idn", + "type": "library", + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "keywords": ["polyfill", "shim", "compatibility", "portable", "intl", "idn"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.3", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php70": "^1.10", + "symfony/polyfill-php72": "^1.10" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Intl\\Idn\\": "" }, + "files": [ "bootstrap.php" ] + }, + "suggest": { + "ext-intl": "For best performance" + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/vendor/symfony/polyfill-intl-normalizer/LICENSE b/vendor/symfony/polyfill-intl-normalizer/LICENSE new file mode 100644 index 0000000..4cd8bdd --- /dev/null +++ b/vendor/symfony/polyfill-intl-normalizer/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015-2019 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/polyfill-intl-normalizer/Normalizer.php b/vendor/symfony/polyfill-intl-normalizer/Normalizer.php new file mode 100644 index 0000000..a60fae6 --- /dev/null +++ b/vendor/symfony/polyfill-intl-normalizer/Normalizer.php @@ -0,0 +1,308 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Intl\Normalizer; + +/** + * Normalizer is a PHP fallback implementation of the Normalizer class provided by the intl extension. + * + * It has been validated with Unicode 6.3 Normalization Conformance Test. + * See http://www.unicode.org/reports/tr15/ for detailed info about Unicode normalizations. + * + * @author Nicolas Grekas + * + * @internal + */ +class Normalizer +{ + const FORM_D = \Normalizer::FORM_D; + const FORM_KD = \Normalizer::FORM_KD; + const FORM_C = \Normalizer::FORM_C; + const FORM_KC = \Normalizer::FORM_KC; + const NFD = \Normalizer::NFD; + const NFKD = \Normalizer::NFKD; + const NFC = \Normalizer::NFC; + const NFKC = \Normalizer::NFKC; + + private static $C; + private static $D; + private static $KD; + private static $cC; + private static $ulenMask = array("\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4); + private static $ASCII = "\x20\x65\x69\x61\x73\x6E\x74\x72\x6F\x6C\x75\x64\x5D\x5B\x63\x6D\x70\x27\x0A\x67\x7C\x68\x76\x2E\x66\x62\x2C\x3A\x3D\x2D\x71\x31\x30\x43\x32\x2A\x79\x78\x29\x28\x4C\x39\x41\x53\x2F\x50\x22\x45\x6A\x4D\x49\x6B\x33\x3E\x35\x54\x3C\x44\x34\x7D\x42\x7B\x38\x46\x77\x52\x36\x37\x55\x47\x4E\x3B\x4A\x7A\x56\x23\x48\x4F\x57\x5F\x26\x21\x4B\x3F\x58\x51\x25\x59\x5C\x09\x5A\x2B\x7E\x5E\x24\x40\x60\x7F\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"; + + public static function isNormalized($s, $form = self::NFC) + { + if (!\in_array($form, array(self::NFD, self::NFKD, self::NFC, self::NFKC))) { + return false; + } + $s = (string) $s; + if (!isset($s[strspn($s, self::$ASCII)])) { + return true; + } + if (self::NFC == $form && preg_match('//u', $s) && !preg_match('/[^\x00-\x{2FF}]/u', $s)) { + return true; + } + + return self::normalize($s, $form) === $s; + } + + public static function normalize($s, $form = self::NFC) + { + $s = (string) $s; + if (!preg_match('//u', $s)) { + return false; + } + + switch ($form) { + case self::NFC: $C = true; $K = false; break; + case self::NFD: $C = false; $K = false; break; + case self::NFKC: $C = true; $K = true; break; + case self::NFKD: $C = false; $K = true; break; + default: + if (\defined('Normalizer::NONE') && \Normalizer::NONE == $form) { + return $s; + } + + return false; + } + + if ('' === $s) { + return ''; + } + + if ($K && null === self::$KD) { + self::$KD = self::getData('compatibilityDecomposition'); + } + + if (null === self::$D) { + self::$D = self::getData('canonicalDecomposition'); + self::$cC = self::getData('combiningClass'); + } + + if (null !== $mbEncoding = (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) ? mb_internal_encoding() : null) { + mb_internal_encoding('8bit'); + } + + $r = self::decompose($s, $K); + + if ($C) { + if (null === self::$C) { + self::$C = self::getData('canonicalComposition'); + } + + $r = self::recompose($r); + } + if (null !== $mbEncoding) { + mb_internal_encoding($mbEncoding); + } + + return $r; + } + + private static function recompose($s) + { + $ASCII = self::$ASCII; + $compMap = self::$C; + $combClass = self::$cC; + $ulenMask = self::$ulenMask; + + $result = $tail = ''; + + $i = $s[0] < "\x80" ? 1 : $ulenMask[$s[0] & "\xF0"]; + $len = \strlen($s); + + $lastUchr = substr($s, 0, $i); + $lastUcls = isset($combClass[$lastUchr]) ? 256 : 0; + + while ($i < $len) { + if ($s[$i] < "\x80") { + // ASCII chars + + if ($tail) { + $lastUchr .= $tail; + $tail = ''; + } + + if ($j = strspn($s, $ASCII, $i + 1)) { + $lastUchr .= substr($s, $i, $j); + $i += $j; + } + + $result .= $lastUchr; + $lastUchr = $s[$i]; + $lastUcls = 0; + ++$i; + continue; + } + + $ulen = $ulenMask[$s[$i] & "\xF0"]; + $uchr = substr($s, $i, $ulen); + + if ($lastUchr < "\xE1\x84\x80" || "\xE1\x84\x92" < $lastUchr + || $uchr < "\xE1\x85\xA1" || "\xE1\x85\xB5" < $uchr + || $lastUcls) { + // Table lookup and combining chars composition + + $ucls = isset($combClass[$uchr]) ? $combClass[$uchr] : 0; + + if (isset($compMap[$lastUchr.$uchr]) && (!$lastUcls || $lastUcls < $ucls)) { + $lastUchr = $compMap[$lastUchr.$uchr]; + } elseif ($lastUcls = $ucls) { + $tail .= $uchr; + } else { + if ($tail) { + $lastUchr .= $tail; + $tail = ''; + } + + $result .= $lastUchr; + $lastUchr = $uchr; + } + } else { + // Hangul chars + + $L = \ord($lastUchr[2]) - 0x80; + $V = \ord($uchr[2]) - 0xA1; + $T = 0; + + $uchr = substr($s, $i + $ulen, 3); + + if ("\xE1\x86\xA7" <= $uchr && $uchr <= "\xE1\x87\x82") { + $T = \ord($uchr[2]) - 0xA7; + 0 > $T && $T += 0x40; + $ulen += 3; + } + + $L = 0xAC00 + ($L * 21 + $V) * 28 + $T; + $lastUchr = \chr(0xE0 | $L >> 12).\chr(0x80 | $L >> 6 & 0x3F).\chr(0x80 | $L & 0x3F); + } + + $i += $ulen; + } + + return $result.$lastUchr.$tail; + } + + private static function decompose($s, $c) + { + $result = ''; + + $ASCII = self::$ASCII; + $decompMap = self::$D; + $combClass = self::$cC; + $ulenMask = self::$ulenMask; + if ($c) { + $compatMap = self::$KD; + } + + $c = array(); + $i = 0; + $len = \strlen($s); + + while ($i < $len) { + if ($s[$i] < "\x80") { + // ASCII chars + + if ($c) { + ksort($c); + $result .= implode('', $c); + $c = array(); + } + + $j = 1 + strspn($s, $ASCII, $i + 1); + $result .= substr($s, $i, $j); + $i += $j; + continue; + } + + $ulen = $ulenMask[$s[$i] & "\xF0"]; + $uchr = substr($s, $i, $ulen); + $i += $ulen; + + if ($uchr < "\xEA\xB0\x80" || "\xED\x9E\xA3" < $uchr) { + // Table lookup + + if ($uchr !== $j = isset($compatMap[$uchr]) ? $compatMap[$uchr] : (isset($decompMap[$uchr]) ? $decompMap[$uchr] : $uchr)) { + $uchr = $j; + + $j = \strlen($uchr); + $ulen = $uchr[0] < "\x80" ? 1 : $ulenMask[$uchr[0] & "\xF0"]; + + if ($ulen != $j) { + // Put trailing chars in $s + + $j -= $ulen; + $i -= $j; + + if (0 > $i) { + $s = str_repeat(' ', -$i).$s; + $len -= $i; + $i = 0; + } + + while ($j--) { + $s[$i + $j] = $uchr[$ulen + $j]; + } + + $uchr = substr($uchr, 0, $ulen); + } + } + if (isset($combClass[$uchr])) { + // Combining chars, for sorting + + if (!isset($c[$combClass[$uchr]])) { + $c[$combClass[$uchr]] = ''; + } + $c[$combClass[$uchr]] .= $uchr; + continue; + } + } else { + // Hangul chars + + $uchr = unpack('C*', $uchr); + $j = (($uchr[1] - 224) << 12) + (($uchr[2] - 128) << 6) + $uchr[3] - 0xAC80; + + $uchr = "\xE1\x84".\chr(0x80 + (int) ($j / 588)) + ."\xE1\x85".\chr(0xA1 + (int) (($j % 588) / 28)); + + if ($j %= 28) { + $uchr .= $j < 25 + ? ("\xE1\x86".\chr(0xA7 + $j)) + : ("\xE1\x87".\chr(0x67 + $j)); + } + } + if ($c) { + ksort($c); + $result .= implode('', $c); + $c = array(); + } + + $result .= $uchr; + } + + if ($c) { + ksort($c); + $result .= implode('', $c); + } + + return $result; + } + + private static function getData($file) + { + if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) { + return require $file; + } + + return false; + } +} diff --git a/vendor/symfony/polyfill-intl-normalizer/README.md b/vendor/symfony/polyfill-intl-normalizer/README.md new file mode 100644 index 0000000..15060c5 --- /dev/null +++ b/vendor/symfony/polyfill-intl-normalizer/README.md @@ -0,0 +1,14 @@ +Symfony Polyfill / Intl: Normalizer +=================================== + +This component provides a fallback implementation for the +[`Normalizer`](https://php.net/Normalizer) class provided +by the [Intl](https://php.net/intl) extension. + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php b/vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php new file mode 100644 index 0000000..ca18eff --- /dev/null +++ b/vendor/symfony/polyfill-intl-normalizer/Resources/stubs/Normalizer.php @@ -0,0 +1,17 @@ + 'À', + 'Á' => 'Á', + 'Â' => 'Â', + 'Ã' => 'Ã', + 'Ä' => 'Ä', + 'Å' => 'Å', + 'Ç' => 'Ç', + 'È' => 'È', + 'É' => 'É', + 'Ê' => 'Ê', + 'Ë' => 'Ë', + 'Ì' => 'Ì', + 'Í' => 'Í', + 'Î' => 'Î', + 'Ï' => 'Ï', + 'Ñ' => 'Ñ', + 'Ò' => 'Ò', + 'Ó' => 'Ó', + 'Ô' => 'Ô', + 'Õ' => 'Õ', + 'Ö' => 'Ö', + 'Ù' => 'Ù', + 'Ú' => 'Ú', + 'Û' => 'Û', + 'Ü' => 'Ü', + 'Ý' => 'Ý', + 'à' => 'à', + 'á' => 'á', + 'â' => 'â', + 'ã' => 'ã', + 'ä' => 'ä', + 'å' => 'å', + 'ç' => 'ç', + 'è' => 'è', + 'é' => 'é', + 'ê' => 'ê', + 'ë' => 'ë', + 'ì' => 'ì', + 'í' => 'í', + 'î' => 'î', + 'ï' => 'ï', + 'ñ' => 'ñ', + 'ò' => 'ò', + 'ó' => 'ó', + 'ô' => 'ô', + 'õ' => 'õ', + 'ö' => 'ö', + 'ù' => 'ù', + 'ú' => 'ú', + 'û' => 'û', + 'ü' => 'ü', + 'ý' => 'ý', + 'ÿ' => 'ÿ', + 'Ā' => 'Ā', + 'ā' => 'ā', + 'Ă' => 'Ă', + 'ă' => 'ă', + 'Ą' => 'Ą', + 'ą' => 'ą', + 'Ć' => 'Ć', + 'ć' => 'ć', + 'Ĉ' => 'Ĉ', + 'ĉ' => 'ĉ', + 'Ċ' => 'Ċ', + 'ċ' => 'ċ', + 'Č' => 'Č', + 'č' => 'č', + 'Ď' => 'Ď', + 'ď' => 'ď', + 'Ē' => 'Ē', + 'ē' => 'ē', + 'Ĕ' => 'Ĕ', + 'ĕ' => 'ĕ', + 'Ė' => 'Ė', + 'ė' => 'ė', + 'Ę' => 'Ę', + 'ę' => 'ę', + 'Ě' => 'Ě', + 'ě' => 'ě', + 'Ĝ' => 'Ĝ', + 'ĝ' => 'ĝ', + 'Ğ' => 'Ğ', + 'ğ' => 'ğ', + 'Ġ' => 'Ġ', + 'ġ' => 'ġ', + 'Ģ' => 'Ģ', + 'ģ' => 'ģ', + 'Ĥ' => 'Ĥ', + 'ĥ' => 'ĥ', + 'Ĩ' => 'Ĩ', + 'ĩ' => 'ĩ', + 'Ī' => 'Ī', + 'ī' => 'ī', + 'Ĭ' => 'Ĭ', + 'ĭ' => 'ĭ', + 'Į' => 'Į', + 'į' => 'į', + 'İ' => 'İ', + 'Ĵ' => 'Ĵ', + 'ĵ' => 'ĵ', + 'Ķ' => 'Ķ', + 'ķ' => 'ķ', + 'Ĺ' => 'Ĺ', + 'ĺ' => 'ĺ', + 'Ļ' => 'Ļ', + 'ļ' => 'ļ', + 'Ľ' => 'Ľ', + 'ľ' => 'ľ', + 'Ń' => 'Ń', + 'ń' => 'ń', + 'Ņ' => 'Ņ', + 'ņ' => 'ņ', + 'Ň' => 'Ň', + 'ň' => 'ň', + 'Ō' => 'Ō', + 'ō' => 'ō', + 'Ŏ' => 'Ŏ', + 'ŏ' => 'ŏ', + 'Ő' => 'Ő', + 'ő' => 'ő', + 'Ŕ' => 'Ŕ', + 'ŕ' => 'ŕ', + 'Ŗ' => 'Ŗ', + 'ŗ' => 'ŗ', + 'Ř' => 'Ř', + 'ř' => 'ř', + 'Ś' => 'Ś', + 'ś' => 'ś', + 'Ŝ' => 'Ŝ', + 'ŝ' => 'ŝ', + 'Ş' => 'Ş', + 'ş' => 'ş', + 'Š' => 'Š', + 'š' => 'š', + 'Ţ' => 'Ţ', + 'ţ' => 'ţ', + 'Ť' => 'Ť', + 'ť' => 'ť', + 'Ũ' => 'Ũ', + 'ũ' => 'ũ', + 'Ū' => 'Ū', + 'ū' => 'ū', + 'Ŭ' => 'Ŭ', + 'ŭ' => 'ŭ', + 'Ů' => 'Ů', + 'ů' => 'ů', + 'Ű' => 'Ű', + 'ű' => 'ű', + 'Ų' => 'Ų', + 'ų' => 'ų', + 'Ŵ' => 'Ŵ', + 'ŵ' => 'ŵ', + 'Ŷ' => 'Ŷ', + 'ŷ' => 'ŷ', + 'Ÿ' => 'Ÿ', + 'Ź' => 'Ź', + 'ź' => 'ź', + 'Ż' => 'Ż', + 'ż' => 'ż', + 'Ž' => 'Ž', + 'ž' => 'ž', + 'Ơ' => 'Ơ', + 'ơ' => 'ơ', + 'Ư' => 'Ư', + 'ư' => 'ư', + 'Ǎ' => 'Ǎ', + 'ǎ' => 'ǎ', + 'Ǐ' => 'Ǐ', + 'ǐ' => 'ǐ', + 'Ǒ' => 'Ǒ', + 'ǒ' => 'ǒ', + 'Ǔ' => 'Ǔ', + 'ǔ' => 'ǔ', + 'Ǖ' => 'Ǖ', + 'ǖ' => 'ǖ', + 'Ǘ' => 'Ǘ', + 'ǘ' => 'ǘ', + 'Ǚ' => 'Ǚ', + 'ǚ' => 'ǚ', + 'Ǜ' => 'Ǜ', + 'ǜ' => 'ǜ', + 'Ǟ' => 'Ǟ', + 'ǟ' => 'ǟ', + 'Ǡ' => 'Ǡ', + 'ǡ' => 'ǡ', + 'Ǣ' => 'Ǣ', + 'ǣ' => 'ǣ', + 'Ǧ' => 'Ǧ', + 'ǧ' => 'ǧ', + 'Ǩ' => 'Ǩ', + 'ǩ' => 'ǩ', + 'Ǫ' => 'Ǫ', + 'ǫ' => 'ǫ', + 'Ǭ' => 'Ǭ', + 'ǭ' => 'ǭ', + 'Ǯ' => 'Ǯ', + 'ǯ' => 'ǯ', + 'ǰ' => 'ǰ', + 'Ǵ' => 'Ǵ', + 'ǵ' => 'ǵ', + 'Ǹ' => 'Ǹ', + 'ǹ' => 'ǹ', + 'Ǻ' => 'Ǻ', + 'ǻ' => 'ǻ', + 'Ǽ' => 'Ǽ', + 'ǽ' => 'ǽ', + 'Ǿ' => 'Ǿ', + 'ǿ' => 'ǿ', + 'Ȁ' => 'Ȁ', + 'ȁ' => 'ȁ', + 'Ȃ' => 'Ȃ', + 'ȃ' => 'ȃ', + 'Ȅ' => 'Ȅ', + 'ȅ' => 'ȅ', + 'Ȇ' => 'Ȇ', + 'ȇ' => 'ȇ', + 'Ȉ' => 'Ȉ', + 'ȉ' => 'ȉ', + 'Ȋ' => 'Ȋ', + 'ȋ' => 'ȋ', + 'Ȍ' => 'Ȍ', + 'ȍ' => 'ȍ', + 'Ȏ' => 'Ȏ', + 'ȏ' => 'ȏ', + 'Ȑ' => 'Ȑ', + 'ȑ' => 'ȑ', + 'Ȓ' => 'Ȓ', + 'ȓ' => 'ȓ', + 'Ȕ' => 'Ȕ', + 'ȕ' => 'ȕ', + 'Ȗ' => 'Ȗ', + 'ȗ' => 'ȗ', + 'Ș' => 'Ș', + 'ș' => 'ș', + 'Ț' => 'Ț', + 'ț' => 'ț', + 'Ȟ' => 'Ȟ', + 'ȟ' => 'ȟ', + 'Ȧ' => 'Ȧ', + 'ȧ' => 'ȧ', + 'Ȩ' => 'Ȩ', + 'ȩ' => 'ȩ', + 'Ȫ' => 'Ȫ', + 'ȫ' => 'ȫ', + 'Ȭ' => 'Ȭ', + 'ȭ' => 'ȭ', + 'Ȯ' => 'Ȯ', + 'ȯ' => 'ȯ', + 'Ȱ' => 'Ȱ', + 'ȱ' => 'ȱ', + 'Ȳ' => 'Ȳ', + 'ȳ' => 'ȳ', + '΅' => '΅', + 'Ά' => 'Ά', + 'Έ' => 'Έ', + 'Ή' => 'Ή', + 'Ί' => 'Ί', + 'Ό' => 'Ό', + 'Ύ' => 'Ύ', + 'Ώ' => 'Ώ', + 'ΐ' => 'ΐ', + 'Ϊ' => 'Ϊ', + 'Ϋ' => 'Ϋ', + 'ά' => 'ά', + 'έ' => 'έ', + 'ή' => 'ή', + 'ί' => 'ί', + 'ΰ' => 'ΰ', + 'ϊ' => 'ϊ', + 'ϋ' => 'ϋ', + 'ό' => 'ό', + 'ύ' => 'ύ', + 'ώ' => 'ώ', + 'ϓ' => 'ϓ', + 'ϔ' => 'ϔ', + 'Ѐ' => 'Ѐ', + 'Ё' => 'Ё', + 'Ѓ' => 'Ѓ', + 'Ї' => 'Ї', + 'Ќ' => 'Ќ', + 'Ѝ' => 'Ѝ', + 'Ў' => 'Ў', + 'Й' => 'Й', + 'й' => 'й', + 'ѐ' => 'ѐ', + 'ё' => 'ё', + 'ѓ' => 'ѓ', + 'ї' => 'ї', + 'ќ' => 'ќ', + 'ѝ' => 'ѝ', + 'ў' => 'ў', + 'Ѷ' => 'Ѷ', + 'ѷ' => 'ѷ', + 'Ӂ' => 'Ӂ', + 'ӂ' => 'ӂ', + 'Ӑ' => 'Ӑ', + 'ӑ' => 'ӑ', + 'Ӓ' => 'Ӓ', + 'ӓ' => 'ӓ', + 'Ӗ' => 'Ӗ', + 'ӗ' => 'ӗ', + 'Ӛ' => 'Ӛ', + 'ӛ' => 'ӛ', + 'Ӝ' => 'Ӝ', + 'ӝ' => 'ӝ', + 'Ӟ' => 'Ӟ', + 'ӟ' => 'ӟ', + 'Ӣ' => 'Ӣ', + 'ӣ' => 'ӣ', + 'Ӥ' => 'Ӥ', + 'ӥ' => 'ӥ', + 'Ӧ' => 'Ӧ', + 'ӧ' => 'ӧ', + 'Ӫ' => 'Ӫ', + 'ӫ' => 'ӫ', + 'Ӭ' => 'Ӭ', + 'ӭ' => 'ӭ', + 'Ӯ' => 'Ӯ', + 'ӯ' => 'ӯ', + 'Ӱ' => 'Ӱ', + 'ӱ' => 'ӱ', + 'Ӳ' => 'Ӳ', + 'ӳ' => 'ӳ', + 'Ӵ' => 'Ӵ', + 'ӵ' => 'ӵ', + 'Ӹ' => 'Ӹ', + 'ӹ' => 'ӹ', + 'آ' => 'آ', + 'أ' => 'أ', + 'ؤ' => 'ؤ', + 'إ' => 'إ', + 'ئ' => 'ئ', + 'ۀ' => 'ۀ', + 'ۂ' => 'ۂ', + 'ۓ' => 'ۓ', + 'ऩ' => 'ऩ', + 'ऱ' => 'ऱ', + 'ऴ' => 'ऴ', + 'ো' => 'ো', + 'ৌ' => 'ৌ', + 'ୈ' => 'ୈ', + 'ୋ' => 'ୋ', + 'ୌ' => 'ୌ', + 'ஔ' => 'ஔ', + 'ொ' => 'ொ', + 'ோ' => 'ோ', + 'ௌ' => 'ௌ', + 'ై' => 'ై', + 'ೀ' => 'ೀ', + 'ೇ' => 'ೇ', + 'ೈ' => 'ೈ', + 'ೊ' => 'ೊ', + 'ೋ' => 'ೋ', + 'ൊ' => 'ൊ', + 'ോ' => 'ോ', + 'ൌ' => 'ൌ', + 'ේ' => 'ේ', + 'ො' => 'ො', + 'ෝ' => 'ෝ', + 'ෞ' => 'ෞ', + 'ဦ' => 'ဦ', + 'ᬆ' => 'ᬆ', + 'ᬈ' => 'ᬈ', + 'ᬊ' => 'ᬊ', + 'ᬌ' => 'ᬌ', + 'ᬎ' => 'ᬎ', + 'ᬒ' => 'ᬒ', + 'ᬻ' => 'ᬻ', + 'ᬽ' => 'ᬽ', + 'ᭀ' => 'ᭀ', + 'ᭁ' => 'ᭁ', + 'ᭃ' => 'ᭃ', + 'Ḁ' => 'Ḁ', + 'ḁ' => 'ḁ', + 'Ḃ' => 'Ḃ', + 'ḃ' => 'ḃ', + 'Ḅ' => 'Ḅ', + 'ḅ' => 'ḅ', + 'Ḇ' => 'Ḇ', + 'ḇ' => 'ḇ', + 'Ḉ' => 'Ḉ', + 'ḉ' => 'ḉ', + 'Ḋ' => 'Ḋ', + 'ḋ' => 'ḋ', + 'Ḍ' => 'Ḍ', + 'ḍ' => 'ḍ', + 'Ḏ' => 'Ḏ', + 'ḏ' => 'ḏ', + 'Ḑ' => 'Ḑ', + 'ḑ' => 'ḑ', + 'Ḓ' => 'Ḓ', + 'ḓ' => 'ḓ', + 'Ḕ' => 'Ḕ', + 'ḕ' => 'ḕ', + 'Ḗ' => 'Ḗ', + 'ḗ' => 'ḗ', + 'Ḙ' => 'Ḙ', + 'ḙ' => 'ḙ', + 'Ḛ' => 'Ḛ', + 'ḛ' => 'ḛ', + 'Ḝ' => 'Ḝ', + 'ḝ' => 'ḝ', + 'Ḟ' => 'Ḟ', + 'ḟ' => 'ḟ', + 'Ḡ' => 'Ḡ', + 'ḡ' => 'ḡ', + 'Ḣ' => 'Ḣ', + 'ḣ' => 'ḣ', + 'Ḥ' => 'Ḥ', + 'ḥ' => 'ḥ', + 'Ḧ' => 'Ḧ', + 'ḧ' => 'ḧ', + 'Ḩ' => 'Ḩ', + 'ḩ' => 'ḩ', + 'Ḫ' => 'Ḫ', + 'ḫ' => 'ḫ', + 'Ḭ' => 'Ḭ', + 'ḭ' => 'ḭ', + 'Ḯ' => 'Ḯ', + 'ḯ' => 'ḯ', + 'Ḱ' => 'Ḱ', + 'ḱ' => 'ḱ', + 'Ḳ' => 'Ḳ', + 'ḳ' => 'ḳ', + 'Ḵ' => 'Ḵ', + 'ḵ' => 'ḵ', + 'Ḷ' => 'Ḷ', + 'ḷ' => 'ḷ', + 'Ḹ' => 'Ḹ', + 'ḹ' => 'ḹ', + 'Ḻ' => 'Ḻ', + 'ḻ' => 'ḻ', + 'Ḽ' => 'Ḽ', + 'ḽ' => 'ḽ', + 'Ḿ' => 'Ḿ', + 'ḿ' => 'ḿ', + 'Ṁ' => 'Ṁ', + 'ṁ' => 'ṁ', + 'Ṃ' => 'Ṃ', + 'ṃ' => 'ṃ', + 'Ṅ' => 'Ṅ', + 'ṅ' => 'ṅ', + 'Ṇ' => 'Ṇ', + 'ṇ' => 'ṇ', + 'Ṉ' => 'Ṉ', + 'ṉ' => 'ṉ', + 'Ṋ' => 'Ṋ', + 'ṋ' => 'ṋ', + 'Ṍ' => 'Ṍ', + 'ṍ' => 'ṍ', + 'Ṏ' => 'Ṏ', + 'ṏ' => 'ṏ', + 'Ṑ' => 'Ṑ', + 'ṑ' => 'ṑ', + 'Ṓ' => 'Ṓ', + 'ṓ' => 'ṓ', + 'Ṕ' => 'Ṕ', + 'ṕ' => 'ṕ', + 'Ṗ' => 'Ṗ', + 'ṗ' => 'ṗ', + 'Ṙ' => 'Ṙ', + 'ṙ' => 'ṙ', + 'Ṛ' => 'Ṛ', + 'ṛ' => 'ṛ', + 'Ṝ' => 'Ṝ', + 'ṝ' => 'ṝ', + 'Ṟ' => 'Ṟ', + 'ṟ' => 'ṟ', + 'Ṡ' => 'Ṡ', + 'ṡ' => 'ṡ', + 'Ṣ' => 'Ṣ', + 'ṣ' => 'ṣ', + 'Ṥ' => 'Ṥ', + 'ṥ' => 'ṥ', + 'Ṧ' => 'Ṧ', + 'ṧ' => 'ṧ', + 'Ṩ' => 'Ṩ', + 'ṩ' => 'ṩ', + 'Ṫ' => 'Ṫ', + 'ṫ' => 'ṫ', + 'Ṭ' => 'Ṭ', + 'ṭ' => 'ṭ', + 'Ṯ' => 'Ṯ', + 'ṯ' => 'ṯ', + 'Ṱ' => 'Ṱ', + 'ṱ' => 'ṱ', + 'Ṳ' => 'Ṳ', + 'ṳ' => 'ṳ', + 'Ṵ' => 'Ṵ', + 'ṵ' => 'ṵ', + 'Ṷ' => 'Ṷ', + 'ṷ' => 'ṷ', + 'Ṹ' => 'Ṹ', + 'ṹ' => 'ṹ', + 'Ṻ' => 'Ṻ', + 'ṻ' => 'ṻ', + 'Ṽ' => 'Ṽ', + 'ṽ' => 'ṽ', + 'Ṿ' => 'Ṿ', + 'ṿ' => 'ṿ', + 'Ẁ' => 'Ẁ', + 'ẁ' => 'ẁ', + 'Ẃ' => 'Ẃ', + 'ẃ' => 'ẃ', + 'Ẅ' => 'Ẅ', + 'ẅ' => 'ẅ', + 'Ẇ' => 'Ẇ', + 'ẇ' => 'ẇ', + 'Ẉ' => 'Ẉ', + 'ẉ' => 'ẉ', + 'Ẋ' => 'Ẋ', + 'ẋ' => 'ẋ', + 'Ẍ' => 'Ẍ', + 'ẍ' => 'ẍ', + 'Ẏ' => 'Ẏ', + 'ẏ' => 'ẏ', + 'Ẑ' => 'Ẑ', + 'ẑ' => 'ẑ', + 'Ẓ' => 'Ẓ', + 'ẓ' => 'ẓ', + 'Ẕ' => 'Ẕ', + 'ẕ' => 'ẕ', + 'ẖ' => 'ẖ', + 'ẗ' => 'ẗ', + 'ẘ' => 'ẘ', + 'ẙ' => 'ẙ', + 'ẛ' => 'ẛ', + 'Ạ' => 'Ạ', + 'ạ' => 'ạ', + 'Ả' => 'Ả', + 'ả' => 'ả', + 'Ấ' => 'Ấ', + 'ấ' => 'ấ', + 'Ầ' => 'Ầ', + 'ầ' => 'ầ', + 'Ẩ' => 'Ẩ', + 'ẩ' => 'ẩ', + 'Ẫ' => 'Ẫ', + 'ẫ' => 'ẫ', + 'Ậ' => 'Ậ', + 'ậ' => 'ậ', + 'Ắ' => 'Ắ', + 'ắ' => 'ắ', + 'Ằ' => 'Ằ', + 'ằ' => 'ằ', + 'Ẳ' => 'Ẳ', + 'ẳ' => 'ẳ', + 'Ẵ' => 'Ẵ', + 'ẵ' => 'ẵ', + 'Ặ' => 'Ặ', + 'ặ' => 'ặ', + 'Ẹ' => 'Ẹ', + 'ẹ' => 'ẹ', + 'Ẻ' => 'Ẻ', + 'ẻ' => 'ẻ', + 'Ẽ' => 'Ẽ', + 'ẽ' => 'ẽ', + 'Ế' => 'Ế', + 'ế' => 'ế', + 'Ề' => 'Ề', + 'ề' => 'ề', + 'Ể' => 'Ể', + 'ể' => 'ể', + 'Ễ' => 'Ễ', + 'ễ' => 'ễ', + 'Ệ' => 'Ệ', + 'ệ' => 'ệ', + 'Ỉ' => 'Ỉ', + 'ỉ' => 'ỉ', + 'Ị' => 'Ị', + 'ị' => 'ị', + 'Ọ' => 'Ọ', + 'ọ' => 'ọ', + 'Ỏ' => 'Ỏ', + 'ỏ' => 'ỏ', + 'Ố' => 'Ố', + 'ố' => 'ố', + 'Ồ' => 'Ồ', + 'ồ' => 'ồ', + 'Ổ' => 'Ổ', + 'ổ' => 'ổ', + 'Ỗ' => 'Ỗ', + 'ỗ' => 'ỗ', + 'Ộ' => 'Ộ', + 'ộ' => 'ộ', + 'Ớ' => 'Ớ', + 'ớ' => 'ớ', + 'Ờ' => 'Ờ', + 'ờ' => 'ờ', + 'Ở' => 'Ở', + 'ở' => 'ở', + 'Ỡ' => 'Ỡ', + 'ỡ' => 'ỡ', + 'Ợ' => 'Ợ', + 'ợ' => 'ợ', + 'Ụ' => 'Ụ', + 'ụ' => 'ụ', + 'Ủ' => 'Ủ', + 'ủ' => 'ủ', + 'Ứ' => 'Ứ', + 'ứ' => 'ứ', + 'Ừ' => 'Ừ', + 'ừ' => 'ừ', + 'Ử' => 'Ử', + 'ử' => 'ử', + 'Ữ' => 'Ữ', + 'ữ' => 'ữ', + 'Ự' => 'Ự', + 'ự' => 'ự', + 'Ỳ' => 'Ỳ', + 'ỳ' => 'ỳ', + 'Ỵ' => 'Ỵ', + 'ỵ' => 'ỵ', + 'Ỷ' => 'Ỷ', + 'ỷ' => 'ỷ', + 'Ỹ' => 'Ỹ', + 'ỹ' => 'ỹ', + 'ἀ' => 'ἀ', + 'ἁ' => 'ἁ', + 'ἂ' => 'ἂ', + 'ἃ' => 'ἃ', + 'ἄ' => 'ἄ', + 'ἅ' => 'ἅ', + 'ἆ' => 'ἆ', + 'ἇ' => 'ἇ', + 'Ἀ' => 'Ἀ', + 'Ἁ' => 'Ἁ', + 'Ἂ' => 'Ἂ', + 'Ἃ' => 'Ἃ', + 'Ἄ' => 'Ἄ', + 'Ἅ' => 'Ἅ', + 'Ἆ' => 'Ἆ', + 'Ἇ' => 'Ἇ', + 'ἐ' => 'ἐ', + 'ἑ' => 'ἑ', + 'ἒ' => 'ἒ', + 'ἓ' => 'ἓ', + 'ἔ' => 'ἔ', + 'ἕ' => 'ἕ', + 'Ἐ' => 'Ἐ', + 'Ἑ' => 'Ἑ', + 'Ἒ' => 'Ἒ', + 'Ἓ' => 'Ἓ', + 'Ἔ' => 'Ἔ', + 'Ἕ' => 'Ἕ', + 'ἠ' => 'ἠ', + 'ἡ' => 'ἡ', + 'ἢ' => 'ἢ', + 'ἣ' => 'ἣ', + 'ἤ' => 'ἤ', + 'ἥ' => 'ἥ', + 'ἦ' => 'ἦ', + 'ἧ' => 'ἧ', + 'Ἠ' => 'Ἠ', + 'Ἡ' => 'Ἡ', + 'Ἢ' => 'Ἢ', + 'Ἣ' => 'Ἣ', + 'Ἤ' => 'Ἤ', + 'Ἥ' => 'Ἥ', + 'Ἦ' => 'Ἦ', + 'Ἧ' => 'Ἧ', + 'ἰ' => 'ἰ', + 'ἱ' => 'ἱ', + 'ἲ' => 'ἲ', + 'ἳ' => 'ἳ', + 'ἴ' => 'ἴ', + 'ἵ' => 'ἵ', + 'ἶ' => 'ἶ', + 'ἷ' => 'ἷ', + 'Ἰ' => 'Ἰ', + 'Ἱ' => 'Ἱ', + 'Ἲ' => 'Ἲ', + 'Ἳ' => 'Ἳ', + 'Ἴ' => 'Ἴ', + 'Ἵ' => 'Ἵ', + 'Ἶ' => 'Ἶ', + 'Ἷ' => 'Ἷ', + 'ὀ' => 'ὀ', + 'ὁ' => 'ὁ', + 'ὂ' => 'ὂ', + 'ὃ' => 'ὃ', + 'ὄ' => 'ὄ', + 'ὅ' => 'ὅ', + 'Ὀ' => 'Ὀ', + 'Ὁ' => 'Ὁ', + 'Ὂ' => 'Ὂ', + 'Ὃ' => 'Ὃ', + 'Ὄ' => 'Ὄ', + 'Ὅ' => 'Ὅ', + 'ὐ' => 'ὐ', + 'ὑ' => 'ὑ', + 'ὒ' => 'ὒ', + 'ὓ' => 'ὓ', + 'ὔ' => 'ὔ', + 'ὕ' => 'ὕ', + 'ὖ' => 'ὖ', + 'ὗ' => 'ὗ', + 'Ὑ' => 'Ὑ', + 'Ὓ' => 'Ὓ', + 'Ὕ' => 'Ὕ', + 'Ὗ' => 'Ὗ', + 'ὠ' => 'ὠ', + 'ὡ' => 'ὡ', + 'ὢ' => 'ὢ', + 'ὣ' => 'ὣ', + 'ὤ' => 'ὤ', + 'ὥ' => 'ὥ', + 'ὦ' => 'ὦ', + 'ὧ' => 'ὧ', + 'Ὠ' => 'Ὠ', + 'Ὡ' => 'Ὡ', + 'Ὢ' => 'Ὢ', + 'Ὣ' => 'Ὣ', + 'Ὤ' => 'Ὤ', + 'Ὥ' => 'Ὥ', + 'Ὦ' => 'Ὦ', + 'Ὧ' => 'Ὧ', + 'ὰ' => 'ὰ', + 'ὲ' => 'ὲ', + 'ὴ' => 'ὴ', + 'ὶ' => 'ὶ', + 'ὸ' => 'ὸ', + 'ὺ' => 'ὺ', + 'ὼ' => 'ὼ', + 'ᾀ' => 'ᾀ', + 'ᾁ' => 'ᾁ', + 'ᾂ' => 'ᾂ', + 'ᾃ' => 'ᾃ', + 'ᾄ' => 'ᾄ', + 'ᾅ' => 'ᾅ', + 'ᾆ' => 'ᾆ', + 'ᾇ' => 'ᾇ', + 'ᾈ' => 'ᾈ', + 'ᾉ' => 'ᾉ', + 'ᾊ' => 'ᾊ', + 'ᾋ' => 'ᾋ', + 'ᾌ' => 'ᾌ', + 'ᾍ' => 'ᾍ', + 'ᾎ' => 'ᾎ', + 'ᾏ' => 'ᾏ', + 'ᾐ' => 'ᾐ', + 'ᾑ' => 'ᾑ', + 'ᾒ' => 'ᾒ', + 'ᾓ' => 'ᾓ', + 'ᾔ' => 'ᾔ', + 'ᾕ' => 'ᾕ', + 'ᾖ' => 'ᾖ', + 'ᾗ' => 'ᾗ', + 'ᾘ' => 'ᾘ', + 'ᾙ' => 'ᾙ', + 'ᾚ' => 'ᾚ', + 'ᾛ' => 'ᾛ', + 'ᾜ' => 'ᾜ', + 'ᾝ' => 'ᾝ', + 'ᾞ' => 'ᾞ', + 'ᾟ' => 'ᾟ', + 'ᾠ' => 'ᾠ', + 'ᾡ' => 'ᾡ', + 'ᾢ' => 'ᾢ', + 'ᾣ' => 'ᾣ', + 'ᾤ' => 'ᾤ', + 'ᾥ' => 'ᾥ', + 'ᾦ' => 'ᾦ', + 'ᾧ' => 'ᾧ', + 'ᾨ' => 'ᾨ', + 'ᾩ' => 'ᾩ', + 'ᾪ' => 'ᾪ', + 'ᾫ' => 'ᾫ', + 'ᾬ' => 'ᾬ', + 'ᾭ' => 'ᾭ', + 'ᾮ' => 'ᾮ', + 'ᾯ' => 'ᾯ', + 'ᾰ' => 'ᾰ', + 'ᾱ' => 'ᾱ', + 'ᾲ' => 'ᾲ', + 'ᾳ' => 'ᾳ', + 'ᾴ' => 'ᾴ', + 'ᾶ' => 'ᾶ', + 'ᾷ' => 'ᾷ', + 'Ᾰ' => 'Ᾰ', + 'Ᾱ' => 'Ᾱ', + 'Ὰ' => 'Ὰ', + 'ᾼ' => 'ᾼ', + '῁' => '῁', + 'ῂ' => 'ῂ', + 'ῃ' => 'ῃ', + 'ῄ' => 'ῄ', + 'ῆ' => 'ῆ', + 'ῇ' => 'ῇ', + 'Ὲ' => 'Ὲ', + 'Ὴ' => 'Ὴ', + 'ῌ' => 'ῌ', + '῍' => '῍', + '῎' => '῎', + '῏' => '῏', + 'ῐ' => 'ῐ', + 'ῑ' => 'ῑ', + 'ῒ' => 'ῒ', + 'ῖ' => 'ῖ', + 'ῗ' => 'ῗ', + 'Ῐ' => 'Ῐ', + 'Ῑ' => 'Ῑ', + 'Ὶ' => 'Ὶ', + '῝' => '῝', + '῞' => '῞', + '῟' => '῟', + 'ῠ' => 'ῠ', + 'ῡ' => 'ῡ', + 'ῢ' => 'ῢ', + 'ῤ' => 'ῤ', + 'ῥ' => 'ῥ', + 'ῦ' => 'ῦ', + 'ῧ' => 'ῧ', + 'Ῠ' => 'Ῠ', + 'Ῡ' => 'Ῡ', + 'Ὺ' => 'Ὺ', + 'Ῥ' => 'Ῥ', + '῭' => '῭', + 'ῲ' => 'ῲ', + 'ῳ' => 'ῳ', + 'ῴ' => 'ῴ', + 'ῶ' => 'ῶ', + 'ῷ' => 'ῷ', + 'Ὸ' => 'Ὸ', + 'Ὼ' => 'Ὼ', + 'ῼ' => 'ῼ', + '↚' => '↚', + '↛' => '↛', + '↮' => '↮', + '⇍' => '⇍', + '⇎' => '⇎', + '⇏' => '⇏', + '∄' => '∄', + '∉' => '∉', + '∌' => '∌', + '∤' => '∤', + '∦' => '∦', + '≁' => '≁', + '≄' => '≄', + '≇' => '≇', + '≉' => '≉', + '≠' => '≠', + '≢' => '≢', + '≭' => '≭', + '≮' => '≮', + '≯' => '≯', + '≰' => '≰', + '≱' => '≱', + '≴' => '≴', + '≵' => '≵', + '≸' => '≸', + '≹' => '≹', + '⊀' => '⊀', + '⊁' => '⊁', + '⊄' => '⊄', + '⊅' => '⊅', + '⊈' => '⊈', + '⊉' => '⊉', + '⊬' => '⊬', + '⊭' => '⊭', + '⊮' => '⊮', + '⊯' => '⊯', + '⋠' => '⋠', + '⋡' => '⋡', + '⋢' => '⋢', + '⋣' => '⋣', + '⋪' => '⋪', + '⋫' => '⋫', + '⋬' => '⋬', + '⋭' => '⋭', + 'が' => 'が', + 'ぎ' => 'ぎ', + 'ぐ' => 'ぐ', + 'げ' => 'げ', + 'ご' => 'ご', + 'ざ' => 'ざ', + 'じ' => 'じ', + 'ず' => 'ず', + 'ぜ' => 'ぜ', + 'ぞ' => 'ぞ', + 'だ' => 'だ', + 'ぢ' => 'ぢ', + 'づ' => 'づ', + 'で' => 'で', + 'ど' => 'ど', + 'ば' => 'ば', + 'ぱ' => 'ぱ', + 'び' => 'び', + 'ぴ' => 'ぴ', + 'ぶ' => 'ぶ', + 'ぷ' => 'ぷ', + 'べ' => 'べ', + 'ぺ' => 'ぺ', + 'ぼ' => 'ぼ', + 'ぽ' => 'ぽ', + 'ゔ' => 'ゔ', + 'ゞ' => 'ゞ', + 'ガ' => 'ガ', + 'ギ' => 'ギ', + 'グ' => 'グ', + 'ゲ' => 'ゲ', + 'ゴ' => 'ゴ', + 'ザ' => 'ザ', + 'ジ' => 'ジ', + 'ズ' => 'ズ', + 'ゼ' => 'ゼ', + 'ゾ' => 'ゾ', + 'ダ' => 'ダ', + 'ヂ' => 'ヂ', + 'ヅ' => 'ヅ', + 'デ' => 'デ', + 'ド' => 'ド', + 'バ' => 'バ', + 'パ' => 'パ', + 'ビ' => 'ビ', + 'ピ' => 'ピ', + 'ブ' => 'ブ', + 'プ' => 'プ', + 'ベ' => 'ベ', + 'ペ' => 'ペ', + 'ボ' => 'ボ', + 'ポ' => 'ポ', + 'ヴ' => 'ヴ', + 'ヷ' => 'ヷ', + 'ヸ' => 'ヸ', + 'ヹ' => 'ヹ', + 'ヺ' => 'ヺ', + 'ヾ' => 'ヾ', + '𑂚' => '𑂚', + '𑂜' => '𑂜', + '𑂫' => '𑂫', + '𑄮' => '𑄮', + '𑄯' => '𑄯', + '𑍋' => '𑍋', + '𑍌' => '𑍌', + '𑒻' => '𑒻', + '𑒼' => '𑒼', + '𑒾' => '𑒾', + '𑖺' => '𑖺', + '𑖻' => '𑖻', + '𑤸' => '𑤸', +); diff --git a/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php new file mode 100644 index 0000000..5a3e8e0 --- /dev/null +++ b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/canonicalDecomposition.php @@ -0,0 +1,2065 @@ + 'À', + 'Á' => 'Á', + 'Â' => 'Â', + 'Ã' => 'Ã', + 'Ä' => 'Ä', + 'Å' => 'Å', + 'Ç' => 'Ç', + 'È' => 'È', + 'É' => 'É', + 'Ê' => 'Ê', + 'Ë' => 'Ë', + 'Ì' => 'Ì', + 'Í' => 'Í', + 'Î' => 'Î', + 'Ï' => 'Ï', + 'Ñ' => 'Ñ', + 'Ò' => 'Ò', + 'Ó' => 'Ó', + 'Ô' => 'Ô', + 'Õ' => 'Õ', + 'Ö' => 'Ö', + 'Ù' => 'Ù', + 'Ú' => 'Ú', + 'Û' => 'Û', + 'Ü' => 'Ü', + 'Ý' => 'Ý', + 'à' => 'à', + 'á' => 'á', + 'â' => 'â', + 'ã' => 'ã', + 'ä' => 'ä', + 'å' => 'å', + 'ç' => 'ç', + 'è' => 'è', + 'é' => 'é', + 'ê' => 'ê', + 'ë' => 'ë', + 'ì' => 'ì', + 'í' => 'í', + 'î' => 'î', + 'ï' => 'ï', + 'ñ' => 'ñ', + 'ò' => 'ò', + 'ó' => 'ó', + 'ô' => 'ô', + 'õ' => 'õ', + 'ö' => 'ö', + 'ù' => 'ù', + 'ú' => 'ú', + 'û' => 'û', + 'ü' => 'ü', + 'ý' => 'ý', + 'ÿ' => 'ÿ', + 'Ā' => 'Ā', + 'ā' => 'ā', + 'Ă' => 'Ă', + 'ă' => 'ă', + 'Ą' => 'Ą', + 'ą' => 'ą', + 'Ć' => 'Ć', + 'ć' => 'ć', + 'Ĉ' => 'Ĉ', + 'ĉ' => 'ĉ', + 'Ċ' => 'Ċ', + 'ċ' => 'ċ', + 'Č' => 'Č', + 'č' => 'č', + 'Ď' => 'Ď', + 'ď' => 'ď', + 'Ē' => 'Ē', + 'ē' => 'ē', + 'Ĕ' => 'Ĕ', + 'ĕ' => 'ĕ', + 'Ė' => 'Ė', + 'ė' => 'ė', + 'Ę' => 'Ę', + 'ę' => 'ę', + 'Ě' => 'Ě', + 'ě' => 'ě', + 'Ĝ' => 'Ĝ', + 'ĝ' => 'ĝ', + 'Ğ' => 'Ğ', + 'ğ' => 'ğ', + 'Ġ' => 'Ġ', + 'ġ' => 'ġ', + 'Ģ' => 'Ģ', + 'ģ' => 'ģ', + 'Ĥ' => 'Ĥ', + 'ĥ' => 'ĥ', + 'Ĩ' => 'Ĩ', + 'ĩ' => 'ĩ', + 'Ī' => 'Ī', + 'ī' => 'ī', + 'Ĭ' => 'Ĭ', + 'ĭ' => 'ĭ', + 'Į' => 'Į', + 'į' => 'į', + 'İ' => 'İ', + 'Ĵ' => 'Ĵ', + 'ĵ' => 'ĵ', + 'Ķ' => 'Ķ', + 'ķ' => 'ķ', + 'Ĺ' => 'Ĺ', + 'ĺ' => 'ĺ', + 'Ļ' => 'Ļ', + 'ļ' => 'ļ', + 'Ľ' => 'Ľ', + 'ľ' => 'ľ', + 'Ń' => 'Ń', + 'ń' => 'ń', + 'Ņ' => 'Ņ', + 'ņ' => 'ņ', + 'Ň' => 'Ň', + 'ň' => 'ň', + 'Ō' => 'Ō', + 'ō' => 'ō', + 'Ŏ' => 'Ŏ', + 'ŏ' => 'ŏ', + 'Ő' => 'Ő', + 'ő' => 'ő', + 'Ŕ' => 'Ŕ', + 'ŕ' => 'ŕ', + 'Ŗ' => 'Ŗ', + 'ŗ' => 'ŗ', + 'Ř' => 'Ř', + 'ř' => 'ř', + 'Ś' => 'Ś', + 'ś' => 'ś', + 'Ŝ' => 'Ŝ', + 'ŝ' => 'ŝ', + 'Ş' => 'Ş', + 'ş' => 'ş', + 'Š' => 'Š', + 'š' => 'š', + 'Ţ' => 'Ţ', + 'ţ' => 'ţ', + 'Ť' => 'Ť', + 'ť' => 'ť', + 'Ũ' => 'Ũ', + 'ũ' => 'ũ', + 'Ū' => 'Ū', + 'ū' => 'ū', + 'Ŭ' => 'Ŭ', + 'ŭ' => 'ŭ', + 'Ů' => 'Ů', + 'ů' => 'ů', + 'Ű' => 'Ű', + 'ű' => 'ű', + 'Ų' => 'Ų', + 'ų' => 'ų', + 'Ŵ' => 'Ŵ', + 'ŵ' => 'ŵ', + 'Ŷ' => 'Ŷ', + 'ŷ' => 'ŷ', + 'Ÿ' => 'Ÿ', + 'Ź' => 'Ź', + 'ź' => 'ź', + 'Ż' => 'Ż', + 'ż' => 'ż', + 'Ž' => 'Ž', + 'ž' => 'ž', + 'Ơ' => 'Ơ', + 'ơ' => 'ơ', + 'Ư' => 'Ư', + 'ư' => 'ư', + 'Ǎ' => 'Ǎ', + 'ǎ' => 'ǎ', + 'Ǐ' => 'Ǐ', + 'ǐ' => 'ǐ', + 'Ǒ' => 'Ǒ', + 'ǒ' => 'ǒ', + 'Ǔ' => 'Ǔ', + 'ǔ' => 'ǔ', + 'Ǖ' => 'Ǖ', + 'ǖ' => 'ǖ', + 'Ǘ' => 'Ǘ', + 'ǘ' => 'ǘ', + 'Ǚ' => 'Ǚ', + 'ǚ' => 'ǚ', + 'Ǜ' => 'Ǜ', + 'ǜ' => 'ǜ', + 'Ǟ' => 'Ǟ', + 'ǟ' => 'ǟ', + 'Ǡ' => 'Ǡ', + 'ǡ' => 'ǡ', + 'Ǣ' => 'Ǣ', + 'ǣ' => 'ǣ', + 'Ǧ' => 'Ǧ', + 'ǧ' => 'ǧ', + 'Ǩ' => 'Ǩ', + 'ǩ' => 'ǩ', + 'Ǫ' => 'Ǫ', + 'ǫ' => 'ǫ', + 'Ǭ' => 'Ǭ', + 'ǭ' => 'ǭ', + 'Ǯ' => 'Ǯ', + 'ǯ' => 'ǯ', + 'ǰ' => 'ǰ', + 'Ǵ' => 'Ǵ', + 'ǵ' => 'ǵ', + 'Ǹ' => 'Ǹ', + 'ǹ' => 'ǹ', + 'Ǻ' => 'Ǻ', + 'ǻ' => 'ǻ', + 'Ǽ' => 'Ǽ', + 'ǽ' => 'ǽ', + 'Ǿ' => 'Ǿ', + 'ǿ' => 'ǿ', + 'Ȁ' => 'Ȁ', + 'ȁ' => 'ȁ', + 'Ȃ' => 'Ȃ', + 'ȃ' => 'ȃ', + 'Ȅ' => 'Ȅ', + 'ȅ' => 'ȅ', + 'Ȇ' => 'Ȇ', + 'ȇ' => 'ȇ', + 'Ȉ' => 'Ȉ', + 'ȉ' => 'ȉ', + 'Ȋ' => 'Ȋ', + 'ȋ' => 'ȋ', + 'Ȍ' => 'Ȍ', + 'ȍ' => 'ȍ', + 'Ȏ' => 'Ȏ', + 'ȏ' => 'ȏ', + 'Ȑ' => 'Ȑ', + 'ȑ' => 'ȑ', + 'Ȓ' => 'Ȓ', + 'ȓ' => 'ȓ', + 'Ȕ' => 'Ȕ', + 'ȕ' => 'ȕ', + 'Ȗ' => 'Ȗ', + 'ȗ' => 'ȗ', + 'Ș' => 'Ș', + 'ș' => 'ș', + 'Ț' => 'Ț', + 'ț' => 'ț', + 'Ȟ' => 'Ȟ', + 'ȟ' => 'ȟ', + 'Ȧ' => 'Ȧ', + 'ȧ' => 'ȧ', + 'Ȩ' => 'Ȩ', + 'ȩ' => 'ȩ', + 'Ȫ' => 'Ȫ', + 'ȫ' => 'ȫ', + 'Ȭ' => 'Ȭ', + 'ȭ' => 'ȭ', + 'Ȯ' => 'Ȯ', + 'ȯ' => 'ȯ', + 'Ȱ' => 'Ȱ', + 'ȱ' => 'ȱ', + 'Ȳ' => 'Ȳ', + 'ȳ' => 'ȳ', + '̀' => '̀', + '́' => '́', + '̓' => '̓', + '̈́' => '̈́', + 'ʹ' => 'ʹ', + ';' => ';', + '΅' => '΅', + 'Ά' => 'Ά', + '·' => '·', + 'Έ' => 'Έ', + 'Ή' => 'Ή', + 'Ί' => 'Ί', + 'Ό' => 'Ό', + 'Ύ' => 'Ύ', + 'Ώ' => 'Ώ', + 'ΐ' => 'ΐ', + 'Ϊ' => 'Ϊ', + 'Ϋ' => 'Ϋ', + 'ά' => 'ά', + 'έ' => 'έ', + 'ή' => 'ή', + 'ί' => 'ί', + 'ΰ' => 'ΰ', + 'ϊ' => 'ϊ', + 'ϋ' => 'ϋ', + 'ό' => 'ό', + 'ύ' => 'ύ', + 'ώ' => 'ώ', + 'ϓ' => 'ϓ', + 'ϔ' => 'ϔ', + 'Ѐ' => 'Ѐ', + 'Ё' => 'Ё', + 'Ѓ' => 'Ѓ', + 'Ї' => 'Ї', + 'Ќ' => 'Ќ', + 'Ѝ' => 'Ѝ', + 'Ў' => 'Ў', + 'Й' => 'Й', + 'й' => 'й', + 'ѐ' => 'ѐ', + 'ё' => 'ё', + 'ѓ' => 'ѓ', + 'ї' => 'ї', + 'ќ' => 'ќ', + 'ѝ' => 'ѝ', + 'ў' => 'ў', + 'Ѷ' => 'Ѷ', + 'ѷ' => 'ѷ', + 'Ӂ' => 'Ӂ', + 'ӂ' => 'ӂ', + 'Ӑ' => 'Ӑ', + 'ӑ' => 'ӑ', + 'Ӓ' => 'Ӓ', + 'ӓ' => 'ӓ', + 'Ӗ' => 'Ӗ', + 'ӗ' => 'ӗ', + 'Ӛ' => 'Ӛ', + 'ӛ' => 'ӛ', + 'Ӝ' => 'Ӝ', + 'ӝ' => 'ӝ', + 'Ӟ' => 'Ӟ', + 'ӟ' => 'ӟ', + 'Ӣ' => 'Ӣ', + 'ӣ' => 'ӣ', + 'Ӥ' => 'Ӥ', + 'ӥ' => 'ӥ', + 'Ӧ' => 'Ӧ', + 'ӧ' => 'ӧ', + 'Ӫ' => 'Ӫ', + 'ӫ' => 'ӫ', + 'Ӭ' => 'Ӭ', + 'ӭ' => 'ӭ', + 'Ӯ' => 'Ӯ', + 'ӯ' => 'ӯ', + 'Ӱ' => 'Ӱ', + 'ӱ' => 'ӱ', + 'Ӳ' => 'Ӳ', + 'ӳ' => 'ӳ', + 'Ӵ' => 'Ӵ', + 'ӵ' => 'ӵ', + 'Ӹ' => 'Ӹ', + 'ӹ' => 'ӹ', + 'آ' => 'آ', + 'أ' => 'أ', + 'ؤ' => 'ؤ', + 'إ' => 'إ', + 'ئ' => 'ئ', + 'ۀ' => 'ۀ', + 'ۂ' => 'ۂ', + 'ۓ' => 'ۓ', + 'ऩ' => 'ऩ', + 'ऱ' => 'ऱ', + 'ऴ' => 'ऴ', + 'क़' => 'क़', + 'ख़' => 'ख़', + 'ग़' => 'ग़', + 'ज़' => 'ज़', + 'ड़' => 'ड़', + 'ढ़' => 'ढ़', + 'फ़' => 'फ़', + 'य़' => 'य़', + 'ো' => 'ো', + 'ৌ' => 'ৌ', + 'ড়' => 'ড়', + 'ঢ়' => 'ঢ়', + 'য়' => 'য়', + 'ਲ਼' => 'ਲ਼', + 'ਸ਼' => 'ਸ਼', + 'ਖ਼' => 'ਖ਼', + 'ਗ਼' => 'ਗ਼', + 'ਜ਼' => 'ਜ਼', + 'ਫ਼' => 'ਫ਼', + 'ୈ' => 'ୈ', + 'ୋ' => 'ୋ', + 'ୌ' => 'ୌ', + 'ଡ଼' => 'ଡ଼', + 'ଢ଼' => 'ଢ଼', + 'ஔ' => 'ஔ', + 'ொ' => 'ொ', + 'ோ' => 'ோ', + 'ௌ' => 'ௌ', + 'ై' => 'ై', + 'ೀ' => 'ೀ', + 'ೇ' => 'ೇ', + 'ೈ' => 'ೈ', + 'ೊ' => 'ೊ', + 'ೋ' => 'ೋ', + 'ൊ' => 'ൊ', + 'ോ' => 'ോ', + 'ൌ' => 'ൌ', + 'ේ' => 'ේ', + 'ො' => 'ො', + 'ෝ' => 'ෝ', + 'ෞ' => 'ෞ', + 'གྷ' => 'གྷ', + 'ཌྷ' => 'ཌྷ', + 'དྷ' => 'དྷ', + 'བྷ' => 'བྷ', + 'ཛྷ' => 'ཛྷ', + 'ཀྵ' => 'ཀྵ', + 'ཱི' => 'ཱི', + 'ཱུ' => 'ཱུ', + 'ྲྀ' => 'ྲྀ', + 'ླྀ' => 'ླྀ', + 'ཱྀ' => 'ཱྀ', + 'ྒྷ' => 'ྒྷ', + 'ྜྷ' => 'ྜྷ', + 'ྡྷ' => 'ྡྷ', + 'ྦྷ' => 'ྦྷ', + 'ྫྷ' => 'ྫྷ', + 'ྐྵ' => 'ྐྵ', + 'ဦ' => 'ဦ', + 'ᬆ' => 'ᬆ', + 'ᬈ' => 'ᬈ', + 'ᬊ' => 'ᬊ', + 'ᬌ' => 'ᬌ', + 'ᬎ' => 'ᬎ', + 'ᬒ' => 'ᬒ', + 'ᬻ' => 'ᬻ', + 'ᬽ' => 'ᬽ', + 'ᭀ' => 'ᭀ', + 'ᭁ' => 'ᭁ', + 'ᭃ' => 'ᭃ', + 'Ḁ' => 'Ḁ', + 'ḁ' => 'ḁ', + 'Ḃ' => 'Ḃ', + 'ḃ' => 'ḃ', + 'Ḅ' => 'Ḅ', + 'ḅ' => 'ḅ', + 'Ḇ' => 'Ḇ', + 'ḇ' => 'ḇ', + 'Ḉ' => 'Ḉ', + 'ḉ' => 'ḉ', + 'Ḋ' => 'Ḋ', + 'ḋ' => 'ḋ', + 'Ḍ' => 'Ḍ', + 'ḍ' => 'ḍ', + 'Ḏ' => 'Ḏ', + 'ḏ' => 'ḏ', + 'Ḑ' => 'Ḑ', + 'ḑ' => 'ḑ', + 'Ḓ' => 'Ḓ', + 'ḓ' => 'ḓ', + 'Ḕ' => 'Ḕ', + 'ḕ' => 'ḕ', + 'Ḗ' => 'Ḗ', + 'ḗ' => 'ḗ', + 'Ḙ' => 'Ḙ', + 'ḙ' => 'ḙ', + 'Ḛ' => 'Ḛ', + 'ḛ' => 'ḛ', + 'Ḝ' => 'Ḝ', + 'ḝ' => 'ḝ', + 'Ḟ' => 'Ḟ', + 'ḟ' => 'ḟ', + 'Ḡ' => 'Ḡ', + 'ḡ' => 'ḡ', + 'Ḣ' => 'Ḣ', + 'ḣ' => 'ḣ', + 'Ḥ' => 'Ḥ', + 'ḥ' => 'ḥ', + 'Ḧ' => 'Ḧ', + 'ḧ' => 'ḧ', + 'Ḩ' => 'Ḩ', + 'ḩ' => 'ḩ', + 'Ḫ' => 'Ḫ', + 'ḫ' => 'ḫ', + 'Ḭ' => 'Ḭ', + 'ḭ' => 'ḭ', + 'Ḯ' => 'Ḯ', + 'ḯ' => 'ḯ', + 'Ḱ' => 'Ḱ', + 'ḱ' => 'ḱ', + 'Ḳ' => 'Ḳ', + 'ḳ' => 'ḳ', + 'Ḵ' => 'Ḵ', + 'ḵ' => 'ḵ', + 'Ḷ' => 'Ḷ', + 'ḷ' => 'ḷ', + 'Ḹ' => 'Ḹ', + 'ḹ' => 'ḹ', + 'Ḻ' => 'Ḻ', + 'ḻ' => 'ḻ', + 'Ḽ' => 'Ḽ', + 'ḽ' => 'ḽ', + 'Ḿ' => 'Ḿ', + 'ḿ' => 'ḿ', + 'Ṁ' => 'Ṁ', + 'ṁ' => 'ṁ', + 'Ṃ' => 'Ṃ', + 'ṃ' => 'ṃ', + 'Ṅ' => 'Ṅ', + 'ṅ' => 'ṅ', + 'Ṇ' => 'Ṇ', + 'ṇ' => 'ṇ', + 'Ṉ' => 'Ṉ', + 'ṉ' => 'ṉ', + 'Ṋ' => 'Ṋ', + 'ṋ' => 'ṋ', + 'Ṍ' => 'Ṍ', + 'ṍ' => 'ṍ', + 'Ṏ' => 'Ṏ', + 'ṏ' => 'ṏ', + 'Ṑ' => 'Ṑ', + 'ṑ' => 'ṑ', + 'Ṓ' => 'Ṓ', + 'ṓ' => 'ṓ', + 'Ṕ' => 'Ṕ', + 'ṕ' => 'ṕ', + 'Ṗ' => 'Ṗ', + 'ṗ' => 'ṗ', + 'Ṙ' => 'Ṙ', + 'ṙ' => 'ṙ', + 'Ṛ' => 'Ṛ', + 'ṛ' => 'ṛ', + 'Ṝ' => 'Ṝ', + 'ṝ' => 'ṝ', + 'Ṟ' => 'Ṟ', + 'ṟ' => 'ṟ', + 'Ṡ' => 'Ṡ', + 'ṡ' => 'ṡ', + 'Ṣ' => 'Ṣ', + 'ṣ' => 'ṣ', + 'Ṥ' => 'Ṥ', + 'ṥ' => 'ṥ', + 'Ṧ' => 'Ṧ', + 'ṧ' => 'ṧ', + 'Ṩ' => 'Ṩ', + 'ṩ' => 'ṩ', + 'Ṫ' => 'Ṫ', + 'ṫ' => 'ṫ', + 'Ṭ' => 'Ṭ', + 'ṭ' => 'ṭ', + 'Ṯ' => 'Ṯ', + 'ṯ' => 'ṯ', + 'Ṱ' => 'Ṱ', + 'ṱ' => 'ṱ', + 'Ṳ' => 'Ṳ', + 'ṳ' => 'ṳ', + 'Ṵ' => 'Ṵ', + 'ṵ' => 'ṵ', + 'Ṷ' => 'Ṷ', + 'ṷ' => 'ṷ', + 'Ṹ' => 'Ṹ', + 'ṹ' => 'ṹ', + 'Ṻ' => 'Ṻ', + 'ṻ' => 'ṻ', + 'Ṽ' => 'Ṽ', + 'ṽ' => 'ṽ', + 'Ṿ' => 'Ṿ', + 'ṿ' => 'ṿ', + 'Ẁ' => 'Ẁ', + 'ẁ' => 'ẁ', + 'Ẃ' => 'Ẃ', + 'ẃ' => 'ẃ', + 'Ẅ' => 'Ẅ', + 'ẅ' => 'ẅ', + 'Ẇ' => 'Ẇ', + 'ẇ' => 'ẇ', + 'Ẉ' => 'Ẉ', + 'ẉ' => 'ẉ', + 'Ẋ' => 'Ẋ', + 'ẋ' => 'ẋ', + 'Ẍ' => 'Ẍ', + 'ẍ' => 'ẍ', + 'Ẏ' => 'Ẏ', + 'ẏ' => 'ẏ', + 'Ẑ' => 'Ẑ', + 'ẑ' => 'ẑ', + 'Ẓ' => 'Ẓ', + 'ẓ' => 'ẓ', + 'Ẕ' => 'Ẕ', + 'ẕ' => 'ẕ', + 'ẖ' => 'ẖ', + 'ẗ' => 'ẗ', + 'ẘ' => 'ẘ', + 'ẙ' => 'ẙ', + 'ẛ' => 'ẛ', + 'Ạ' => 'Ạ', + 'ạ' => 'ạ', + 'Ả' => 'Ả', + 'ả' => 'ả', + 'Ấ' => 'Ấ', + 'ấ' => 'ấ', + 'Ầ' => 'Ầ', + 'ầ' => 'ầ', + 'Ẩ' => 'Ẩ', + 'ẩ' => 'ẩ', + 'Ẫ' => 'Ẫ', + 'ẫ' => 'ẫ', + 'Ậ' => 'Ậ', + 'ậ' => 'ậ', + 'Ắ' => 'Ắ', + 'ắ' => 'ắ', + 'Ằ' => 'Ằ', + 'ằ' => 'ằ', + 'Ẳ' => 'Ẳ', + 'ẳ' => 'ẳ', + 'Ẵ' => 'Ẵ', + 'ẵ' => 'ẵ', + 'Ặ' => 'Ặ', + 'ặ' => 'ặ', + 'Ẹ' => 'Ẹ', + 'ẹ' => 'ẹ', + 'Ẻ' => 'Ẻ', + 'ẻ' => 'ẻ', + 'Ẽ' => 'Ẽ', + 'ẽ' => 'ẽ', + 'Ế' => 'Ế', + 'ế' => 'ế', + 'Ề' => 'Ề', + 'ề' => 'ề', + 'Ể' => 'Ể', + 'ể' => 'ể', + 'Ễ' => 'Ễ', + 'ễ' => 'ễ', + 'Ệ' => 'Ệ', + 'ệ' => 'ệ', + 'Ỉ' => 'Ỉ', + 'ỉ' => 'ỉ', + 'Ị' => 'Ị', + 'ị' => 'ị', + 'Ọ' => 'Ọ', + 'ọ' => 'ọ', + 'Ỏ' => 'Ỏ', + 'ỏ' => 'ỏ', + 'Ố' => 'Ố', + 'ố' => 'ố', + 'Ồ' => 'Ồ', + 'ồ' => 'ồ', + 'Ổ' => 'Ổ', + 'ổ' => 'ổ', + 'Ỗ' => 'Ỗ', + 'ỗ' => 'ỗ', + 'Ộ' => 'Ộ', + 'ộ' => 'ộ', + 'Ớ' => 'Ớ', + 'ớ' => 'ớ', + 'Ờ' => 'Ờ', + 'ờ' => 'ờ', + 'Ở' => 'Ở', + 'ở' => 'ở', + 'Ỡ' => 'Ỡ', + 'ỡ' => 'ỡ', + 'Ợ' => 'Ợ', + 'ợ' => 'ợ', + 'Ụ' => 'Ụ', + 'ụ' => 'ụ', + 'Ủ' => 'Ủ', + 'ủ' => 'ủ', + 'Ứ' => 'Ứ', + 'ứ' => 'ứ', + 'Ừ' => 'Ừ', + 'ừ' => 'ừ', + 'Ử' => 'Ử', + 'ử' => 'ử', + 'Ữ' => 'Ữ', + 'ữ' => 'ữ', + 'Ự' => 'Ự', + 'ự' => 'ự', + 'Ỳ' => 'Ỳ', + 'ỳ' => 'ỳ', + 'Ỵ' => 'Ỵ', + 'ỵ' => 'ỵ', + 'Ỷ' => 'Ỷ', + 'ỷ' => 'ỷ', + 'Ỹ' => 'Ỹ', + 'ỹ' => 'ỹ', + 'ἀ' => 'ἀ', + 'ἁ' => 'ἁ', + 'ἂ' => 'ἂ', + 'ἃ' => 'ἃ', + 'ἄ' => 'ἄ', + 'ἅ' => 'ἅ', + 'ἆ' => 'ἆ', + 'ἇ' => 'ἇ', + 'Ἀ' => 'Ἀ', + 'Ἁ' => 'Ἁ', + 'Ἂ' => 'Ἂ', + 'Ἃ' => 'Ἃ', + 'Ἄ' => 'Ἄ', + 'Ἅ' => 'Ἅ', + 'Ἆ' => 'Ἆ', + 'Ἇ' => 'Ἇ', + 'ἐ' => 'ἐ', + 'ἑ' => 'ἑ', + 'ἒ' => 'ἒ', + 'ἓ' => 'ἓ', + 'ἔ' => 'ἔ', + 'ἕ' => 'ἕ', + 'Ἐ' => 'Ἐ', + 'Ἑ' => 'Ἑ', + 'Ἒ' => 'Ἒ', + 'Ἓ' => 'Ἓ', + 'Ἔ' => 'Ἔ', + 'Ἕ' => 'Ἕ', + 'ἠ' => 'ἠ', + 'ἡ' => 'ἡ', + 'ἢ' => 'ἢ', + 'ἣ' => 'ἣ', + 'ἤ' => 'ἤ', + 'ἥ' => 'ἥ', + 'ἦ' => 'ἦ', + 'ἧ' => 'ἧ', + 'Ἠ' => 'Ἠ', + 'Ἡ' => 'Ἡ', + 'Ἢ' => 'Ἢ', + 'Ἣ' => 'Ἣ', + 'Ἤ' => 'Ἤ', + 'Ἥ' => 'Ἥ', + 'Ἦ' => 'Ἦ', + 'Ἧ' => 'Ἧ', + 'ἰ' => 'ἰ', + 'ἱ' => 'ἱ', + 'ἲ' => 'ἲ', + 'ἳ' => 'ἳ', + 'ἴ' => 'ἴ', + 'ἵ' => 'ἵ', + 'ἶ' => 'ἶ', + 'ἷ' => 'ἷ', + 'Ἰ' => 'Ἰ', + 'Ἱ' => 'Ἱ', + 'Ἲ' => 'Ἲ', + 'Ἳ' => 'Ἳ', + 'Ἴ' => 'Ἴ', + 'Ἵ' => 'Ἵ', + 'Ἶ' => 'Ἶ', + 'Ἷ' => 'Ἷ', + 'ὀ' => 'ὀ', + 'ὁ' => 'ὁ', + 'ὂ' => 'ὂ', + 'ὃ' => 'ὃ', + 'ὄ' => 'ὄ', + 'ὅ' => 'ὅ', + 'Ὀ' => 'Ὀ', + 'Ὁ' => 'Ὁ', + 'Ὂ' => 'Ὂ', + 'Ὃ' => 'Ὃ', + 'Ὄ' => 'Ὄ', + 'Ὅ' => 'Ὅ', + 'ὐ' => 'ὐ', + 'ὑ' => 'ὑ', + 'ὒ' => 'ὒ', + 'ὓ' => 'ὓ', + 'ὔ' => 'ὔ', + 'ὕ' => 'ὕ', + 'ὖ' => 'ὖ', + 'ὗ' => 'ὗ', + 'Ὑ' => 'Ὑ', + 'Ὓ' => 'Ὓ', + 'Ὕ' => 'Ὕ', + 'Ὗ' => 'Ὗ', + 'ὠ' => 'ὠ', + 'ὡ' => 'ὡ', + 'ὢ' => 'ὢ', + 'ὣ' => 'ὣ', + 'ὤ' => 'ὤ', + 'ὥ' => 'ὥ', + 'ὦ' => 'ὦ', + 'ὧ' => 'ὧ', + 'Ὠ' => 'Ὠ', + 'Ὡ' => 'Ὡ', + 'Ὢ' => 'Ὢ', + 'Ὣ' => 'Ὣ', + 'Ὤ' => 'Ὤ', + 'Ὥ' => 'Ὥ', + 'Ὦ' => 'Ὦ', + 'Ὧ' => 'Ὧ', + 'ὰ' => 'ὰ', + 'ά' => 'ά', + 'ὲ' => 'ὲ', + 'έ' => 'έ', + 'ὴ' => 'ὴ', + 'ή' => 'ή', + 'ὶ' => 'ὶ', + 'ί' => 'ί', + 'ὸ' => 'ὸ', + 'ό' => 'ό', + 'ὺ' => 'ὺ', + 'ύ' => 'ύ', + 'ὼ' => 'ὼ', + 'ώ' => 'ώ', + 'ᾀ' => 'ᾀ', + 'ᾁ' => 'ᾁ', + 'ᾂ' => 'ᾂ', + 'ᾃ' => 'ᾃ', + 'ᾄ' => 'ᾄ', + 'ᾅ' => 'ᾅ', + 'ᾆ' => 'ᾆ', + 'ᾇ' => 'ᾇ', + 'ᾈ' => 'ᾈ', + 'ᾉ' => 'ᾉ', + 'ᾊ' => 'ᾊ', + 'ᾋ' => 'ᾋ', + 'ᾌ' => 'ᾌ', + 'ᾍ' => 'ᾍ', + 'ᾎ' => 'ᾎ', + 'ᾏ' => 'ᾏ', + 'ᾐ' => 'ᾐ', + 'ᾑ' => 'ᾑ', + 'ᾒ' => 'ᾒ', + 'ᾓ' => 'ᾓ', + 'ᾔ' => 'ᾔ', + 'ᾕ' => 'ᾕ', + 'ᾖ' => 'ᾖ', + 'ᾗ' => 'ᾗ', + 'ᾘ' => 'ᾘ', + 'ᾙ' => 'ᾙ', + 'ᾚ' => 'ᾚ', + 'ᾛ' => 'ᾛ', + 'ᾜ' => 'ᾜ', + 'ᾝ' => 'ᾝ', + 'ᾞ' => 'ᾞ', + 'ᾟ' => 'ᾟ', + 'ᾠ' => 'ᾠ', + 'ᾡ' => 'ᾡ', + 'ᾢ' => 'ᾢ', + 'ᾣ' => 'ᾣ', + 'ᾤ' => 'ᾤ', + 'ᾥ' => 'ᾥ', + 'ᾦ' => 'ᾦ', + 'ᾧ' => 'ᾧ', + 'ᾨ' => 'ᾨ', + 'ᾩ' => 'ᾩ', + 'ᾪ' => 'ᾪ', + 'ᾫ' => 'ᾫ', + 'ᾬ' => 'ᾬ', + 'ᾭ' => 'ᾭ', + 'ᾮ' => 'ᾮ', + 'ᾯ' => 'ᾯ', + 'ᾰ' => 'ᾰ', + 'ᾱ' => 'ᾱ', + 'ᾲ' => 'ᾲ', + 'ᾳ' => 'ᾳ', + 'ᾴ' => 'ᾴ', + 'ᾶ' => 'ᾶ', + 'ᾷ' => 'ᾷ', + 'Ᾰ' => 'Ᾰ', + 'Ᾱ' => 'Ᾱ', + 'Ὰ' => 'Ὰ', + 'Ά' => 'Ά', + 'ᾼ' => 'ᾼ', + 'ι' => 'ι', + '῁' => '῁', + 'ῂ' => 'ῂ', + 'ῃ' => 'ῃ', + 'ῄ' => 'ῄ', + 'ῆ' => 'ῆ', + 'ῇ' => 'ῇ', + 'Ὲ' => 'Ὲ', + 'Έ' => 'Έ', + 'Ὴ' => 'Ὴ', + 'Ή' => 'Ή', + 'ῌ' => 'ῌ', + '῍' => '῍', + '῎' => '῎', + '῏' => '῏', + 'ῐ' => 'ῐ', + 'ῑ' => 'ῑ', + 'ῒ' => 'ῒ', + 'ΐ' => 'ΐ', + 'ῖ' => 'ῖ', + 'ῗ' => 'ῗ', + 'Ῐ' => 'Ῐ', + 'Ῑ' => 'Ῑ', + 'Ὶ' => 'Ὶ', + 'Ί' => 'Ί', + '῝' => '῝', + '῞' => '῞', + '῟' => '῟', + 'ῠ' => 'ῠ', + 'ῡ' => 'ῡ', + 'ῢ' => 'ῢ', + 'ΰ' => 'ΰ', + 'ῤ' => 'ῤ', + 'ῥ' => 'ῥ', + 'ῦ' => 'ῦ', + 'ῧ' => 'ῧ', + 'Ῠ' => 'Ῠ', + 'Ῡ' => 'Ῡ', + 'Ὺ' => 'Ὺ', + 'Ύ' => 'Ύ', + 'Ῥ' => 'Ῥ', + '῭' => '῭', + '΅' => '΅', + '`' => '`', + 'ῲ' => 'ῲ', + 'ῳ' => 'ῳ', + 'ῴ' => 'ῴ', + 'ῶ' => 'ῶ', + 'ῷ' => 'ῷ', + 'Ὸ' => 'Ὸ', + 'Ό' => 'Ό', + 'Ὼ' => 'Ὼ', + 'Ώ' => 'Ώ', + 'ῼ' => 'ῼ', + '´' => '´', + ' ' => ' ', + ' ' => ' ', + 'Ω' => 'Ω', + 'K' => 'K', + 'Å' => 'Å', + '↚' => '↚', + '↛' => '↛', + '↮' => '↮', + '⇍' => '⇍', + '⇎' => '⇎', + '⇏' => '⇏', + '∄' => '∄', + '∉' => '∉', + '∌' => '∌', + '∤' => '∤', + '∦' => '∦', + '≁' => '≁', + '≄' => '≄', + '≇' => '≇', + '≉' => '≉', + '≠' => '≠', + '≢' => '≢', + '≭' => '≭', + '≮' => '≮', + '≯' => '≯', + '≰' => '≰', + '≱' => '≱', + '≴' => '≴', + '≵' => '≵', + '≸' => '≸', + '≹' => '≹', + '⊀' => '⊀', + '⊁' => '⊁', + '⊄' => '⊄', + '⊅' => '⊅', + '⊈' => '⊈', + '⊉' => '⊉', + '⊬' => '⊬', + '⊭' => '⊭', + '⊮' => '⊮', + '⊯' => '⊯', + '⋠' => '⋠', + '⋡' => '⋡', + '⋢' => '⋢', + '⋣' => '⋣', + '⋪' => '⋪', + '⋫' => '⋫', + '⋬' => '⋬', + '⋭' => '⋭', + '〈' => '〈', + '〉' => '〉', + '⫝̸' => '⫝̸', + 'が' => 'が', + 'ぎ' => 'ぎ', + 'ぐ' => 'ぐ', + 'げ' => 'げ', + 'ご' => 'ご', + 'ざ' => 'ざ', + 'じ' => 'じ', + 'ず' => 'ず', + 'ぜ' => 'ぜ', + 'ぞ' => 'ぞ', + 'だ' => 'だ', + 'ぢ' => 'ぢ', + 'づ' => 'づ', + 'で' => 'で', + 'ど' => 'ど', + 'ば' => 'ば', + 'ぱ' => 'ぱ', + 'び' => 'び', + 'ぴ' => 'ぴ', + 'ぶ' => 'ぶ', + 'ぷ' => 'ぷ', + 'べ' => 'べ', + 'ぺ' => 'ぺ', + 'ぼ' => 'ぼ', + 'ぽ' => 'ぽ', + 'ゔ' => 'ゔ', + 'ゞ' => 'ゞ', + 'ガ' => 'ガ', + 'ギ' => 'ギ', + 'グ' => 'グ', + 'ゲ' => 'ゲ', + 'ゴ' => 'ゴ', + 'ザ' => 'ザ', + 'ジ' => 'ジ', + 'ズ' => 'ズ', + 'ゼ' => 'ゼ', + 'ゾ' => 'ゾ', + 'ダ' => 'ダ', + 'ヂ' => 'ヂ', + 'ヅ' => 'ヅ', + 'デ' => 'デ', + 'ド' => 'ド', + 'バ' => 'バ', + 'パ' => 'パ', + 'ビ' => 'ビ', + 'ピ' => 'ピ', + 'ブ' => 'ブ', + 'プ' => 'プ', + 'ベ' => 'ベ', + 'ペ' => 'ペ', + 'ボ' => 'ボ', + 'ポ' => 'ポ', + 'ヴ' => 'ヴ', + 'ヷ' => 'ヷ', + 'ヸ' => 'ヸ', + 'ヹ' => 'ヹ', + 'ヺ' => 'ヺ', + 'ヾ' => 'ヾ', + '豈' => '豈', + '更' => '更', + '車' => '車', + '賈' => '賈', + '滑' => '滑', + '串' => '串', + '句' => '句', + '龜' => '龜', + '龜' => '龜', + '契' => '契', + '金' => '金', + '喇' => '喇', + '奈' => '奈', + '懶' => '懶', + '癩' => '癩', + '羅' => '羅', + '蘿' => '蘿', + '螺' => '螺', + '裸' => '裸', + '邏' => '邏', + '樂' => '樂', + '洛' => '洛', + '烙' => '烙', + '珞' => '珞', + '落' => '落', + '酪' => '酪', + '駱' => '駱', + '亂' => '亂', + '卵' => '卵', + '欄' => '欄', + '爛' => '爛', + '蘭' => '蘭', + '鸞' => '鸞', + '嵐' => '嵐', + '濫' => '濫', + '藍' => '藍', + '襤' => '襤', + '拉' => '拉', + '臘' => '臘', + '蠟' => '蠟', + '廊' => '廊', + '朗' => '朗', + '浪' => '浪', + '狼' => '狼', + '郎' => '郎', + '來' => '來', + '冷' => '冷', + '勞' => '勞', + '擄' => '擄', + '櫓' => '櫓', + '爐' => '爐', + '盧' => '盧', + '老' => '老', + '蘆' => '蘆', + '虜' => '虜', + '路' => '路', + '露' => '露', + '魯' => '魯', + '鷺' => '鷺', + '碌' => '碌', + '祿' => '祿', + '綠' => '綠', + '菉' => '菉', + '錄' => '錄', + '鹿' => '鹿', + '論' => '論', + '壟' => '壟', + '弄' => '弄', + '籠' => '籠', + '聾' => '聾', + '牢' => '牢', + '磊' => '磊', + '賂' => '賂', + '雷' => '雷', + '壘' => '壘', + '屢' => '屢', + '樓' => '樓', + '淚' => '淚', + '漏' => '漏', + '累' => '累', + '縷' => '縷', + '陋' => '陋', + '勒' => '勒', + '肋' => '肋', + '凜' => '凜', + '凌' => '凌', + '稜' => '稜', + '綾' => '綾', + '菱' => '菱', + '陵' => '陵', + '讀' => '讀', + '拏' => '拏', + '樂' => '樂', + '諾' => '諾', + '丹' => '丹', + '寧' => '寧', + '怒' => '怒', + '率' => '率', + '異' => '異', + '北' => '北', + '磻' => '磻', + '便' => '便', + '復' => '復', + '不' => '不', + '泌' => '泌', + '數' => '數', + '索' => '索', + '參' => '參', + '塞' => '塞', + '省' => '省', + '葉' => '葉', + '說' => '說', + '殺' => '殺', + '辰' => '辰', + '沈' => '沈', + '拾' => '拾', + '若' => '若', + '掠' => '掠', + '略' => '略', + '亮' => '亮', + '兩' => '兩', + '凉' => '凉', + '梁' => '梁', + '糧' => '糧', + '良' => '良', + '諒' => '諒', + '量' => '量', + '勵' => '勵', + '呂' => '呂', + '女' => '女', + '廬' => '廬', + '旅' => '旅', + '濾' => '濾', + '礪' => '礪', + '閭' => '閭', + '驪' => '驪', + '麗' => '麗', + '黎' => '黎', + '力' => '力', + '曆' => '曆', + '歷' => '歷', + '轢' => '轢', + '年' => '年', + '憐' => '憐', + '戀' => '戀', + '撚' => '撚', + '漣' => '漣', + '煉' => '煉', + '璉' => '璉', + '秊' => '秊', + '練' => '練', + '聯' => '聯', + '輦' => '輦', + '蓮' => '蓮', + '連' => '連', + '鍊' => '鍊', + '列' => '列', + '劣' => '劣', + '咽' => '咽', + '烈' => '烈', + '裂' => '裂', + '說' => '說', + '廉' => '廉', + '念' => '念', + '捻' => '捻', + '殮' => '殮', + '簾' => '簾', + '獵' => '獵', + '令' => '令', + '囹' => '囹', + '寧' => '寧', + '嶺' => '嶺', + '怜' => '怜', + '玲' => '玲', + '瑩' => '瑩', + '羚' => '羚', + '聆' => '聆', + '鈴' => '鈴', + '零' => '零', + '靈' => '靈', + '領' => '領', + '例' => '例', + '禮' => '禮', + '醴' => '醴', + '隸' => '隸', + '惡' => '惡', + '了' => '了', + '僚' => '僚', + '寮' => '寮', + '尿' => '尿', + '料' => '料', + '樂' => '樂', + '燎' => '燎', + '療' => '療', + '蓼' => '蓼', + '遼' => '遼', + '龍' => '龍', + '暈' => '暈', + '阮' => '阮', + '劉' => '劉', + '杻' => '杻', + '柳' => '柳', + '流' => '流', + '溜' => '溜', + '琉' => '琉', + '留' => '留', + '硫' => '硫', + '紐' => '紐', + '類' => '類', + '六' => '六', + '戮' => '戮', + '陸' => '陸', + '倫' => '倫', + '崙' => '崙', + '淪' => '淪', + '輪' => '輪', + '律' => '律', + '慄' => '慄', + '栗' => '栗', + '率' => '率', + '隆' => '隆', + '利' => '利', + '吏' => '吏', + '履' => '履', + '易' => '易', + '李' => '李', + '梨' => '梨', + '泥' => '泥', + '理' => '理', + '痢' => '痢', + '罹' => '罹', + '裏' => '裏', + '裡' => '裡', + '里' => '里', + '離' => '離', + '匿' => '匿', + '溺' => '溺', + '吝' => '吝', + '燐' => '燐', + '璘' => '璘', + '藺' => '藺', + '隣' => '隣', + '鱗' => '鱗', + '麟' => '麟', + '林' => '林', + '淋' => '淋', + '臨' => '臨', + '立' => '立', + '笠' => '笠', + '粒' => '粒', + '狀' => '狀', + '炙' => '炙', + '識' => '識', + '什' => '什', + '茶' => '茶', + '刺' => '刺', + '切' => '切', + '度' => '度', + '拓' => '拓', + '糖' => '糖', + '宅' => '宅', + '洞' => '洞', + '暴' => '暴', + '輻' => '輻', + '行' => '行', + '降' => '降', + '見' => '見', + '廓' => '廓', + '兀' => '兀', + '嗀' => '嗀', + '塚' => '塚', + '晴' => '晴', + '凞' => '凞', + '猪' => '猪', + '益' => '益', + '礼' => '礼', + '神' => '神', + '祥' => '祥', + '福' => '福', + '靖' => '靖', + '精' => '精', + '羽' => '羽', + '蘒' => '蘒', + '諸' => '諸', + '逸' => '逸', + '都' => '都', + '飯' => '飯', + '飼' => '飼', + '館' => '館', + '鶴' => '鶴', + '郞' => '郞', + '隷' => '隷', + '侮' => '侮', + '僧' => '僧', + '免' => '免', + '勉' => '勉', + '勤' => '勤', + '卑' => '卑', + '喝' => '喝', + '嘆' => '嘆', + '器' => '器', + '塀' => '塀', + '墨' => '墨', + '層' => '層', + '屮' => '屮', + '悔' => '悔', + '慨' => '慨', + '憎' => '憎', + '懲' => '懲', + '敏' => '敏', + '既' => '既', + '暑' => '暑', + '梅' => '梅', + '海' => '海', + '渚' => '渚', + '漢' => '漢', + '煮' => '煮', + '爫' => '爫', + '琢' => '琢', + '碑' => '碑', + '社' => '社', + '祉' => '祉', + '祈' => '祈', + '祐' => '祐', + '祖' => '祖', + '祝' => '祝', + '禍' => '禍', + '禎' => '禎', + '穀' => '穀', + '突' => '突', + '節' => '節', + '練' => '練', + '縉' => '縉', + '繁' => '繁', + '署' => '署', + '者' => '者', + '臭' => '臭', + '艹' => '艹', + '艹' => '艹', + '著' => '著', + '褐' => '褐', + '視' => '視', + '謁' => '謁', + '謹' => '謹', + '賓' => '賓', + '贈' => '贈', + '辶' => '辶', + '逸' => '逸', + '難' => '難', + '響' => '響', + '頻' => '頻', + '恵' => '恵', + '𤋮' => '𤋮', + '舘' => '舘', + '並' => '並', + '况' => '况', + '全' => '全', + '侀' => '侀', + '充' => '充', + '冀' => '冀', + '勇' => '勇', + '勺' => '勺', + '喝' => '喝', + '啕' => '啕', + '喙' => '喙', + '嗢' => '嗢', + '塚' => '塚', + '墳' => '墳', + '奄' => '奄', + '奔' => '奔', + '婢' => '婢', + '嬨' => '嬨', + '廒' => '廒', + '廙' => '廙', + '彩' => '彩', + '徭' => '徭', + '惘' => '惘', + '慎' => '慎', + '愈' => '愈', + '憎' => '憎', + '慠' => '慠', + '懲' => '懲', + '戴' => '戴', + '揄' => '揄', + '搜' => '搜', + '摒' => '摒', + '敖' => '敖', + '晴' => '晴', + '朗' => '朗', + '望' => '望', + '杖' => '杖', + '歹' => '歹', + '殺' => '殺', + '流' => '流', + '滛' => '滛', + '滋' => '滋', + '漢' => '漢', + '瀞' => '瀞', + '煮' => '煮', + '瞧' => '瞧', + '爵' => '爵', + '犯' => '犯', + '猪' => '猪', + '瑱' => '瑱', + '甆' => '甆', + '画' => '画', + '瘝' => '瘝', + '瘟' => '瘟', + '益' => '益', + '盛' => '盛', + '直' => '直', + '睊' => '睊', + '着' => '着', + '磌' => '磌', + '窱' => '窱', + '節' => '節', + '类' => '类', + '絛' => '絛', + '練' => '練', + '缾' => '缾', + '者' => '者', + '荒' => '荒', + '華' => '華', + '蝹' => '蝹', + '襁' => '襁', + '覆' => '覆', + '視' => '視', + '調' => '調', + '諸' => '諸', + '請' => '請', + '謁' => '謁', + '諾' => '諾', + '諭' => '諭', + '謹' => '謹', + '變' => '變', + '贈' => '贈', + '輸' => '輸', + '遲' => '遲', + '醙' => '醙', + '鉶' => '鉶', + '陼' => '陼', + '難' => '難', + '靖' => '靖', + '韛' => '韛', + '響' => '響', + '頋' => '頋', + '頻' => '頻', + '鬒' => '鬒', + '龜' => '龜', + '𢡊' => '𢡊', + '𢡄' => '𢡄', + '𣏕' => '𣏕', + '㮝' => '㮝', + '䀘' => '䀘', + '䀹' => '䀹', + '𥉉' => '𥉉', + '𥳐' => '𥳐', + '𧻓' => '𧻓', + '齃' => '齃', + '龎' => '龎', + 'יִ' => 'יִ', + 'ײַ' => 'ײַ', + 'שׁ' => 'שׁ', + 'שׂ' => 'שׂ', + 'שּׁ' => 'שּׁ', + 'שּׂ' => 'שּׂ', + 'אַ' => 'אַ', + 'אָ' => 'אָ', + 'אּ' => 'אּ', + 'בּ' => 'בּ', + 'גּ' => 'גּ', + 'דּ' => 'דּ', + 'הּ' => 'הּ', + 'וּ' => 'וּ', + 'זּ' => 'זּ', + 'טּ' => 'טּ', + 'יּ' => 'יּ', + 'ךּ' => 'ךּ', + 'כּ' => 'כּ', + 'לּ' => 'לּ', + 'מּ' => 'מּ', + 'נּ' => 'נּ', + 'סּ' => 'סּ', + 'ףּ' => 'ףּ', + 'פּ' => 'פּ', + 'צּ' => 'צּ', + 'קּ' => 'קּ', + 'רּ' => 'רּ', + 'שּ' => 'שּ', + 'תּ' => 'תּ', + 'וֹ' => 'וֹ', + 'בֿ' => 'בֿ', + 'כֿ' => 'כֿ', + 'פֿ' => 'פֿ', + '𑂚' => '𑂚', + '𑂜' => '𑂜', + '𑂫' => '𑂫', + '𑄮' => '𑄮', + '𑄯' => '𑄯', + '𑍋' => '𑍋', + '𑍌' => '𑍌', + '𑒻' => '𑒻', + '𑒼' => '𑒼', + '𑒾' => '𑒾', + '𑖺' => '𑖺', + '𑖻' => '𑖻', + '𑤸' => '𑤸', + '𝅗𝅥' => '𝅗𝅥', + '𝅘𝅥' => '𝅘𝅥', + '𝅘𝅥𝅮' => '𝅘𝅥𝅮', + '𝅘𝅥𝅯' => '𝅘𝅥𝅯', + '𝅘𝅥𝅰' => '𝅘𝅥𝅰', + '𝅘𝅥𝅱' => '𝅘𝅥𝅱', + '𝅘𝅥𝅲' => '𝅘𝅥𝅲', + '𝆹𝅥' => '𝆹𝅥', + '𝆺𝅥' => '𝆺𝅥', + '𝆹𝅥𝅮' => '𝆹𝅥𝅮', + '𝆺𝅥𝅮' => '𝆺𝅥𝅮', + '𝆹𝅥𝅯' => '𝆹𝅥𝅯', + '𝆺𝅥𝅯' => '𝆺𝅥𝅯', + '丽' => '丽', + '丸' => '丸', + '乁' => '乁', + '𠄢' => '𠄢', + '你' => '你', + '侮' => '侮', + '侻' => '侻', + '倂' => '倂', + '偺' => '偺', + '備' => '備', + '僧' => '僧', + '像' => '像', + '㒞' => '㒞', + '𠘺' => '𠘺', + '免' => '免', + '兔' => '兔', + '兤' => '兤', + '具' => '具', + '𠔜' => '𠔜', + '㒹' => '㒹', + '內' => '內', + '再' => '再', + '𠕋' => '𠕋', + '冗' => '冗', + '冤' => '冤', + '仌' => '仌', + '冬' => '冬', + '况' => '况', + '𩇟' => '𩇟', + '凵' => '凵', + '刃' => '刃', + '㓟' => '㓟', + '刻' => '刻', + '剆' => '剆', + '割' => '割', + '剷' => '剷', + '㔕' => '㔕', + '勇' => '勇', + '勉' => '勉', + '勤' => '勤', + '勺' => '勺', + '包' => '包', + '匆' => '匆', + '北' => '北', + '卉' => '卉', + '卑' => '卑', + '博' => '博', + '即' => '即', + '卽' => '卽', + '卿' => '卿', + '卿' => '卿', + '卿' => '卿', + '𠨬' => '𠨬', + '灰' => '灰', + '及' => '及', + '叟' => '叟', + '𠭣' => '𠭣', + '叫' => '叫', + '叱' => '叱', + '吆' => '吆', + '咞' => '咞', + '吸' => '吸', + '呈' => '呈', + '周' => '周', + '咢' => '咢', + '哶' => '哶', + '唐' => '唐', + '啓' => '啓', + '啣' => '啣', + '善' => '善', + '善' => '善', + '喙' => '喙', + '喫' => '喫', + '喳' => '喳', + '嗂' => '嗂', + '圖' => '圖', + '嘆' => '嘆', + '圗' => '圗', + '噑' => '噑', + '噴' => '噴', + '切' => '切', + '壮' => '壮', + '城' => '城', + '埴' => '埴', + '堍' => '堍', + '型' => '型', + '堲' => '堲', + '報' => '報', + '墬' => '墬', + '𡓤' => '𡓤', + '売' => '売', + '壷' => '壷', + '夆' => '夆', + '多' => '多', + '夢' => '夢', + '奢' => '奢', + '𡚨' => '𡚨', + '𡛪' => '𡛪', + '姬' => '姬', + '娛' => '娛', + '娧' => '娧', + '姘' => '姘', + '婦' => '婦', + '㛮' => '㛮', + '㛼' => '㛼', + '嬈' => '嬈', + '嬾' => '嬾', + '嬾' => '嬾', + '𡧈' => '𡧈', + '寃' => '寃', + '寘' => '寘', + '寧' => '寧', + '寳' => '寳', + '𡬘' => '𡬘', + '寿' => '寿', + '将' => '将', + '当' => '当', + '尢' => '尢', + '㞁' => '㞁', + '屠' => '屠', + '屮' => '屮', + '峀' => '峀', + '岍' => '岍', + '𡷤' => '𡷤', + '嵃' => '嵃', + '𡷦' => '𡷦', + '嵮' => '嵮', + '嵫' => '嵫', + '嵼' => '嵼', + '巡' => '巡', + '巢' => '巢', + '㠯' => '㠯', + '巽' => '巽', + '帨' => '帨', + '帽' => '帽', + '幩' => '幩', + '㡢' => '㡢', + '𢆃' => '𢆃', + '㡼' => '㡼', + '庰' => '庰', + '庳' => '庳', + '庶' => '庶', + '廊' => '廊', + '𪎒' => '𪎒', + '廾' => '廾', + '𢌱' => '𢌱', + '𢌱' => '𢌱', + '舁' => '舁', + '弢' => '弢', + '弢' => '弢', + '㣇' => '㣇', + '𣊸' => '𣊸', + '𦇚' => '𦇚', + '形' => '形', + '彫' => '彫', + '㣣' => '㣣', + '徚' => '徚', + '忍' => '忍', + '志' => '志', + '忹' => '忹', + '悁' => '悁', + '㤺' => '㤺', + '㤜' => '㤜', + '悔' => '悔', + '𢛔' => '𢛔', + '惇' => '惇', + '慈' => '慈', + '慌' => '慌', + '慎' => '慎', + '慌' => '慌', + '慺' => '慺', + '憎' => '憎', + '憲' => '憲', + '憤' => '憤', + '憯' => '憯', + '懞' => '懞', + '懲' => '懲', + '懶' => '懶', + '成' => '成', + '戛' => '戛', + '扝' => '扝', + '抱' => '抱', + '拔' => '拔', + '捐' => '捐', + '𢬌' => '𢬌', + '挽' => '挽', + '拼' => '拼', + '捨' => '捨', + '掃' => '掃', + '揤' => '揤', + '𢯱' => '𢯱', + '搢' => '搢', + '揅' => '揅', + '掩' => '掩', + '㨮' => '㨮', + '摩' => '摩', + '摾' => '摾', + '撝' => '撝', + '摷' => '摷', + '㩬' => '㩬', + '敏' => '敏', + '敬' => '敬', + '𣀊' => '𣀊', + '旣' => '旣', + '書' => '書', + '晉' => '晉', + '㬙' => '㬙', + '暑' => '暑', + '㬈' => '㬈', + '㫤' => '㫤', + '冒' => '冒', + '冕' => '冕', + '最' => '最', + '暜' => '暜', + '肭' => '肭', + '䏙' => '䏙', + '朗' => '朗', + '望' => '望', + '朡' => '朡', + '杞' => '杞', + '杓' => '杓', + '𣏃' => '𣏃', + '㭉' => '㭉', + '柺' => '柺', + '枅' => '枅', + '桒' => '桒', + '梅' => '梅', + '𣑭' => '𣑭', + '梎' => '梎', + '栟' => '栟', + '椔' => '椔', + '㮝' => '㮝', + '楂' => '楂', + '榣' => '榣', + '槪' => '槪', + '檨' => '檨', + '𣚣' => '𣚣', + '櫛' => '櫛', + '㰘' => '㰘', + '次' => '次', + '𣢧' => '𣢧', + '歔' => '歔', + '㱎' => '㱎', + '歲' => '歲', + '殟' => '殟', + '殺' => '殺', + '殻' => '殻', + '𣪍' => '𣪍', + '𡴋' => '𡴋', + '𣫺' => '𣫺', + '汎' => '汎', + '𣲼' => '𣲼', + '沿' => '沿', + '泍' => '泍', + '汧' => '汧', + '洖' => '洖', + '派' => '派', + '海' => '海', + '流' => '流', + '浩' => '浩', + '浸' => '浸', + '涅' => '涅', + '𣴞' => '𣴞', + '洴' => '洴', + '港' => '港', + '湮' => '湮', + '㴳' => '㴳', + '滋' => '滋', + '滇' => '滇', + '𣻑' => '𣻑', + '淹' => '淹', + '潮' => '潮', + '𣽞' => '𣽞', + '𣾎' => '𣾎', + '濆' => '濆', + '瀹' => '瀹', + '瀞' => '瀞', + '瀛' => '瀛', + '㶖' => '㶖', + '灊' => '灊', + '災' => '災', + '灷' => '灷', + '炭' => '炭', + '𠔥' => '𠔥', + '煅' => '煅', + '𤉣' => '𤉣', + '熜' => '熜', + '𤎫' => '𤎫', + '爨' => '爨', + '爵' => '爵', + '牐' => '牐', + '𤘈' => '𤘈', + '犀' => '犀', + '犕' => '犕', + '𤜵' => '𤜵', + '𤠔' => '𤠔', + '獺' => '獺', + '王' => '王', + '㺬' => '㺬', + '玥' => '玥', + '㺸' => '㺸', + '㺸' => '㺸', + '瑇' => '瑇', + '瑜' => '瑜', + '瑱' => '瑱', + '璅' => '璅', + '瓊' => '瓊', + '㼛' => '㼛', + '甤' => '甤', + '𤰶' => '𤰶', + '甾' => '甾', + '𤲒' => '𤲒', + '異' => '異', + '𢆟' => '𢆟', + '瘐' => '瘐', + '𤾡' => '𤾡', + '𤾸' => '𤾸', + '𥁄' => '𥁄', + '㿼' => '㿼', + '䀈' => '䀈', + '直' => '直', + '𥃳' => '𥃳', + '𥃲' => '𥃲', + '𥄙' => '𥄙', + '𥄳' => '𥄳', + '眞' => '眞', + '真' => '真', + '真' => '真', + '睊' => '睊', + '䀹' => '䀹', + '瞋' => '瞋', + '䁆' => '䁆', + '䂖' => '䂖', + '𥐝' => '𥐝', + '硎' => '硎', + '碌' => '碌', + '磌' => '磌', + '䃣' => '䃣', + '𥘦' => '𥘦', + '祖' => '祖', + '𥚚' => '𥚚', + '𥛅' => '𥛅', + '福' => '福', + '秫' => '秫', + '䄯' => '䄯', + '穀' => '穀', + '穊' => '穊', + '穏' => '穏', + '𥥼' => '𥥼', + '𥪧' => '𥪧', + '𥪧' => '𥪧', + '竮' => '竮', + '䈂' => '䈂', + '𥮫' => '𥮫', + '篆' => '篆', + '築' => '築', + '䈧' => '䈧', + '𥲀' => '𥲀', + '糒' => '糒', + '䊠' => '䊠', + '糨' => '糨', + '糣' => '糣', + '紀' => '紀', + '𥾆' => '𥾆', + '絣' => '絣', + '䌁' => '䌁', + '緇' => '緇', + '縂' => '縂', + '繅' => '繅', + '䌴' => '䌴', + '𦈨' => '𦈨', + '𦉇' => '𦉇', + '䍙' => '䍙', + '𦋙' => '𦋙', + '罺' => '罺', + '𦌾' => '𦌾', + '羕' => '羕', + '翺' => '翺', + '者' => '者', + '𦓚' => '𦓚', + '𦔣' => '𦔣', + '聠' => '聠', + '𦖨' => '𦖨', + '聰' => '聰', + '𣍟' => '𣍟', + '䏕' => '䏕', + '育' => '育', + '脃' => '脃', + '䐋' => '䐋', + '脾' => '脾', + '媵' => '媵', + '𦞧' => '𦞧', + '𦞵' => '𦞵', + '𣎓' => '𣎓', + '𣎜' => '𣎜', + '舁' => '舁', + '舄' => '舄', + '辞' => '辞', + '䑫' => '䑫', + '芑' => '芑', + '芋' => '芋', + '芝' => '芝', + '劳' => '劳', + '花' => '花', + '芳' => '芳', + '芽' => '芽', + '苦' => '苦', + '𦬼' => '𦬼', + '若' => '若', + '茝' => '茝', + '荣' => '荣', + '莭' => '莭', + '茣' => '茣', + '莽' => '莽', + '菧' => '菧', + '著' => '著', + '荓' => '荓', + '菊' => '菊', + '菌' => '菌', + '菜' => '菜', + '𦰶' => '𦰶', + '𦵫' => '𦵫', + '𦳕' => '𦳕', + '䔫' => '䔫', + '蓱' => '蓱', + '蓳' => '蓳', + '蔖' => '蔖', + '𧏊' => '𧏊', + '蕤' => '蕤', + '𦼬' => '𦼬', + '䕝' => '䕝', + '䕡' => '䕡', + '𦾱' => '𦾱', + '𧃒' => '𧃒', + '䕫' => '䕫', + '虐' => '虐', + '虜' => '虜', + '虧' => '虧', + '虩' => '虩', + '蚩' => '蚩', + '蚈' => '蚈', + '蜎' => '蜎', + '蛢' => '蛢', + '蝹' => '蝹', + '蜨' => '蜨', + '蝫' => '蝫', + '螆' => '螆', + '䗗' => '䗗', + '蟡' => '蟡', + '蠁' => '蠁', + '䗹' => '䗹', + '衠' => '衠', + '衣' => '衣', + '𧙧' => '𧙧', + '裗' => '裗', + '裞' => '裞', + '䘵' => '䘵', + '裺' => '裺', + '㒻' => '㒻', + '𧢮' => '𧢮', + '𧥦' => '𧥦', + '䚾' => '䚾', + '䛇' => '䛇', + '誠' => '誠', + '諭' => '諭', + '變' => '變', + '豕' => '豕', + '𧲨' => '𧲨', + '貫' => '貫', + '賁' => '賁', + '贛' => '贛', + '起' => '起', + '𧼯' => '𧼯', + '𠠄' => '𠠄', + '跋' => '跋', + '趼' => '趼', + '跰' => '跰', + '𠣞' => '𠣞', + '軔' => '軔', + '輸' => '輸', + '𨗒' => '𨗒', + '𨗭' => '𨗭', + '邔' => '邔', + '郱' => '郱', + '鄑' => '鄑', + '𨜮' => '𨜮', + '鄛' => '鄛', + '鈸' => '鈸', + '鋗' => '鋗', + '鋘' => '鋘', + '鉼' => '鉼', + '鏹' => '鏹', + '鐕' => '鐕', + '𨯺' => '𨯺', + '開' => '開', + '䦕' => '䦕', + '閷' => '閷', + '𨵷' => '𨵷', + '䧦' => '䧦', + '雃' => '雃', + '嶲' => '嶲', + '霣' => '霣', + '𩅅' => '𩅅', + '𩈚' => '𩈚', + '䩮' => '䩮', + '䩶' => '䩶', + '韠' => '韠', + '𩐊' => '𩐊', + '䪲' => '䪲', + '𩒖' => '𩒖', + '頋' => '頋', + '頋' => '頋', + '頩' => '頩', + '𩖶' => '𩖶', + '飢' => '飢', + '䬳' => '䬳', + '餩' => '餩', + '馧' => '馧', + '駂' => '駂', + '駾' => '駾', + '䯎' => '䯎', + '𩬰' => '𩬰', + '鬒' => '鬒', + '鱀' => '鱀', + '鳽' => '鳽', + '䳎' => '䳎', + '䳭' => '䳭', + '鵧' => '鵧', + '𪃎' => '𪃎', + '䳸' => '䳸', + '𪄅' => '𪄅', + '𪈎' => '𪈎', + '𪊑' => '𪊑', + '麻' => '麻', + '䵖' => '䵖', + '黹' => '黹', + '黾' => '黾', + '鼅' => '鼅', + '鼏' => '鼏', + '鼖' => '鼖', + '鼻' => '鼻', + '𪘀' => '𪘀', +); diff --git a/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php new file mode 100644 index 0000000..ec90f36 --- /dev/null +++ b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/combiningClass.php @@ -0,0 +1,876 @@ + 230, + '́' => 230, + '̂' => 230, + '̃' => 230, + '̄' => 230, + '̅' => 230, + '̆' => 230, + '̇' => 230, + '̈' => 230, + '̉' => 230, + '̊' => 230, + '̋' => 230, + '̌' => 230, + '̍' => 230, + '̎' => 230, + '̏' => 230, + '̐' => 230, + '̑' => 230, + '̒' => 230, + '̓' => 230, + '̔' => 230, + '̕' => 232, + '̖' => 220, + '̗' => 220, + '̘' => 220, + '̙' => 220, + '̚' => 232, + '̛' => 216, + '̜' => 220, + '̝' => 220, + '̞' => 220, + '̟' => 220, + '̠' => 220, + '̡' => 202, + '̢' => 202, + '̣' => 220, + '̤' => 220, + '̥' => 220, + '̦' => 220, + '̧' => 202, + '̨' => 202, + '̩' => 220, + '̪' => 220, + '̫' => 220, + '̬' => 220, + '̭' => 220, + '̮' => 220, + '̯' => 220, + '̰' => 220, + '̱' => 220, + '̲' => 220, + '̳' => 220, + '̴' => 1, + '̵' => 1, + '̶' => 1, + '̷' => 1, + '̸' => 1, + '̹' => 220, + '̺' => 220, + '̻' => 220, + '̼' => 220, + '̽' => 230, + '̾' => 230, + '̿' => 230, + '̀' => 230, + '́' => 230, + '͂' => 230, + '̓' => 230, + '̈́' => 230, + 'ͅ' => 240, + '͆' => 230, + '͇' => 220, + '͈' => 220, + '͉' => 220, + '͊' => 230, + '͋' => 230, + '͌' => 230, + '͍' => 220, + '͎' => 220, + '͐' => 230, + '͑' => 230, + '͒' => 230, + '͓' => 220, + '͔' => 220, + '͕' => 220, + '͖' => 220, + '͗' => 230, + '͘' => 232, + '͙' => 220, + '͚' => 220, + '͛' => 230, + '͜' => 233, + '͝' => 234, + '͞' => 234, + '͟' => 233, + '͠' => 234, + '͡' => 234, + '͢' => 233, + 'ͣ' => 230, + 'ͤ' => 230, + 'ͥ' => 230, + 'ͦ' => 230, + 'ͧ' => 230, + 'ͨ' => 230, + 'ͩ' => 230, + 'ͪ' => 230, + 'ͫ' => 230, + 'ͬ' => 230, + 'ͭ' => 230, + 'ͮ' => 230, + 'ͯ' => 230, + '҃' => 230, + '҄' => 230, + '҅' => 230, + '҆' => 230, + '҇' => 230, + '֑' => 220, + '֒' => 230, + '֓' => 230, + '֔' => 230, + '֕' => 230, + '֖' => 220, + '֗' => 230, + '֘' => 230, + '֙' => 230, + '֚' => 222, + '֛' => 220, + '֜' => 230, + '֝' => 230, + '֞' => 230, + '֟' => 230, + '֠' => 230, + '֡' => 230, + '֢' => 220, + '֣' => 220, + '֤' => 220, + '֥' => 220, + '֦' => 220, + '֧' => 220, + '֨' => 230, + '֩' => 230, + '֪' => 220, + '֫' => 230, + '֬' => 230, + '֭' => 222, + '֮' => 228, + '֯' => 230, + 'ְ' => 10, + 'ֱ' => 11, + 'ֲ' => 12, + 'ֳ' => 13, + 'ִ' => 14, + 'ֵ' => 15, + 'ֶ' => 16, + 'ַ' => 17, + 'ָ' => 18, + 'ֹ' => 19, + 'ֺ' => 19, + 'ֻ' => 20, + 'ּ' => 21, + 'ֽ' => 22, + 'ֿ' => 23, + 'ׁ' => 24, + 'ׂ' => 25, + 'ׄ' => 230, + 'ׅ' => 220, + 'ׇ' => 18, + 'ؐ' => 230, + 'ؑ' => 230, + 'ؒ' => 230, + 'ؓ' => 230, + 'ؔ' => 230, + 'ؕ' => 230, + 'ؖ' => 230, + 'ؗ' => 230, + 'ؘ' => 30, + 'ؙ' => 31, + 'ؚ' => 32, + 'ً' => 27, + 'ٌ' => 28, + 'ٍ' => 29, + 'َ' => 30, + 'ُ' => 31, + 'ِ' => 32, + 'ّ' => 33, + 'ْ' => 34, + 'ٓ' => 230, + 'ٔ' => 230, + 'ٕ' => 220, + 'ٖ' => 220, + 'ٗ' => 230, + '٘' => 230, + 'ٙ' => 230, + 'ٚ' => 230, + 'ٛ' => 230, + 'ٜ' => 220, + 'ٝ' => 230, + 'ٞ' => 230, + 'ٟ' => 220, + 'ٰ' => 35, + 'ۖ' => 230, + 'ۗ' => 230, + 'ۘ' => 230, + 'ۙ' => 230, + 'ۚ' => 230, + 'ۛ' => 230, + 'ۜ' => 230, + '۟' => 230, + '۠' => 230, + 'ۡ' => 230, + 'ۢ' => 230, + 'ۣ' => 220, + 'ۤ' => 230, + 'ۧ' => 230, + 'ۨ' => 230, + '۪' => 220, + '۫' => 230, + '۬' => 230, + 'ۭ' => 220, + 'ܑ' => 36, + 'ܰ' => 230, + 'ܱ' => 220, + 'ܲ' => 230, + 'ܳ' => 230, + 'ܴ' => 220, + 'ܵ' => 230, + 'ܶ' => 230, + 'ܷ' => 220, + 'ܸ' => 220, + 'ܹ' => 220, + 'ܺ' => 230, + 'ܻ' => 220, + 'ܼ' => 220, + 'ܽ' => 230, + 'ܾ' => 220, + 'ܿ' => 230, + '݀' => 230, + '݁' => 230, + '݂' => 220, + '݃' => 230, + '݄' => 220, + '݅' => 230, + '݆' => 220, + '݇' => 230, + '݈' => 220, + '݉' => 230, + '݊' => 230, + '߫' => 230, + '߬' => 230, + '߭' => 230, + '߮' => 230, + '߯' => 230, + '߰' => 230, + '߱' => 230, + '߲' => 220, + '߳' => 230, + '߽' => 220, + 'ࠖ' => 230, + 'ࠗ' => 230, + '࠘' => 230, + '࠙' => 230, + 'ࠛ' => 230, + 'ࠜ' => 230, + 'ࠝ' => 230, + 'ࠞ' => 230, + 'ࠟ' => 230, + 'ࠠ' => 230, + 'ࠡ' => 230, + 'ࠢ' => 230, + 'ࠣ' => 230, + 'ࠥ' => 230, + 'ࠦ' => 230, + 'ࠧ' => 230, + 'ࠩ' => 230, + 'ࠪ' => 230, + 'ࠫ' => 230, + 'ࠬ' => 230, + '࠭' => 230, + '࡙' => 220, + '࡚' => 220, + '࡛' => 220, + '࣓' => 220, + 'ࣔ' => 230, + 'ࣕ' => 230, + 'ࣖ' => 230, + 'ࣗ' => 230, + 'ࣘ' => 230, + 'ࣙ' => 230, + 'ࣚ' => 230, + 'ࣛ' => 230, + 'ࣜ' => 230, + 'ࣝ' => 230, + 'ࣞ' => 230, + 'ࣟ' => 230, + '࣠' => 230, + '࣡' => 230, + 'ࣣ' => 220, + 'ࣤ' => 230, + 'ࣥ' => 230, + 'ࣦ' => 220, + 'ࣧ' => 230, + 'ࣨ' => 230, + 'ࣩ' => 220, + '࣪' => 230, + '࣫' => 230, + '࣬' => 230, + '࣭' => 220, + '࣮' => 220, + '࣯' => 220, + 'ࣰ' => 27, + 'ࣱ' => 28, + 'ࣲ' => 29, + 'ࣳ' => 230, + 'ࣴ' => 230, + 'ࣵ' => 230, + 'ࣶ' => 220, + 'ࣷ' => 230, + 'ࣸ' => 230, + 'ࣹ' => 220, + 'ࣺ' => 220, + 'ࣻ' => 230, + 'ࣼ' => 230, + 'ࣽ' => 230, + 'ࣾ' => 230, + 'ࣿ' => 230, + '़' => 7, + '्' => 9, + '॑' => 230, + '॒' => 220, + '॓' => 230, + '॔' => 230, + '়' => 7, + '্' => 9, + '৾' => 230, + '਼' => 7, + '੍' => 9, + '઼' => 7, + '્' => 9, + '଼' => 7, + '୍' => 9, + '்' => 9, + '్' => 9, + 'ౕ' => 84, + 'ౖ' => 91, + '಼' => 7, + '್' => 9, + '഻' => 9, + '഼' => 9, + '്' => 9, + '්' => 9, + 'ุ' => 103, + 'ู' => 103, + 'ฺ' => 9, + '่' => 107, + '้' => 107, + '๊' => 107, + '๋' => 107, + 'ຸ' => 118, + 'ູ' => 118, + '຺' => 9, + '່' => 122, + '້' => 122, + '໊' => 122, + '໋' => 122, + '༘' => 220, + '༙' => 220, + '༵' => 220, + '༷' => 220, + '༹' => 216, + 'ཱ' => 129, + 'ི' => 130, + 'ུ' => 132, + 'ེ' => 130, + 'ཻ' => 130, + 'ོ' => 130, + 'ཽ' => 130, + 'ྀ' => 130, + 'ྂ' => 230, + 'ྃ' => 230, + '྄' => 9, + '྆' => 230, + '྇' => 230, + '࿆' => 220, + '့' => 7, + '္' => 9, + '်' => 9, + 'ႍ' => 220, + '፝' => 230, + '፞' => 230, + '፟' => 230, + '᜔' => 9, + '᜴' => 9, + '្' => 9, + '៝' => 230, + 'ᢩ' => 228, + '᤹' => 222, + '᤺' => 230, + '᤻' => 220, + 'ᨗ' => 230, + 'ᨘ' => 220, + '᩠' => 9, + '᩵' => 230, + '᩶' => 230, + '᩷' => 230, + '᩸' => 230, + '᩹' => 230, + '᩺' => 230, + '᩻' => 230, + '᩼' => 230, + '᩿' => 220, + '᪰' => 230, + '᪱' => 230, + '᪲' => 230, + '᪳' => 230, + '᪴' => 230, + '᪵' => 220, + '᪶' => 220, + '᪷' => 220, + '᪸' => 220, + '᪹' => 220, + '᪺' => 220, + '᪻' => 230, + '᪼' => 230, + '᪽' => 220, + 'ᪿ' => 220, + 'ᫀ' => 220, + '᬴' => 7, + '᭄' => 9, + '᭫' => 230, + '᭬' => 220, + '᭭' => 230, + '᭮' => 230, + '᭯' => 230, + '᭰' => 230, + '᭱' => 230, + '᭲' => 230, + '᭳' => 230, + '᮪' => 9, + '᮫' => 9, + '᯦' => 7, + '᯲' => 9, + '᯳' => 9, + '᰷' => 7, + '᳐' => 230, + '᳑' => 230, + '᳒' => 230, + '᳔' => 1, + '᳕' => 220, + '᳖' => 220, + '᳗' => 220, + '᳘' => 220, + '᳙' => 220, + '᳚' => 230, + '᳛' => 230, + '᳜' => 220, + '᳝' => 220, + '᳞' => 220, + '᳟' => 220, + '᳠' => 230, + '᳢' => 1, + '᳣' => 1, + '᳤' => 1, + '᳥' => 1, + '᳦' => 1, + '᳧' => 1, + '᳨' => 1, + '᳭' => 220, + '᳴' => 230, + '᳸' => 230, + '᳹' => 230, + '᷀' => 230, + '᷁' => 230, + '᷂' => 220, + '᷃' => 230, + '᷄' => 230, + '᷅' => 230, + '᷆' => 230, + '᷇' => 230, + '᷈' => 230, + '᷉' => 230, + '᷊' => 220, + '᷋' => 230, + '᷌' => 230, + '᷍' => 234, + '᷎' => 214, + '᷏' => 220, + '᷐' => 202, + '᷑' => 230, + '᷒' => 230, + 'ᷓ' => 230, + 'ᷔ' => 230, + 'ᷕ' => 230, + 'ᷖ' => 230, + 'ᷗ' => 230, + 'ᷘ' => 230, + 'ᷙ' => 230, + 'ᷚ' => 230, + 'ᷛ' => 230, + 'ᷜ' => 230, + 'ᷝ' => 230, + 'ᷞ' => 230, + 'ᷟ' => 230, + 'ᷠ' => 230, + 'ᷡ' => 230, + 'ᷢ' => 230, + 'ᷣ' => 230, + 'ᷤ' => 230, + 'ᷥ' => 230, + 'ᷦ' => 230, + 'ᷧ' => 230, + 'ᷨ' => 230, + 'ᷩ' => 230, + 'ᷪ' => 230, + 'ᷫ' => 230, + 'ᷬ' => 230, + 'ᷭ' => 230, + 'ᷮ' => 230, + 'ᷯ' => 230, + 'ᷰ' => 230, + 'ᷱ' => 230, + 'ᷲ' => 230, + 'ᷳ' => 230, + 'ᷴ' => 230, + '᷵' => 230, + '᷶' => 232, + '᷷' => 228, + '᷸' => 228, + '᷹' => 220, + '᷻' => 230, + '᷼' => 233, + '᷽' => 220, + '᷾' => 230, + '᷿' => 220, + '⃐' => 230, + '⃑' => 230, + '⃒' => 1, + '⃓' => 1, + '⃔' => 230, + '⃕' => 230, + '⃖' => 230, + '⃗' => 230, + '⃘' => 1, + '⃙' => 1, + '⃚' => 1, + '⃛' => 230, + '⃜' => 230, + '⃡' => 230, + '⃥' => 1, + '⃦' => 1, + '⃧' => 230, + '⃨' => 220, + '⃩' => 230, + '⃪' => 1, + '⃫' => 1, + '⃬' => 220, + '⃭' => 220, + '⃮' => 220, + '⃯' => 220, + '⃰' => 230, + '⳯' => 230, + '⳰' => 230, + '⳱' => 230, + '⵿' => 9, + 'ⷠ' => 230, + 'ⷡ' => 230, + 'ⷢ' => 230, + 'ⷣ' => 230, + 'ⷤ' => 230, + 'ⷥ' => 230, + 'ⷦ' => 230, + 'ⷧ' => 230, + 'ⷨ' => 230, + 'ⷩ' => 230, + 'ⷪ' => 230, + 'ⷫ' => 230, + 'ⷬ' => 230, + 'ⷭ' => 230, + 'ⷮ' => 230, + 'ⷯ' => 230, + 'ⷰ' => 230, + 'ⷱ' => 230, + 'ⷲ' => 230, + 'ⷳ' => 230, + 'ⷴ' => 230, + 'ⷵ' => 230, + 'ⷶ' => 230, + 'ⷷ' => 230, + 'ⷸ' => 230, + 'ⷹ' => 230, + 'ⷺ' => 230, + 'ⷻ' => 230, + 'ⷼ' => 230, + 'ⷽ' => 230, + 'ⷾ' => 230, + 'ⷿ' => 230, + '〪' => 218, + '〫' => 228, + '〬' => 232, + '〭' => 222, + '〮' => 224, + '〯' => 224, + '゙' => 8, + '゚' => 8, + '꙯' => 230, + 'ꙴ' => 230, + 'ꙵ' => 230, + 'ꙶ' => 230, + 'ꙷ' => 230, + 'ꙸ' => 230, + 'ꙹ' => 230, + 'ꙺ' => 230, + 'ꙻ' => 230, + '꙼' => 230, + '꙽' => 230, + 'ꚞ' => 230, + 'ꚟ' => 230, + '꛰' => 230, + '꛱' => 230, + '꠆' => 9, + '꠬' => 9, + '꣄' => 9, + '꣠' => 230, + '꣡' => 230, + '꣢' => 230, + '꣣' => 230, + '꣤' => 230, + '꣥' => 230, + '꣦' => 230, + '꣧' => 230, + '꣨' => 230, + '꣩' => 230, + '꣪' => 230, + '꣫' => 230, + '꣬' => 230, + '꣭' => 230, + '꣮' => 230, + '꣯' => 230, + '꣰' => 230, + '꣱' => 230, + '꤫' => 220, + '꤬' => 220, + '꤭' => 220, + '꥓' => 9, + '꦳' => 7, + '꧀' => 9, + 'ꪰ' => 230, + 'ꪲ' => 230, + 'ꪳ' => 230, + 'ꪴ' => 220, + 'ꪷ' => 230, + 'ꪸ' => 230, + 'ꪾ' => 230, + '꪿' => 230, + '꫁' => 230, + '꫶' => 9, + '꯭' => 9, + 'ﬞ' => 26, + '︠' => 230, + '︡' => 230, + '︢' => 230, + '︣' => 230, + '︤' => 230, + '︥' => 230, + '︦' => 230, + '︧' => 220, + '︨' => 220, + '︩' => 220, + '︪' => 220, + '︫' => 220, + '︬' => 220, + '︭' => 220, + '︮' => 230, + '︯' => 230, + '𐇽' => 220, + '𐋠' => 220, + '𐍶' => 230, + '𐍷' => 230, + '𐍸' => 230, + '𐍹' => 230, + '𐍺' => 230, + '𐨍' => 220, + '𐨏' => 230, + '𐨸' => 230, + '𐨹' => 1, + '𐨺' => 220, + '𐨿' => 9, + '𐫥' => 230, + '𐫦' => 220, + '𐴤' => 230, + '𐴥' => 230, + '𐴦' => 230, + '𐴧' => 230, + '𐺫' => 230, + '𐺬' => 230, + '𐽆' => 220, + '𐽇' => 220, + '𐽈' => 230, + '𐽉' => 230, + '𐽊' => 230, + '𐽋' => 220, + '𐽌' => 230, + '𐽍' => 220, + '𐽎' => 220, + '𐽏' => 220, + '𐽐' => 220, + '𑁆' => 9, + '𑁿' => 9, + '𑂹' => 9, + '𑂺' => 7, + '𑄀' => 230, + '𑄁' => 230, + '𑄂' => 230, + '𑄳' => 9, + '𑄴' => 9, + '𑅳' => 7, + '𑇀' => 9, + '𑇊' => 7, + '𑈵' => 9, + '𑈶' => 7, + '𑋩' => 7, + '𑋪' => 9, + '𑌻' => 7, + '𑌼' => 7, + '𑍍' => 9, + '𑍦' => 230, + '𑍧' => 230, + '𑍨' => 230, + '𑍩' => 230, + '𑍪' => 230, + '𑍫' => 230, + '𑍬' => 230, + '𑍰' => 230, + '𑍱' => 230, + '𑍲' => 230, + '𑍳' => 230, + '𑍴' => 230, + '𑑂' => 9, + '𑑆' => 7, + '𑑞' => 230, + '𑓂' => 9, + '𑓃' => 7, + '𑖿' => 9, + '𑗀' => 7, + '𑘿' => 9, + '𑚶' => 9, + '𑚷' => 7, + '𑜫' => 9, + '𑠹' => 9, + '𑠺' => 7, + '𑤽' => 9, + '𑤾' => 9, + '𑥃' => 7, + '𑧠' => 9, + '𑨴' => 9, + '𑩇' => 9, + '𑪙' => 9, + '𑰿' => 9, + '𑵂' => 7, + '𑵄' => 9, + '𑵅' => 9, + '𑶗' => 9, + '𖫰' => 1, + '𖫱' => 1, + '𖫲' => 1, + '𖫳' => 1, + '𖫴' => 1, + '𖬰' => 230, + '𖬱' => 230, + '𖬲' => 230, + '𖬳' => 230, + '𖬴' => 230, + '𖬵' => 230, + '𖬶' => 230, + '𖿰' => 6, + '𖿱' => 6, + '𛲞' => 1, + '𝅥' => 216, + '𝅦' => 216, + '𝅧' => 1, + '𝅨' => 1, + '𝅩' => 1, + '𝅭' => 226, + '𝅮' => 216, + '𝅯' => 216, + '𝅰' => 216, + '𝅱' => 216, + '𝅲' => 216, + '𝅻' => 220, + '𝅼' => 220, + '𝅽' => 220, + '𝅾' => 220, + '𝅿' => 220, + '𝆀' => 220, + '𝆁' => 220, + '𝆂' => 220, + '𝆅' => 230, + '𝆆' => 230, + '𝆇' => 230, + '𝆈' => 230, + '𝆉' => 230, + '𝆊' => 220, + '𝆋' => 220, + '𝆪' => 230, + '𝆫' => 230, + '𝆬' => 230, + '𝆭' => 230, + '𝉂' => 230, + '𝉃' => 230, + '𝉄' => 230, + '𞀀' => 230, + '𞀁' => 230, + '𞀂' => 230, + '𞀃' => 230, + '𞀄' => 230, + '𞀅' => 230, + '𞀆' => 230, + '𞀈' => 230, + '𞀉' => 230, + '𞀊' => 230, + '𞀋' => 230, + '𞀌' => 230, + '𞀍' => 230, + '𞀎' => 230, + '𞀏' => 230, + '𞀐' => 230, + '𞀑' => 230, + '𞀒' => 230, + '𞀓' => 230, + '𞀔' => 230, + '𞀕' => 230, + '𞀖' => 230, + '𞀗' => 230, + '𞀘' => 230, + '𞀛' => 230, + '𞀜' => 230, + '𞀝' => 230, + '𞀞' => 230, + '𞀟' => 230, + '𞀠' => 230, + '𞀡' => 230, + '𞀣' => 230, + '𞀤' => 230, + '𞀦' => 230, + '𞀧' => 230, + '𞀨' => 230, + '𞀩' => 230, + '𞀪' => 230, + '𞄰' => 230, + '𞄱' => 230, + '𞄲' => 230, + '𞄳' => 230, + '𞄴' => 230, + '𞄵' => 230, + '𞄶' => 230, + '𞋬' => 230, + '𞋭' => 230, + '𞋮' => 230, + '𞋯' => 230, + '𞣐' => 220, + '𞣑' => 220, + '𞣒' => 220, + '𞣓' => 220, + '𞣔' => 220, + '𞣕' => 220, + '𞣖' => 220, + '𞥄' => 230, + '𞥅' => 230, + '𞥆' => 230, + '𞥇' => 230, + '𞥈' => 230, + '𞥉' => 230, + '𞥊' => 7, +); diff --git a/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php new file mode 100644 index 0000000..1574902 --- /dev/null +++ b/vendor/symfony/polyfill-intl-normalizer/Resources/unidata/compatibilityDecomposition.php @@ -0,0 +1,3695 @@ + ' ', + '¨' => ' ̈', + 'ª' => 'a', + '¯' => ' ̄', + '²' => '2', + '³' => '3', + '´' => ' ́', + 'µ' => 'μ', + '¸' => ' ̧', + '¹' => '1', + 'º' => 'o', + '¼' => '1⁄4', + '½' => '1⁄2', + '¾' => '3⁄4', + 'IJ' => 'IJ', + 'ij' => 'ij', + 'Ŀ' => 'L·', + 'ŀ' => 'l·', + 'ʼn' => 'ʼn', + 'ſ' => 's', + 'DŽ' => 'DŽ', + 'Dž' => 'Dž', + 'dž' => 'dž', + 'LJ' => 'LJ', + 'Lj' => 'Lj', + 'lj' => 'lj', + 'NJ' => 'NJ', + 'Nj' => 'Nj', + 'nj' => 'nj', + 'DZ' => 'DZ', + 'Dz' => 'Dz', + 'dz' => 'dz', + 'ʰ' => 'h', + 'ʱ' => 'ɦ', + 'ʲ' => 'j', + 'ʳ' => 'r', + 'ʴ' => 'ɹ', + 'ʵ' => 'ɻ', + 'ʶ' => 'ʁ', + 'ʷ' => 'w', + 'ʸ' => 'y', + '˘' => ' ̆', + '˙' => ' ̇', + '˚' => ' ̊', + '˛' => ' ̨', + '˜' => ' ̃', + '˝' => ' ̋', + 'ˠ' => 'ɣ', + 'ˡ' => 'l', + 'ˢ' => 's', + 'ˣ' => 'x', + 'ˤ' => 'ʕ', + 'ͺ' => ' ͅ', + '΄' => ' ́', + '΅' => ' ̈́', + 'ϐ' => 'β', + 'ϑ' => 'θ', + 'ϒ' => 'Υ', + 'ϓ' => 'Ύ', + 'ϔ' => 'Ϋ', + 'ϕ' => 'φ', + 'ϖ' => 'π', + 'ϰ' => 'κ', + 'ϱ' => 'ρ', + 'ϲ' => 'ς', + 'ϴ' => 'Θ', + 'ϵ' => 'ε', + 'Ϲ' => 'Σ', + 'և' => 'եւ', + 'ٵ' => 'اٴ', + 'ٶ' => 'وٴ', + 'ٷ' => 'ۇٴ', + 'ٸ' => 'يٴ', + 'ำ' => 'ํา', + 'ຳ' => 'ໍາ', + 'ໜ' => 'ຫນ', + 'ໝ' => 'ຫມ', + '༌' => '་', + 'ཷ' => 'ྲཱྀ', + 'ཹ' => 'ླཱྀ', + 'ჼ' => 'ნ', + 'ᴬ' => 'A', + 'ᴭ' => 'Æ', + 'ᴮ' => 'B', + 'ᴰ' => 'D', + 'ᴱ' => 'E', + 'ᴲ' => 'Ǝ', + 'ᴳ' => 'G', + 'ᴴ' => 'H', + 'ᴵ' => 'I', + 'ᴶ' => 'J', + 'ᴷ' => 'K', + 'ᴸ' => 'L', + 'ᴹ' => 'M', + 'ᴺ' => 'N', + 'ᴼ' => 'O', + 'ᴽ' => 'Ȣ', + 'ᴾ' => 'P', + 'ᴿ' => 'R', + 'ᵀ' => 'T', + 'ᵁ' => 'U', + 'ᵂ' => 'W', + 'ᵃ' => 'a', + 'ᵄ' => 'ɐ', + 'ᵅ' => 'ɑ', + 'ᵆ' => 'ᴂ', + 'ᵇ' => 'b', + 'ᵈ' => 'd', + 'ᵉ' => 'e', + 'ᵊ' => 'ə', + 'ᵋ' => 'ɛ', + 'ᵌ' => 'ɜ', + 'ᵍ' => 'g', + 'ᵏ' => 'k', + 'ᵐ' => 'm', + 'ᵑ' => 'ŋ', + 'ᵒ' => 'o', + 'ᵓ' => 'ɔ', + 'ᵔ' => 'ᴖ', + 'ᵕ' => 'ᴗ', + 'ᵖ' => 'p', + 'ᵗ' => 't', + 'ᵘ' => 'u', + 'ᵙ' => 'ᴝ', + 'ᵚ' => 'ɯ', + 'ᵛ' => 'v', + 'ᵜ' => 'ᴥ', + 'ᵝ' => 'β', + 'ᵞ' => 'γ', + 'ᵟ' => 'δ', + 'ᵠ' => 'φ', + 'ᵡ' => 'χ', + 'ᵢ' => 'i', + 'ᵣ' => 'r', + 'ᵤ' => 'u', + 'ᵥ' => 'v', + 'ᵦ' => 'β', + 'ᵧ' => 'γ', + 'ᵨ' => 'ρ', + 'ᵩ' => 'φ', + 'ᵪ' => 'χ', + 'ᵸ' => 'н', + 'ᶛ' => 'ɒ', + 'ᶜ' => 'c', + 'ᶝ' => 'ɕ', + 'ᶞ' => 'ð', + 'ᶟ' => 'ɜ', + 'ᶠ' => 'f', + 'ᶡ' => 'ɟ', + 'ᶢ' => 'ɡ', + 'ᶣ' => 'ɥ', + 'ᶤ' => 'ɨ', + 'ᶥ' => 'ɩ', + 'ᶦ' => 'ɪ', + 'ᶧ' => 'ᵻ', + 'ᶨ' => 'ʝ', + 'ᶩ' => 'ɭ', + 'ᶪ' => 'ᶅ', + 'ᶫ' => 'ʟ', + 'ᶬ' => 'ɱ', + 'ᶭ' => 'ɰ', + 'ᶮ' => 'ɲ', + 'ᶯ' => 'ɳ', + 'ᶰ' => 'ɴ', + 'ᶱ' => 'ɵ', + 'ᶲ' => 'ɸ', + 'ᶳ' => 'ʂ', + 'ᶴ' => 'ʃ', + 'ᶵ' => 'ƫ', + 'ᶶ' => 'ʉ', + 'ᶷ' => 'ʊ', + 'ᶸ' => 'ᴜ', + 'ᶹ' => 'ʋ', + 'ᶺ' => 'ʌ', + 'ᶻ' => 'z', + 'ᶼ' => 'ʐ', + 'ᶽ' => 'ʑ', + 'ᶾ' => 'ʒ', + 'ᶿ' => 'θ', + 'ẚ' => 'aʾ', + 'ẛ' => 'ṡ', + '᾽' => ' ̓', + '᾿' => ' ̓', + '῀' => ' ͂', + '῁' => ' ̈͂', + '῍' => ' ̓̀', + '῎' => ' ̓́', + '῏' => ' ̓͂', + '῝' => ' ̔̀', + '῞' => ' ̔́', + '῟' => ' ̔͂', + '῭' => ' ̈̀', + '΅' => ' ̈́', + '´' => ' ́', + '῾' => ' ̔', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + ' ' => ' ', + '‑' => '‐', + '‗' => ' ̳', + '․' => '.', + '‥' => '..', + '…' => '...', + ' ' => ' ', + '″' => '′′', + '‴' => '′′′', + '‶' => '‵‵', + '‷' => '‵‵‵', + '‼' => '!!', + '‾' => ' ̅', + '⁇' => '??', + '⁈' => '?!', + '⁉' => '!?', + '⁗' => '′′′′', + ' ' => ' ', + '⁰' => '0', + 'ⁱ' => 'i', + '⁴' => '4', + '⁵' => '5', + '⁶' => '6', + '⁷' => '7', + '⁸' => '8', + '⁹' => '9', + '⁺' => '+', + '⁻' => '−', + '⁼' => '=', + '⁽' => '(', + '⁾' => ')', + 'ⁿ' => 'n', + '₀' => '0', + '₁' => '1', + '₂' => '2', + '₃' => '3', + '₄' => '4', + '₅' => '5', + '₆' => '6', + '₇' => '7', + '₈' => '8', + '₉' => '9', + '₊' => '+', + '₋' => '−', + '₌' => '=', + '₍' => '(', + '₎' => ')', + 'ₐ' => 'a', + 'ₑ' => 'e', + 'ₒ' => 'o', + 'ₓ' => 'x', + 'ₔ' => 'ə', + 'ₕ' => 'h', + 'ₖ' => 'k', + 'ₗ' => 'l', + 'ₘ' => 'm', + 'ₙ' => 'n', + 'ₚ' => 'p', + 'ₛ' => 's', + 'ₜ' => 't', + '₨' => 'Rs', + '℀' => 'a/c', + '℁' => 'a/s', + 'ℂ' => 'C', + '℃' => '°C', + '℅' => 'c/o', + '℆' => 'c/u', + 'ℇ' => 'Ɛ', + '℉' => '°F', + 'ℊ' => 'g', + 'ℋ' => 'H', + 'ℌ' => 'H', + 'ℍ' => 'H', + 'ℎ' => 'h', + 'ℏ' => 'ħ', + 'ℐ' => 'I', + 'ℑ' => 'I', + 'ℒ' => 'L', + 'ℓ' => 'l', + 'ℕ' => 'N', + '№' => 'No', + 'ℙ' => 'P', + 'ℚ' => 'Q', + 'ℛ' => 'R', + 'ℜ' => 'R', + 'ℝ' => 'R', + '℠' => 'SM', + '℡' => 'TEL', + '™' => 'TM', + 'ℤ' => 'Z', + 'ℨ' => 'Z', + 'ℬ' => 'B', + 'ℭ' => 'C', + 'ℯ' => 'e', + 'ℰ' => 'E', + 'ℱ' => 'F', + 'ℳ' => 'M', + 'ℴ' => 'o', + 'ℵ' => 'א', + 'ℶ' => 'ב', + 'ℷ' => 'ג', + 'ℸ' => 'ד', + 'ℹ' => 'i', + '℻' => 'FAX', + 'ℼ' => 'π', + 'ℽ' => 'γ', + 'ℾ' => 'Γ', + 'ℿ' => 'Π', + '⅀' => '∑', + 'ⅅ' => 'D', + 'ⅆ' => 'd', + 'ⅇ' => 'e', + 'ⅈ' => 'i', + 'ⅉ' => 'j', + '⅐' => '1⁄7', + '⅑' => '1⁄9', + '⅒' => '1⁄10', + '⅓' => '1⁄3', + '⅔' => '2⁄3', + '⅕' => '1⁄5', + '⅖' => '2⁄5', + '⅗' => '3⁄5', + '⅘' => '4⁄5', + '⅙' => '1⁄6', + '⅚' => '5⁄6', + '⅛' => '1⁄8', + '⅜' => '3⁄8', + '⅝' => '5⁄8', + '⅞' => '7⁄8', + '⅟' => '1⁄', + 'Ⅰ' => 'I', + 'Ⅱ' => 'II', + 'Ⅲ' => 'III', + 'Ⅳ' => 'IV', + 'Ⅴ' => 'V', + 'Ⅵ' => 'VI', + 'Ⅶ' => 'VII', + 'Ⅷ' => 'VIII', + 'Ⅸ' => 'IX', + 'Ⅹ' => 'X', + 'Ⅺ' => 'XI', + 'Ⅻ' => 'XII', + 'Ⅼ' => 'L', + 'Ⅽ' => 'C', + 'Ⅾ' => 'D', + 'Ⅿ' => 'M', + 'ⅰ' => 'i', + 'ⅱ' => 'ii', + 'ⅲ' => 'iii', + 'ⅳ' => 'iv', + 'ⅴ' => 'v', + 'ⅵ' => 'vi', + 'ⅶ' => 'vii', + 'ⅷ' => 'viii', + 'ⅸ' => 'ix', + 'ⅹ' => 'x', + 'ⅺ' => 'xi', + 'ⅻ' => 'xii', + 'ⅼ' => 'l', + 'ⅽ' => 'c', + 'ⅾ' => 'd', + 'ⅿ' => 'm', + '↉' => '0⁄3', + '∬' => '∫∫', + '∭' => '∫∫∫', + '∯' => '∮∮', + '∰' => '∮∮∮', + '①' => '1', + '②' => '2', + '③' => '3', + '④' => '4', + '⑤' => '5', + '⑥' => '6', + '⑦' => '7', + '⑧' => '8', + '⑨' => '9', + '⑩' => '10', + '⑪' => '11', + '⑫' => '12', + '⑬' => '13', + '⑭' => '14', + '⑮' => '15', + '⑯' => '16', + '⑰' => '17', + '⑱' => '18', + '⑲' => '19', + '⑳' => '20', + '⑴' => '(1)', + '⑵' => '(2)', + '⑶' => '(3)', + '⑷' => '(4)', + '⑸' => '(5)', + '⑹' => '(6)', + '⑺' => '(7)', + '⑻' => '(8)', + '⑼' => '(9)', + '⑽' => '(10)', + '⑾' => '(11)', + '⑿' => '(12)', + '⒀' => '(13)', + '⒁' => '(14)', + '⒂' => '(15)', + '⒃' => '(16)', + '⒄' => '(17)', + '⒅' => '(18)', + '⒆' => '(19)', + '⒇' => '(20)', + '⒈' => '1.', + '⒉' => '2.', + '⒊' => '3.', + '⒋' => '4.', + '⒌' => '5.', + '⒍' => '6.', + '⒎' => '7.', + '⒏' => '8.', + '⒐' => '9.', + '⒑' => '10.', + '⒒' => '11.', + '⒓' => '12.', + '⒔' => '13.', + '⒕' => '14.', + '⒖' => '15.', + '⒗' => '16.', + '⒘' => '17.', + '⒙' => '18.', + '⒚' => '19.', + '⒛' => '20.', + '⒜' => '(a)', + '⒝' => '(b)', + '⒞' => '(c)', + '⒟' => '(d)', + '⒠' => '(e)', + '⒡' => '(f)', + '⒢' => '(g)', + '⒣' => '(h)', + '⒤' => '(i)', + '⒥' => '(j)', + '⒦' => '(k)', + '⒧' => '(l)', + '⒨' => '(m)', + '⒩' => '(n)', + '⒪' => '(o)', + '⒫' => '(p)', + '⒬' => '(q)', + '⒭' => '(r)', + '⒮' => '(s)', + '⒯' => '(t)', + '⒰' => '(u)', + '⒱' => '(v)', + '⒲' => '(w)', + '⒳' => '(x)', + '⒴' => '(y)', + '⒵' => '(z)', + 'Ⓐ' => 'A', + 'Ⓑ' => 'B', + 'Ⓒ' => 'C', + 'Ⓓ' => 'D', + 'Ⓔ' => 'E', + 'Ⓕ' => 'F', + 'Ⓖ' => 'G', + 'Ⓗ' => 'H', + 'Ⓘ' => 'I', + 'Ⓙ' => 'J', + 'Ⓚ' => 'K', + 'Ⓛ' => 'L', + 'Ⓜ' => 'M', + 'Ⓝ' => 'N', + 'Ⓞ' => 'O', + 'Ⓟ' => 'P', + 'Ⓠ' => 'Q', + 'Ⓡ' => 'R', + 'Ⓢ' => 'S', + 'Ⓣ' => 'T', + 'Ⓤ' => 'U', + 'Ⓥ' => 'V', + 'Ⓦ' => 'W', + 'Ⓧ' => 'X', + 'Ⓨ' => 'Y', + 'Ⓩ' => 'Z', + 'ⓐ' => 'a', + 'ⓑ' => 'b', + 'ⓒ' => 'c', + 'ⓓ' => 'd', + 'ⓔ' => 'e', + 'ⓕ' => 'f', + 'ⓖ' => 'g', + 'ⓗ' => 'h', + 'ⓘ' => 'i', + 'ⓙ' => 'j', + 'ⓚ' => 'k', + 'ⓛ' => 'l', + 'ⓜ' => 'm', + 'ⓝ' => 'n', + 'ⓞ' => 'o', + 'ⓟ' => 'p', + 'ⓠ' => 'q', + 'ⓡ' => 'r', + 'ⓢ' => 's', + 'ⓣ' => 't', + 'ⓤ' => 'u', + 'ⓥ' => 'v', + 'ⓦ' => 'w', + 'ⓧ' => 'x', + 'ⓨ' => 'y', + 'ⓩ' => 'z', + '⓪' => '0', + '⨌' => '∫∫∫∫', + '⩴' => '::=', + '⩵' => '==', + '⩶' => '===', + 'ⱼ' => 'j', + 'ⱽ' => 'V', + 'ⵯ' => 'ⵡ', + '⺟' => '母', + '⻳' => '龟', + '⼀' => '一', + '⼁' => '丨', + '⼂' => '丶', + '⼃' => '丿', + '⼄' => '乙', + '⼅' => '亅', + '⼆' => '二', + '⼇' => '亠', + '⼈' => '人', + '⼉' => '儿', + '⼊' => '入', + '⼋' => '八', + '⼌' => '冂', + '⼍' => '冖', + '⼎' => '冫', + '⼏' => '几', + '⼐' => '凵', + '⼑' => '刀', + '⼒' => '力', + '⼓' => '勹', + '⼔' => '匕', + '⼕' => '匚', + '⼖' => '匸', + '⼗' => '十', + '⼘' => '卜', + '⼙' => '卩', + '⼚' => '厂', + '⼛' => '厶', + '⼜' => '又', + '⼝' => '口', + '⼞' => '囗', + '⼟' => '土', + '⼠' => '士', + '⼡' => '夂', + '⼢' => '夊', + '⼣' => '夕', + '⼤' => '大', + '⼥' => '女', + '⼦' => '子', + '⼧' => '宀', + '⼨' => '寸', + '⼩' => '小', + '⼪' => '尢', + '⼫' => '尸', + '⼬' => '屮', + '⼭' => '山', + '⼮' => '巛', + '⼯' => '工', + '⼰' => '己', + '⼱' => '巾', + '⼲' => '干', + '⼳' => '幺', + '⼴' => '广', + '⼵' => '廴', + '⼶' => '廾', + '⼷' => '弋', + '⼸' => '弓', + '⼹' => '彐', + '⼺' => '彡', + '⼻' => '彳', + '⼼' => '心', + '⼽' => '戈', + '⼾' => '戶', + '⼿' => '手', + '⽀' => '支', + '⽁' => '攴', + '⽂' => '文', + '⽃' => '斗', + '⽄' => '斤', + '⽅' => '方', + '⽆' => '无', + '⽇' => '日', + '⽈' => '曰', + '⽉' => '月', + '⽊' => '木', + '⽋' => '欠', + '⽌' => '止', + '⽍' => '歹', + '⽎' => '殳', + '⽏' => '毋', + '⽐' => '比', + '⽑' => '毛', + '⽒' => '氏', + '⽓' => '气', + '⽔' => '水', + '⽕' => '火', + '⽖' => '爪', + '⽗' => '父', + '⽘' => '爻', + '⽙' => '爿', + '⽚' => '片', + '⽛' => '牙', + '⽜' => '牛', + '⽝' => '犬', + '⽞' => '玄', + '⽟' => '玉', + '⽠' => '瓜', + '⽡' => '瓦', + '⽢' => '甘', + '⽣' => '生', + '⽤' => '用', + '⽥' => '田', + '⽦' => '疋', + '⽧' => '疒', + '⽨' => '癶', + '⽩' => '白', + '⽪' => '皮', + '⽫' => '皿', + '⽬' => '目', + '⽭' => '矛', + '⽮' => '矢', + '⽯' => '石', + '⽰' => '示', + '⽱' => '禸', + '⽲' => '禾', + '⽳' => '穴', + '⽴' => '立', + '⽵' => '竹', + '⽶' => '米', + '⽷' => '糸', + '⽸' => '缶', + '⽹' => '网', + '⽺' => '羊', + '⽻' => '羽', + '⽼' => '老', + '⽽' => '而', + '⽾' => '耒', + '⽿' => '耳', + '⾀' => '聿', + '⾁' => '肉', + '⾂' => '臣', + '⾃' => '自', + '⾄' => '至', + '⾅' => '臼', + '⾆' => '舌', + '⾇' => '舛', + '⾈' => '舟', + '⾉' => '艮', + '⾊' => '色', + '⾋' => '艸', + '⾌' => '虍', + '⾍' => '虫', + '⾎' => '血', + '⾏' => '行', + '⾐' => '衣', + '⾑' => '襾', + '⾒' => '見', + '⾓' => '角', + '⾔' => '言', + '⾕' => '谷', + '⾖' => '豆', + '⾗' => '豕', + '⾘' => '豸', + '⾙' => '貝', + '⾚' => '赤', + '⾛' => '走', + '⾜' => '足', + '⾝' => '身', + '⾞' => '車', + '⾟' => '辛', + '⾠' => '辰', + '⾡' => '辵', + '⾢' => '邑', + '⾣' => '酉', + '⾤' => '釆', + '⾥' => '里', + '⾦' => '金', + '⾧' => '長', + '⾨' => '門', + '⾩' => '阜', + '⾪' => '隶', + '⾫' => '隹', + '⾬' => '雨', + '⾭' => '靑', + '⾮' => '非', + '⾯' => '面', + '⾰' => '革', + '⾱' => '韋', + '⾲' => '韭', + '⾳' => '音', + '⾴' => '頁', + '⾵' => '風', + '⾶' => '飛', + '⾷' => '食', + '⾸' => '首', + '⾹' => '香', + '⾺' => '馬', + '⾻' => '骨', + '⾼' => '高', + '⾽' => '髟', + '⾾' => '鬥', + '⾿' => '鬯', + '⿀' => '鬲', + '⿁' => '鬼', + '⿂' => '魚', + '⿃' => '鳥', + '⿄' => '鹵', + '⿅' => '鹿', + '⿆' => '麥', + '⿇' => '麻', + '⿈' => '黃', + '⿉' => '黍', + '⿊' => '黑', + '⿋' => '黹', + '⿌' => '黽', + '⿍' => '鼎', + '⿎' => '鼓', + '⿏' => '鼠', + '⿐' => '鼻', + '⿑' => '齊', + '⿒' => '齒', + '⿓' => '龍', + '⿔' => '龜', + '⿕' => '龠', + ' ' => ' ', + '〶' => '〒', + '〸' => '十', + '〹' => '卄', + '〺' => '卅', + '゛' => ' ゙', + '゜' => ' ゚', + 'ゟ' => 'より', + 'ヿ' => 'コト', + 'ㄱ' => 'ᄀ', + 'ㄲ' => 'ᄁ', + 'ㄳ' => 'ᆪ', + 'ㄴ' => 'ᄂ', + 'ㄵ' => 'ᆬ', + 'ㄶ' => 'ᆭ', + 'ㄷ' => 'ᄃ', + 'ㄸ' => 'ᄄ', + 'ㄹ' => 'ᄅ', + 'ㄺ' => 'ᆰ', + 'ㄻ' => 'ᆱ', + 'ㄼ' => 'ᆲ', + 'ㄽ' => 'ᆳ', + 'ㄾ' => 'ᆴ', + 'ㄿ' => 'ᆵ', + 'ㅀ' => 'ᄚ', + 'ㅁ' => 'ᄆ', + 'ㅂ' => 'ᄇ', + 'ㅃ' => 'ᄈ', + 'ㅄ' => 'ᄡ', + 'ㅅ' => 'ᄉ', + 'ㅆ' => 'ᄊ', + 'ㅇ' => 'ᄋ', + 'ㅈ' => 'ᄌ', + 'ㅉ' => 'ᄍ', + 'ㅊ' => 'ᄎ', + 'ㅋ' => 'ᄏ', + 'ㅌ' => 'ᄐ', + 'ㅍ' => 'ᄑ', + 'ㅎ' => 'ᄒ', + 'ㅏ' => 'ᅡ', + 'ㅐ' => 'ᅢ', + 'ㅑ' => 'ᅣ', + 'ㅒ' => 'ᅤ', + 'ㅓ' => 'ᅥ', + 'ㅔ' => 'ᅦ', + 'ㅕ' => 'ᅧ', + 'ㅖ' => 'ᅨ', + 'ㅗ' => 'ᅩ', + 'ㅘ' => 'ᅪ', + 'ㅙ' => 'ᅫ', + 'ㅚ' => 'ᅬ', + 'ㅛ' => 'ᅭ', + 'ㅜ' => 'ᅮ', + 'ㅝ' => 'ᅯ', + 'ㅞ' => 'ᅰ', + 'ㅟ' => 'ᅱ', + 'ㅠ' => 'ᅲ', + 'ㅡ' => 'ᅳ', + 'ㅢ' => 'ᅴ', + 'ㅣ' => 'ᅵ', + 'ㅤ' => 'ᅠ', + 'ㅥ' => 'ᄔ', + 'ㅦ' => 'ᄕ', + 'ㅧ' => 'ᇇ', + 'ㅨ' => 'ᇈ', + 'ㅩ' => 'ᇌ', + 'ㅪ' => 'ᇎ', + 'ㅫ' => 'ᇓ', + 'ㅬ' => 'ᇗ', + 'ㅭ' => 'ᇙ', + 'ㅮ' => 'ᄜ', + 'ㅯ' => 'ᇝ', + 'ㅰ' => 'ᇟ', + 'ㅱ' => 'ᄝ', + 'ㅲ' => 'ᄞ', + 'ㅳ' => 'ᄠ', + 'ㅴ' => 'ᄢ', + 'ㅵ' => 'ᄣ', + 'ㅶ' => 'ᄧ', + 'ㅷ' => 'ᄩ', + 'ㅸ' => 'ᄫ', + 'ㅹ' => 'ᄬ', + 'ㅺ' => 'ᄭ', + 'ㅻ' => 'ᄮ', + 'ㅼ' => 'ᄯ', + 'ㅽ' => 'ᄲ', + 'ㅾ' => 'ᄶ', + 'ㅿ' => 'ᅀ', + 'ㆀ' => 'ᅇ', + 'ㆁ' => 'ᅌ', + 'ㆂ' => 'ᇱ', + 'ㆃ' => 'ᇲ', + 'ㆄ' => 'ᅗ', + 'ㆅ' => 'ᅘ', + 'ㆆ' => 'ᅙ', + 'ㆇ' => 'ᆄ', + 'ㆈ' => 'ᆅ', + 'ㆉ' => 'ᆈ', + 'ㆊ' => 'ᆑ', + 'ㆋ' => 'ᆒ', + 'ㆌ' => 'ᆔ', + 'ㆍ' => 'ᆞ', + 'ㆎ' => 'ᆡ', + '㆒' => '一', + '㆓' => '二', + '㆔' => '三', + '㆕' => '四', + '㆖' => '上', + '㆗' => '中', + '㆘' => '下', + '㆙' => '甲', + '㆚' => '乙', + '㆛' => '丙', + '㆜' => '丁', + '㆝' => '天', + '㆞' => '地', + '㆟' => '人', + '㈀' => '(ᄀ)', + '㈁' => '(ᄂ)', + '㈂' => '(ᄃ)', + '㈃' => '(ᄅ)', + '㈄' => '(ᄆ)', + '㈅' => '(ᄇ)', + '㈆' => '(ᄉ)', + '㈇' => '(ᄋ)', + '㈈' => '(ᄌ)', + '㈉' => '(ᄎ)', + '㈊' => '(ᄏ)', + '㈋' => '(ᄐ)', + '㈌' => '(ᄑ)', + '㈍' => '(ᄒ)', + '㈎' => '(가)', + '㈏' => '(나)', + '㈐' => '(다)', + '㈑' => '(라)', + '㈒' => '(마)', + '㈓' => '(바)', + '㈔' => '(사)', + '㈕' => '(아)', + '㈖' => '(자)', + '㈗' => '(차)', + '㈘' => '(카)', + '㈙' => '(타)', + '㈚' => '(파)', + '㈛' => '(하)', + '㈜' => '(주)', + '㈝' => '(오전)', + '㈞' => '(오후)', + '㈠' => '(一)', + '㈡' => '(二)', + '㈢' => '(三)', + '㈣' => '(四)', + '㈤' => '(五)', + '㈥' => '(六)', + '㈦' => '(七)', + '㈧' => '(八)', + '㈨' => '(九)', + '㈩' => '(十)', + '㈪' => '(月)', + '㈫' => '(火)', + '㈬' => '(水)', + '㈭' => '(木)', + '㈮' => '(金)', + '㈯' => '(土)', + '㈰' => '(日)', + '㈱' => '(株)', + '㈲' => '(有)', + '㈳' => '(社)', + '㈴' => '(名)', + '㈵' => '(特)', + '㈶' => '(財)', + '㈷' => '(祝)', + '㈸' => '(労)', + '㈹' => '(代)', + '㈺' => '(呼)', + '㈻' => '(学)', + '㈼' => '(監)', + '㈽' => '(企)', + '㈾' => '(資)', + '㈿' => '(協)', + '㉀' => '(祭)', + '㉁' => '(休)', + '㉂' => '(自)', + '㉃' => '(至)', + '㉄' => '問', + '㉅' => '幼', + '㉆' => '文', + '㉇' => '箏', + '㉐' => 'PTE', + '㉑' => '21', + '㉒' => '22', + '㉓' => '23', + '㉔' => '24', + '㉕' => '25', + '㉖' => '26', + '㉗' => '27', + '㉘' => '28', + '㉙' => '29', + '㉚' => '30', + '㉛' => '31', + '㉜' => '32', + '㉝' => '33', + '㉞' => '34', + '㉟' => '35', + '㉠' => 'ᄀ', + '㉡' => 'ᄂ', + '㉢' => 'ᄃ', + '㉣' => 'ᄅ', + '㉤' => 'ᄆ', + '㉥' => 'ᄇ', + '㉦' => 'ᄉ', + '㉧' => 'ᄋ', + '㉨' => 'ᄌ', + '㉩' => 'ᄎ', + '㉪' => 'ᄏ', + '㉫' => 'ᄐ', + '㉬' => 'ᄑ', + '㉭' => 'ᄒ', + '㉮' => '가', + '㉯' => '나', + '㉰' => '다', + '㉱' => '라', + '㉲' => '마', + '㉳' => '바', + '㉴' => '사', + '㉵' => '아', + '㉶' => '자', + '㉷' => '차', + '㉸' => '카', + '㉹' => '타', + '㉺' => '파', + '㉻' => '하', + '㉼' => '참고', + '㉽' => '주의', + '㉾' => '우', + '㊀' => '一', + '㊁' => '二', + '㊂' => '三', + '㊃' => '四', + '㊄' => '五', + '㊅' => '六', + '㊆' => '七', + '㊇' => '八', + '㊈' => '九', + '㊉' => '十', + '㊊' => '月', + '㊋' => '火', + '㊌' => '水', + '㊍' => '木', + '㊎' => '金', + '㊏' => '土', + '㊐' => '日', + '㊑' => '株', + '㊒' => '有', + '㊓' => '社', + '㊔' => '名', + '㊕' => '特', + '㊖' => '財', + '㊗' => '祝', + '㊘' => '労', + '㊙' => '秘', + '㊚' => '男', + '㊛' => '女', + '㊜' => '適', + '㊝' => '優', + '㊞' => '印', + '㊟' => '注', + '㊠' => '項', + '㊡' => '休', + '㊢' => '写', + '㊣' => '正', + '㊤' => '上', + '㊥' => '中', + '㊦' => '下', + '㊧' => '左', + '㊨' => '右', + '㊩' => '医', + '㊪' => '宗', + '㊫' => '学', + '㊬' => '監', + '㊭' => '企', + '㊮' => '資', + '㊯' => '協', + '㊰' => '夜', + '㊱' => '36', + '㊲' => '37', + '㊳' => '38', + '㊴' => '39', + '㊵' => '40', + '㊶' => '41', + '㊷' => '42', + '㊸' => '43', + '㊹' => '44', + '㊺' => '45', + '㊻' => '46', + '㊼' => '47', + '㊽' => '48', + '㊾' => '49', + '㊿' => '50', + '㋀' => '1月', + '㋁' => '2月', + '㋂' => '3月', + '㋃' => '4月', + '㋄' => '5月', + '㋅' => '6月', + '㋆' => '7月', + '㋇' => '8月', + '㋈' => '9月', + '㋉' => '10月', + '㋊' => '11月', + '㋋' => '12月', + '㋌' => 'Hg', + '㋍' => 'erg', + '㋎' => 'eV', + '㋏' => 'LTD', + '㋐' => 'ア', + '㋑' => 'イ', + '㋒' => 'ウ', + '㋓' => 'エ', + '㋔' => 'オ', + '㋕' => 'カ', + '㋖' => 'キ', + '㋗' => 'ク', + '㋘' => 'ケ', + '㋙' => 'コ', + '㋚' => 'サ', + '㋛' => 'シ', + '㋜' => 'ス', + '㋝' => 'セ', + '㋞' => 'ソ', + '㋟' => 'タ', + '㋠' => 'チ', + '㋡' => 'ツ', + '㋢' => 'テ', + '㋣' => 'ト', + '㋤' => 'ナ', + '㋥' => 'ニ', + '㋦' => 'ヌ', + '㋧' => 'ネ', + '㋨' => 'ノ', + '㋩' => 'ハ', + '㋪' => 'ヒ', + '㋫' => 'フ', + '㋬' => 'ヘ', + '㋭' => 'ホ', + '㋮' => 'マ', + '㋯' => 'ミ', + '㋰' => 'ム', + '㋱' => 'メ', + '㋲' => 'モ', + '㋳' => 'ヤ', + '㋴' => 'ユ', + '㋵' => 'ヨ', + '㋶' => 'ラ', + '㋷' => 'リ', + '㋸' => 'ル', + '㋹' => 'レ', + '㋺' => 'ロ', + '㋻' => 'ワ', + '㋼' => 'ヰ', + '㋽' => 'ヱ', + '㋾' => 'ヲ', + '㋿' => '令和', + '㌀' => 'アパート', + '㌁' => 'アルファ', + '㌂' => 'アンペア', + '㌃' => 'アール', + '㌄' => 'イニング', + '㌅' => 'インチ', + '㌆' => 'ウォン', + '㌇' => 'エスクード', + '㌈' => 'エーカー', + '㌉' => 'オンス', + '㌊' => 'オーム', + '㌋' => 'カイリ', + '㌌' => 'カラット', + '㌍' => 'カロリー', + '㌎' => 'ガロン', + '㌏' => 'ガンマ', + '㌐' => 'ギガ', + '㌑' => 'ギニー', + '㌒' => 'キュリー', + '㌓' => 'ギルダー', + '㌔' => 'キロ', + '㌕' => 'キログラム', + '㌖' => 'キロメートル', + '㌗' => 'キロワット', + '㌘' => 'グラム', + '㌙' => 'グラムトン', + '㌚' => 'クルゼイロ', + '㌛' => 'クローネ', + '㌜' => 'ケース', + '㌝' => 'コルナ', + '㌞' => 'コーポ', + '㌟' => 'サイクル', + '㌠' => 'サンチーム', + '㌡' => 'シリング', + '㌢' => 'センチ', + '㌣' => 'セント', + '㌤' => 'ダース', + '㌥' => 'デシ', + '㌦' => 'ドル', + '㌧' => 'トン', + '㌨' => 'ナノ', + '㌩' => 'ノット', + '㌪' => 'ハイツ', + '㌫' => 'パーセント', + '㌬' => 'パーツ', + '㌭' => 'バーレル', + '㌮' => 'ピアストル', + '㌯' => 'ピクル', + '㌰' => 'ピコ', + '㌱' => 'ビル', + '㌲' => 'ファラッド', + '㌳' => 'フィート', + '㌴' => 'ブッシェル', + '㌵' => 'フラン', + '㌶' => 'ヘクタール', + '㌷' => 'ペソ', + '㌸' => 'ペニヒ', + '㌹' => 'ヘルツ', + '㌺' => 'ペンス', + '㌻' => 'ページ', + '㌼' => 'ベータ', + '㌽' => 'ポイント', + '㌾' => 'ボルト', + '㌿' => 'ホン', + '㍀' => 'ポンド', + '㍁' => 'ホール', + '㍂' => 'ホーン', + '㍃' => 'マイクロ', + '㍄' => 'マイル', + '㍅' => 'マッハ', + '㍆' => 'マルク', + '㍇' => 'マンション', + '㍈' => 'ミクロン', + '㍉' => 'ミリ', + '㍊' => 'ミリバール', + '㍋' => 'メガ', + '㍌' => 'メガトン', + '㍍' => 'メートル', + '㍎' => 'ヤード', + '㍏' => 'ヤール', + '㍐' => 'ユアン', + '㍑' => 'リットル', + '㍒' => 'リラ', + '㍓' => 'ルピー', + '㍔' => 'ルーブル', + '㍕' => 'レム', + '㍖' => 'レントゲン', + '㍗' => 'ワット', + '㍘' => '0点', + '㍙' => '1点', + '㍚' => '2点', + '㍛' => '3点', + '㍜' => '4点', + '㍝' => '5点', + '㍞' => '6点', + '㍟' => '7点', + '㍠' => '8点', + '㍡' => '9点', + '㍢' => '10点', + '㍣' => '11点', + '㍤' => '12点', + '㍥' => '13点', + '㍦' => '14点', + '㍧' => '15点', + '㍨' => '16点', + '㍩' => '17点', + '㍪' => '18点', + '㍫' => '19点', + '㍬' => '20点', + '㍭' => '21点', + '㍮' => '22点', + '㍯' => '23点', + '㍰' => '24点', + '㍱' => 'hPa', + '㍲' => 'da', + '㍳' => 'AU', + '㍴' => 'bar', + '㍵' => 'oV', + '㍶' => 'pc', + '㍷' => 'dm', + '㍸' => 'dm2', + '㍹' => 'dm3', + '㍺' => 'IU', + '㍻' => '平成', + '㍼' => '昭和', + '㍽' => '大正', + '㍾' => '明治', + '㍿' => '株式会社', + '㎀' => 'pA', + '㎁' => 'nA', + '㎂' => 'μA', + '㎃' => 'mA', + '㎄' => 'kA', + '㎅' => 'KB', + '㎆' => 'MB', + '㎇' => 'GB', + '㎈' => 'cal', + '㎉' => 'kcal', + '㎊' => 'pF', + '㎋' => 'nF', + '㎌' => 'μF', + '㎍' => 'μg', + '㎎' => 'mg', + '㎏' => 'kg', + '㎐' => 'Hz', + '㎑' => 'kHz', + '㎒' => 'MHz', + '㎓' => 'GHz', + '㎔' => 'THz', + '㎕' => 'μl', + '㎖' => 'ml', + '㎗' => 'dl', + '㎘' => 'kl', + '㎙' => 'fm', + '㎚' => 'nm', + '㎛' => 'μm', + '㎜' => 'mm', + '㎝' => 'cm', + '㎞' => 'km', + '㎟' => 'mm2', + '㎠' => 'cm2', + '㎡' => 'm2', + '㎢' => 'km2', + '㎣' => 'mm3', + '㎤' => 'cm3', + '㎥' => 'm3', + '㎦' => 'km3', + '㎧' => 'm∕s', + '㎨' => 'm∕s2', + '㎩' => 'Pa', + '㎪' => 'kPa', + '㎫' => 'MPa', + '㎬' => 'GPa', + '㎭' => 'rad', + '㎮' => 'rad∕s', + '㎯' => 'rad∕s2', + '㎰' => 'ps', + '㎱' => 'ns', + '㎲' => 'μs', + '㎳' => 'ms', + '㎴' => 'pV', + '㎵' => 'nV', + '㎶' => 'μV', + '㎷' => 'mV', + '㎸' => 'kV', + '㎹' => 'MV', + '㎺' => 'pW', + '㎻' => 'nW', + '㎼' => 'μW', + '㎽' => 'mW', + '㎾' => 'kW', + '㎿' => 'MW', + '㏀' => 'kΩ', + '㏁' => 'MΩ', + '㏂' => 'a.m.', + '㏃' => 'Bq', + '㏄' => 'cc', + '㏅' => 'cd', + '㏆' => 'C∕kg', + '㏇' => 'Co.', + '㏈' => 'dB', + '㏉' => 'Gy', + '㏊' => 'ha', + '㏋' => 'HP', + '㏌' => 'in', + '㏍' => 'KK', + '㏎' => 'KM', + '㏏' => 'kt', + '㏐' => 'lm', + '㏑' => 'ln', + '㏒' => 'log', + '㏓' => 'lx', + '㏔' => 'mb', + '㏕' => 'mil', + '㏖' => 'mol', + '㏗' => 'PH', + '㏘' => 'p.m.', + '㏙' => 'PPM', + '㏚' => 'PR', + '㏛' => 'sr', + '㏜' => 'Sv', + '㏝' => 'Wb', + '㏞' => 'V∕m', + '㏟' => 'A∕m', + '㏠' => '1日', + '㏡' => '2日', + '㏢' => '3日', + '㏣' => '4日', + '㏤' => '5日', + '㏥' => '6日', + '㏦' => '7日', + '㏧' => '8日', + '㏨' => '9日', + '㏩' => '10日', + '㏪' => '11日', + '㏫' => '12日', + '㏬' => '13日', + '㏭' => '14日', + '㏮' => '15日', + '㏯' => '16日', + '㏰' => '17日', + '㏱' => '18日', + '㏲' => '19日', + '㏳' => '20日', + '㏴' => '21日', + '㏵' => '22日', + '㏶' => '23日', + '㏷' => '24日', + '㏸' => '25日', + '㏹' => '26日', + '㏺' => '27日', + '㏻' => '28日', + '㏼' => '29日', + '㏽' => '30日', + '㏾' => '31日', + '㏿' => 'gal', + 'ꚜ' => 'ъ', + 'ꚝ' => 'ь', + 'ꝰ' => 'ꝯ', + 'ꟸ' => 'Ħ', + 'ꟹ' => 'œ', + 'ꭜ' => 'ꜧ', + 'ꭝ' => 'ꬷ', + 'ꭞ' => 'ɫ', + 'ꭟ' => 'ꭒ', + 'ꭩ' => 'ʍ', + 'ff' => 'ff', + 'fi' => 'fi', + 'fl' => 'fl', + 'ffi' => 'ffi', + 'ffl' => 'ffl', + 'ſt' => 'st', + 'st' => 'st', + 'ﬓ' => 'մն', + 'ﬔ' => 'մե', + 'ﬕ' => 'մի', + 'ﬖ' => 'վն', + 'ﬗ' => 'մխ', + 'ﬠ' => 'ע', + 'ﬡ' => 'א', + 'ﬢ' => 'ד', + 'ﬣ' => 'ה', + 'ﬤ' => 'כ', + 'ﬥ' => 'ל', + 'ﬦ' => 'ם', + 'ﬧ' => 'ר', + 'ﬨ' => 'ת', + '﬩' => '+', + 'ﭏ' => 'אל', + 'ﭐ' => 'ٱ', + 'ﭑ' => 'ٱ', + 'ﭒ' => 'ٻ', + 'ﭓ' => 'ٻ', + 'ﭔ' => 'ٻ', + 'ﭕ' => 'ٻ', + 'ﭖ' => 'پ', + 'ﭗ' => 'پ', + 'ﭘ' => 'پ', + 'ﭙ' => 'پ', + 'ﭚ' => 'ڀ', + 'ﭛ' => 'ڀ', + 'ﭜ' => 'ڀ', + 'ﭝ' => 'ڀ', + 'ﭞ' => 'ٺ', + 'ﭟ' => 'ٺ', + 'ﭠ' => 'ٺ', + 'ﭡ' => 'ٺ', + 'ﭢ' => 'ٿ', + 'ﭣ' => 'ٿ', + 'ﭤ' => 'ٿ', + 'ﭥ' => 'ٿ', + 'ﭦ' => 'ٹ', + 'ﭧ' => 'ٹ', + 'ﭨ' => 'ٹ', + 'ﭩ' => 'ٹ', + 'ﭪ' => 'ڤ', + 'ﭫ' => 'ڤ', + 'ﭬ' => 'ڤ', + 'ﭭ' => 'ڤ', + 'ﭮ' => 'ڦ', + 'ﭯ' => 'ڦ', + 'ﭰ' => 'ڦ', + 'ﭱ' => 'ڦ', + 'ﭲ' => 'ڄ', + 'ﭳ' => 'ڄ', + 'ﭴ' => 'ڄ', + 'ﭵ' => 'ڄ', + 'ﭶ' => 'ڃ', + 'ﭷ' => 'ڃ', + 'ﭸ' => 'ڃ', + 'ﭹ' => 'ڃ', + 'ﭺ' => 'چ', + 'ﭻ' => 'چ', + 'ﭼ' => 'چ', + 'ﭽ' => 'چ', + 'ﭾ' => 'ڇ', + 'ﭿ' => 'ڇ', + 'ﮀ' => 'ڇ', + 'ﮁ' => 'ڇ', + 'ﮂ' => 'ڍ', + 'ﮃ' => 'ڍ', + 'ﮄ' => 'ڌ', + 'ﮅ' => 'ڌ', + 'ﮆ' => 'ڎ', + 'ﮇ' => 'ڎ', + 'ﮈ' => 'ڈ', + 'ﮉ' => 'ڈ', + 'ﮊ' => 'ژ', + 'ﮋ' => 'ژ', + 'ﮌ' => 'ڑ', + 'ﮍ' => 'ڑ', + 'ﮎ' => 'ک', + 'ﮏ' => 'ک', + 'ﮐ' => 'ک', + 'ﮑ' => 'ک', + 'ﮒ' => 'گ', + 'ﮓ' => 'گ', + 'ﮔ' => 'گ', + 'ﮕ' => 'گ', + 'ﮖ' => 'ڳ', + 'ﮗ' => 'ڳ', + 'ﮘ' => 'ڳ', + 'ﮙ' => 'ڳ', + 'ﮚ' => 'ڱ', + 'ﮛ' => 'ڱ', + 'ﮜ' => 'ڱ', + 'ﮝ' => 'ڱ', + 'ﮞ' => 'ں', + 'ﮟ' => 'ں', + 'ﮠ' => 'ڻ', + 'ﮡ' => 'ڻ', + 'ﮢ' => 'ڻ', + 'ﮣ' => 'ڻ', + 'ﮤ' => 'ۀ', + 'ﮥ' => 'ۀ', + 'ﮦ' => 'ہ', + 'ﮧ' => 'ہ', + 'ﮨ' => 'ہ', + 'ﮩ' => 'ہ', + 'ﮪ' => 'ھ', + 'ﮫ' => 'ھ', + 'ﮬ' => 'ھ', + 'ﮭ' => 'ھ', + 'ﮮ' => 'ے', + 'ﮯ' => 'ے', + 'ﮰ' => 'ۓ', + 'ﮱ' => 'ۓ', + 'ﯓ' => 'ڭ', + 'ﯔ' => 'ڭ', + 'ﯕ' => 'ڭ', + 'ﯖ' => 'ڭ', + 'ﯗ' => 'ۇ', + 'ﯘ' => 'ۇ', + 'ﯙ' => 'ۆ', + 'ﯚ' => 'ۆ', + 'ﯛ' => 'ۈ', + 'ﯜ' => 'ۈ', + 'ﯝ' => 'ۇٴ', + 'ﯞ' => 'ۋ', + 'ﯟ' => 'ۋ', + 'ﯠ' => 'ۅ', + 'ﯡ' => 'ۅ', + 'ﯢ' => 'ۉ', + 'ﯣ' => 'ۉ', + 'ﯤ' => 'ې', + 'ﯥ' => 'ې', + 'ﯦ' => 'ې', + 'ﯧ' => 'ې', + 'ﯨ' => 'ى', + 'ﯩ' => 'ى', + 'ﯪ' => 'ئا', + 'ﯫ' => 'ئا', + 'ﯬ' => 'ئە', + 'ﯭ' => 'ئە', + 'ﯮ' => 'ئو', + 'ﯯ' => 'ئو', + 'ﯰ' => 'ئۇ', + 'ﯱ' => 'ئۇ', + 'ﯲ' => 'ئۆ', + 'ﯳ' => 'ئۆ', + 'ﯴ' => 'ئۈ', + 'ﯵ' => 'ئۈ', + 'ﯶ' => 'ئې', + 'ﯷ' => 'ئې', + 'ﯸ' => 'ئې', + 'ﯹ' => 'ئى', + 'ﯺ' => 'ئى', + 'ﯻ' => 'ئى', + 'ﯼ' => 'ی', + 'ﯽ' => 'ی', + 'ﯾ' => 'ی', + 'ﯿ' => 'ی', + 'ﰀ' => 'ئج', + 'ﰁ' => 'ئح', + 'ﰂ' => 'ئم', + 'ﰃ' => 'ئى', + 'ﰄ' => 'ئي', + 'ﰅ' => 'بج', + 'ﰆ' => 'بح', + 'ﰇ' => 'بخ', + 'ﰈ' => 'بم', + 'ﰉ' => 'بى', + 'ﰊ' => 'بي', + 'ﰋ' => 'تج', + 'ﰌ' => 'تح', + 'ﰍ' => 'تخ', + 'ﰎ' => 'تم', + 'ﰏ' => 'تى', + 'ﰐ' => 'تي', + 'ﰑ' => 'ثج', + 'ﰒ' => 'ثم', + 'ﰓ' => 'ثى', + 'ﰔ' => 'ثي', + 'ﰕ' => 'جح', + 'ﰖ' => 'جم', + 'ﰗ' => 'حج', + 'ﰘ' => 'حم', + 'ﰙ' => 'خج', + 'ﰚ' => 'خح', + 'ﰛ' => 'خم', + 'ﰜ' => 'سج', + 'ﰝ' => 'سح', + 'ﰞ' => 'سخ', + 'ﰟ' => 'سم', + 'ﰠ' => 'صح', + 'ﰡ' => 'صم', + 'ﰢ' => 'ضج', + 'ﰣ' => 'ضح', + 'ﰤ' => 'ضخ', + 'ﰥ' => 'ضم', + 'ﰦ' => 'طح', + 'ﰧ' => 'طم', + 'ﰨ' => 'ظم', + 'ﰩ' => 'عج', + 'ﰪ' => 'عم', + 'ﰫ' => 'غج', + 'ﰬ' => 'غم', + 'ﰭ' => 'فج', + 'ﰮ' => 'فح', + 'ﰯ' => 'فخ', + 'ﰰ' => 'فم', + 'ﰱ' => 'فى', + 'ﰲ' => 'في', + 'ﰳ' => 'قح', + 'ﰴ' => 'قم', + 'ﰵ' => 'قى', + 'ﰶ' => 'قي', + 'ﰷ' => 'كا', + 'ﰸ' => 'كج', + 'ﰹ' => 'كح', + 'ﰺ' => 'كخ', + 'ﰻ' => 'كل', + 'ﰼ' => 'كم', + 'ﰽ' => 'كى', + 'ﰾ' => 'كي', + 'ﰿ' => 'لج', + 'ﱀ' => 'لح', + 'ﱁ' => 'لخ', + 'ﱂ' => 'لم', + 'ﱃ' => 'لى', + 'ﱄ' => 'لي', + 'ﱅ' => 'مج', + 'ﱆ' => 'مح', + 'ﱇ' => 'مخ', + 'ﱈ' => 'مم', + 'ﱉ' => 'مى', + 'ﱊ' => 'مي', + 'ﱋ' => 'نج', + 'ﱌ' => 'نح', + 'ﱍ' => 'نخ', + 'ﱎ' => 'نم', + 'ﱏ' => 'نى', + 'ﱐ' => 'ني', + 'ﱑ' => 'هج', + 'ﱒ' => 'هم', + 'ﱓ' => 'هى', + 'ﱔ' => 'هي', + 'ﱕ' => 'يج', + 'ﱖ' => 'يح', + 'ﱗ' => 'يخ', + 'ﱘ' => 'يم', + 'ﱙ' => 'يى', + 'ﱚ' => 'يي', + 'ﱛ' => 'ذٰ', + 'ﱜ' => 'رٰ', + 'ﱝ' => 'ىٰ', + 'ﱞ' => ' ٌّ', + 'ﱟ' => ' ٍّ', + 'ﱠ' => ' َّ', + 'ﱡ' => ' ُّ', + 'ﱢ' => ' ِّ', + 'ﱣ' => ' ّٰ', + 'ﱤ' => 'ئر', + 'ﱥ' => 'ئز', + 'ﱦ' => 'ئم', + 'ﱧ' => 'ئن', + 'ﱨ' => 'ئى', + 'ﱩ' => 'ئي', + 'ﱪ' => 'بر', + 'ﱫ' => 'بز', + 'ﱬ' => 'بم', + 'ﱭ' => 'بن', + 'ﱮ' => 'بى', + 'ﱯ' => 'بي', + 'ﱰ' => 'تر', + 'ﱱ' => 'تز', + 'ﱲ' => 'تم', + 'ﱳ' => 'تن', + 'ﱴ' => 'تى', + 'ﱵ' => 'تي', + 'ﱶ' => 'ثر', + 'ﱷ' => 'ثز', + 'ﱸ' => 'ثم', + 'ﱹ' => 'ثن', + 'ﱺ' => 'ثى', + 'ﱻ' => 'ثي', + 'ﱼ' => 'فى', + 'ﱽ' => 'في', + 'ﱾ' => 'قى', + 'ﱿ' => 'قي', + 'ﲀ' => 'كا', + 'ﲁ' => 'كل', + 'ﲂ' => 'كم', + 'ﲃ' => 'كى', + 'ﲄ' => 'كي', + 'ﲅ' => 'لم', + 'ﲆ' => 'لى', + 'ﲇ' => 'لي', + 'ﲈ' => 'ما', + 'ﲉ' => 'مم', + 'ﲊ' => 'نر', + 'ﲋ' => 'نز', + 'ﲌ' => 'نم', + 'ﲍ' => 'نن', + 'ﲎ' => 'نى', + 'ﲏ' => 'ني', + 'ﲐ' => 'ىٰ', + 'ﲑ' => 'ير', + 'ﲒ' => 'يز', + 'ﲓ' => 'يم', + 'ﲔ' => 'ين', + 'ﲕ' => 'يى', + 'ﲖ' => 'يي', + 'ﲗ' => 'ئج', + 'ﲘ' => 'ئح', + 'ﲙ' => 'ئخ', + 'ﲚ' => 'ئم', + 'ﲛ' => 'ئه', + 'ﲜ' => 'بج', + 'ﲝ' => 'بح', + 'ﲞ' => 'بخ', + 'ﲟ' => 'بم', + 'ﲠ' => 'به', + 'ﲡ' => 'تج', + 'ﲢ' => 'تح', + 'ﲣ' => 'تخ', + 'ﲤ' => 'تم', + 'ﲥ' => 'ته', + 'ﲦ' => 'ثم', + 'ﲧ' => 'جح', + 'ﲨ' => 'جم', + 'ﲩ' => 'حج', + 'ﲪ' => 'حم', + 'ﲫ' => 'خج', + 'ﲬ' => 'خم', + 'ﲭ' => 'سج', + 'ﲮ' => 'سح', + 'ﲯ' => 'سخ', + 'ﲰ' => 'سم', + 'ﲱ' => 'صح', + 'ﲲ' => 'صخ', + 'ﲳ' => 'صم', + 'ﲴ' => 'ضج', + 'ﲵ' => 'ضح', + 'ﲶ' => 'ضخ', + 'ﲷ' => 'ضم', + 'ﲸ' => 'طح', + 'ﲹ' => 'ظم', + 'ﲺ' => 'عج', + 'ﲻ' => 'عم', + 'ﲼ' => 'غج', + 'ﲽ' => 'غم', + 'ﲾ' => 'فج', + 'ﲿ' => 'فح', + 'ﳀ' => 'فخ', + 'ﳁ' => 'فم', + 'ﳂ' => 'قح', + 'ﳃ' => 'قم', + 'ﳄ' => 'كج', + 'ﳅ' => 'كح', + 'ﳆ' => 'كخ', + 'ﳇ' => 'كل', + 'ﳈ' => 'كم', + 'ﳉ' => 'لج', + 'ﳊ' => 'لح', + 'ﳋ' => 'لخ', + 'ﳌ' => 'لم', + 'ﳍ' => 'له', + 'ﳎ' => 'مج', + 'ﳏ' => 'مح', + 'ﳐ' => 'مخ', + 'ﳑ' => 'مم', + 'ﳒ' => 'نج', + 'ﳓ' => 'نح', + 'ﳔ' => 'نخ', + 'ﳕ' => 'نم', + 'ﳖ' => 'نه', + 'ﳗ' => 'هج', + 'ﳘ' => 'هم', + 'ﳙ' => 'هٰ', + 'ﳚ' => 'يج', + 'ﳛ' => 'يح', + 'ﳜ' => 'يخ', + 'ﳝ' => 'يم', + 'ﳞ' => 'يه', + 'ﳟ' => 'ئم', + 'ﳠ' => 'ئه', + 'ﳡ' => 'بم', + 'ﳢ' => 'به', + 'ﳣ' => 'تم', + 'ﳤ' => 'ته', + 'ﳥ' => 'ثم', + 'ﳦ' => 'ثه', + 'ﳧ' => 'سم', + 'ﳨ' => 'سه', + 'ﳩ' => 'شم', + 'ﳪ' => 'شه', + 'ﳫ' => 'كل', + 'ﳬ' => 'كم', + 'ﳭ' => 'لم', + 'ﳮ' => 'نم', + 'ﳯ' => 'نه', + 'ﳰ' => 'يم', + 'ﳱ' => 'يه', + 'ﳲ' => 'ـَّ', + 'ﳳ' => 'ـُّ', + 'ﳴ' => 'ـِّ', + 'ﳵ' => 'طى', + 'ﳶ' => 'طي', + 'ﳷ' => 'عى', + 'ﳸ' => 'عي', + 'ﳹ' => 'غى', + 'ﳺ' => 'غي', + 'ﳻ' => 'سى', + 'ﳼ' => 'سي', + 'ﳽ' => 'شى', + 'ﳾ' => 'شي', + 'ﳿ' => 'حى', + 'ﴀ' => 'حي', + 'ﴁ' => 'جى', + 'ﴂ' => 'جي', + 'ﴃ' => 'خى', + 'ﴄ' => 'خي', + 'ﴅ' => 'صى', + 'ﴆ' => 'صي', + 'ﴇ' => 'ضى', + 'ﴈ' => 'ضي', + 'ﴉ' => 'شج', + 'ﴊ' => 'شح', + 'ﴋ' => 'شخ', + 'ﴌ' => 'شم', + 'ﴍ' => 'شر', + 'ﴎ' => 'سر', + 'ﴏ' => 'صر', + 'ﴐ' => 'ضر', + 'ﴑ' => 'طى', + 'ﴒ' => 'طي', + 'ﴓ' => 'عى', + 'ﴔ' => 'عي', + 'ﴕ' => 'غى', + 'ﴖ' => 'غي', + 'ﴗ' => 'سى', + 'ﴘ' => 'سي', + 'ﴙ' => 'شى', + 'ﴚ' => 'شي', + 'ﴛ' => 'حى', + 'ﴜ' => 'حي', + 'ﴝ' => 'جى', + 'ﴞ' => 'جي', + 'ﴟ' => 'خى', + 'ﴠ' => 'خي', + 'ﴡ' => 'صى', + 'ﴢ' => 'صي', + 'ﴣ' => 'ضى', + 'ﴤ' => 'ضي', + 'ﴥ' => 'شج', + 'ﴦ' => 'شح', + 'ﴧ' => 'شخ', + 'ﴨ' => 'شم', + 'ﴩ' => 'شر', + 'ﴪ' => 'سر', + 'ﴫ' => 'صر', + 'ﴬ' => 'ضر', + 'ﴭ' => 'شج', + 'ﴮ' => 'شح', + 'ﴯ' => 'شخ', + 'ﴰ' => 'شم', + 'ﴱ' => 'سه', + 'ﴲ' => 'شه', + 'ﴳ' => 'طم', + 'ﴴ' => 'سج', + 'ﴵ' => 'سح', + 'ﴶ' => 'سخ', + 'ﴷ' => 'شج', + 'ﴸ' => 'شح', + 'ﴹ' => 'شخ', + 'ﴺ' => 'طم', + 'ﴻ' => 'ظم', + 'ﴼ' => 'اً', + 'ﴽ' => 'اً', + 'ﵐ' => 'تجم', + 'ﵑ' => 'تحج', + 'ﵒ' => 'تحج', + 'ﵓ' => 'تحم', + 'ﵔ' => 'تخم', + 'ﵕ' => 'تمج', + 'ﵖ' => 'تمح', + 'ﵗ' => 'تمخ', + 'ﵘ' => 'جمح', + 'ﵙ' => 'جمح', + 'ﵚ' => 'حمي', + 'ﵛ' => 'حمى', + 'ﵜ' => 'سحج', + 'ﵝ' => 'سجح', + 'ﵞ' => 'سجى', + 'ﵟ' => 'سمح', + 'ﵠ' => 'سمح', + 'ﵡ' => 'سمج', + 'ﵢ' => 'سمم', + 'ﵣ' => 'سمم', + 'ﵤ' => 'صحح', + 'ﵥ' => 'صحح', + 'ﵦ' => 'صمم', + 'ﵧ' => 'شحم', + 'ﵨ' => 'شحم', + 'ﵩ' => 'شجي', + 'ﵪ' => 'شمخ', + 'ﵫ' => 'شمخ', + 'ﵬ' => 'شمم', + 'ﵭ' => 'شمم', + 'ﵮ' => 'ضحى', + 'ﵯ' => 'ضخم', + 'ﵰ' => 'ضخم', + 'ﵱ' => 'طمح', + 'ﵲ' => 'طمح', + 'ﵳ' => 'طمم', + 'ﵴ' => 'طمي', + 'ﵵ' => 'عجم', + 'ﵶ' => 'عمم', + 'ﵷ' => 'عمم', + 'ﵸ' => 'عمى', + 'ﵹ' => 'غمم', + 'ﵺ' => 'غمي', + 'ﵻ' => 'غمى', + 'ﵼ' => 'فخم', + 'ﵽ' => 'فخم', + 'ﵾ' => 'قمح', + 'ﵿ' => 'قمم', + 'ﶀ' => 'لحم', + 'ﶁ' => 'لحي', + 'ﶂ' => 'لحى', + 'ﶃ' => 'لجج', + 'ﶄ' => 'لجج', + 'ﶅ' => 'لخم', + 'ﶆ' => 'لخم', + 'ﶇ' => 'لمح', + 'ﶈ' => 'لمح', + 'ﶉ' => 'محج', + 'ﶊ' => 'محم', + 'ﶋ' => 'محي', + 'ﶌ' => 'مجح', + 'ﶍ' => 'مجم', + 'ﶎ' => 'مخج', + 'ﶏ' => 'مخم', + 'ﶒ' => 'مجخ', + 'ﶓ' => 'همج', + 'ﶔ' => 'همم', + 'ﶕ' => 'نحم', + 'ﶖ' => 'نحى', + 'ﶗ' => 'نجم', + 'ﶘ' => 'نجم', + 'ﶙ' => 'نجى', + 'ﶚ' => 'نمي', + 'ﶛ' => 'نمى', + 'ﶜ' => 'يمم', + 'ﶝ' => 'يمم', + 'ﶞ' => 'بخي', + 'ﶟ' => 'تجي', + 'ﶠ' => 'تجى', + 'ﶡ' => 'تخي', + 'ﶢ' => 'تخى', + 'ﶣ' => 'تمي', + 'ﶤ' => 'تمى', + 'ﶥ' => 'جمي', + 'ﶦ' => 'جحى', + 'ﶧ' => 'جمى', + 'ﶨ' => 'سخى', + 'ﶩ' => 'صحي', + 'ﶪ' => 'شحي', + 'ﶫ' => 'ضحي', + 'ﶬ' => 'لجي', + 'ﶭ' => 'لمي', + 'ﶮ' => 'يحي', + 'ﶯ' => 'يجي', + 'ﶰ' => 'يمي', + 'ﶱ' => 'ممي', + 'ﶲ' => 'قمي', + 'ﶳ' => 'نحي', + 'ﶴ' => 'قمح', + 'ﶵ' => 'لحم', + 'ﶶ' => 'عمي', + 'ﶷ' => 'كمي', + 'ﶸ' => 'نجح', + 'ﶹ' => 'مخي', + 'ﶺ' => 'لجم', + 'ﶻ' => 'كمم', + 'ﶼ' => 'لجم', + 'ﶽ' => 'نجح', + 'ﶾ' => 'جحي', + 'ﶿ' => 'حجي', + 'ﷀ' => 'مجي', + 'ﷁ' => 'فمي', + 'ﷂ' => 'بحي', + 'ﷃ' => 'كمم', + 'ﷄ' => 'عجم', + 'ﷅ' => 'صمم', + 'ﷆ' => 'سخي', + 'ﷇ' => 'نجي', + 'ﷰ' => 'صلے', + 'ﷱ' => 'قلے', + 'ﷲ' => 'الله', + 'ﷳ' => 'اكبر', + 'ﷴ' => 'محمد', + 'ﷵ' => 'صلعم', + 'ﷶ' => 'رسول', + 'ﷷ' => 'عليه', + 'ﷸ' => 'وسلم', + 'ﷹ' => 'صلى', + 'ﷺ' => 'صلى الله عليه وسلم', + 'ﷻ' => 'جل جلاله', + '﷼' => 'ریال', + '︐' => ',', + '︑' => '、', + '︒' => '。', + '︓' => ':', + '︔' => ';', + '︕' => '!', + '︖' => '?', + '︗' => '〖', + '︘' => '〗', + '︙' => '...', + '︰' => '..', + '︱' => '—', + '︲' => '–', + '︳' => '_', + '︴' => '_', + '︵' => '(', + '︶' => ')', + '︷' => '{', + '︸' => '}', + '︹' => '〔', + '︺' => '〕', + '︻' => '【', + '︼' => '】', + '︽' => '《', + '︾' => '》', + '︿' => '〈', + '﹀' => '〉', + '﹁' => '「', + '﹂' => '」', + '﹃' => '『', + '﹄' => '』', + '﹇' => '[', + '﹈' => ']', + '﹉' => ' ̅', + '﹊' => ' ̅', + '﹋' => ' ̅', + '﹌' => ' ̅', + '﹍' => '_', + '﹎' => '_', + '﹏' => '_', + '﹐' => ',', + '﹑' => '、', + '﹒' => '.', + '﹔' => ';', + '﹕' => ':', + '﹖' => '?', + '﹗' => '!', + '﹘' => '—', + '﹙' => '(', + '﹚' => ')', + '﹛' => '{', + '﹜' => '}', + '﹝' => '〔', + '﹞' => '〕', + '﹟' => '#', + '﹠' => '&', + '﹡' => '*', + '﹢' => '+', + '﹣' => '-', + '﹤' => '<', + '﹥' => '>', + '﹦' => '=', + '﹨' => '\\', + '﹩' => '$', + '﹪' => '%', + '﹫' => '@', + 'ﹰ' => ' ً', + 'ﹱ' => 'ـً', + 'ﹲ' => ' ٌ', + 'ﹴ' => ' ٍ', + 'ﹶ' => ' َ', + 'ﹷ' => 'ـَ', + 'ﹸ' => ' ُ', + 'ﹹ' => 'ـُ', + 'ﹺ' => ' ِ', + 'ﹻ' => 'ـِ', + 'ﹼ' => ' ّ', + 'ﹽ' => 'ـّ', + 'ﹾ' => ' ْ', + 'ﹿ' => 'ـْ', + 'ﺀ' => 'ء', + 'ﺁ' => 'آ', + 'ﺂ' => 'آ', + 'ﺃ' => 'أ', + 'ﺄ' => 'أ', + 'ﺅ' => 'ؤ', + 'ﺆ' => 'ؤ', + 'ﺇ' => 'إ', + 'ﺈ' => 'إ', + 'ﺉ' => 'ئ', + 'ﺊ' => 'ئ', + 'ﺋ' => 'ئ', + 'ﺌ' => 'ئ', + 'ﺍ' => 'ا', + 'ﺎ' => 'ا', + 'ﺏ' => 'ب', + 'ﺐ' => 'ب', + 'ﺑ' => 'ب', + 'ﺒ' => 'ب', + 'ﺓ' => 'ة', + 'ﺔ' => 'ة', + 'ﺕ' => 'ت', + 'ﺖ' => 'ت', + 'ﺗ' => 'ت', + 'ﺘ' => 'ت', + 'ﺙ' => 'ث', + 'ﺚ' => 'ث', + 'ﺛ' => 'ث', + 'ﺜ' => 'ث', + 'ﺝ' => 'ج', + 'ﺞ' => 'ج', + 'ﺟ' => 'ج', + 'ﺠ' => 'ج', + 'ﺡ' => 'ح', + 'ﺢ' => 'ح', + 'ﺣ' => 'ح', + 'ﺤ' => 'ح', + 'ﺥ' => 'خ', + 'ﺦ' => 'خ', + 'ﺧ' => 'خ', + 'ﺨ' => 'خ', + 'ﺩ' => 'د', + 'ﺪ' => 'د', + 'ﺫ' => 'ذ', + 'ﺬ' => 'ذ', + 'ﺭ' => 'ر', + 'ﺮ' => 'ر', + 'ﺯ' => 'ز', + 'ﺰ' => 'ز', + 'ﺱ' => 'س', + 'ﺲ' => 'س', + 'ﺳ' => 'س', + 'ﺴ' => 'س', + 'ﺵ' => 'ش', + 'ﺶ' => 'ش', + 'ﺷ' => 'ش', + 'ﺸ' => 'ش', + 'ﺹ' => 'ص', + 'ﺺ' => 'ص', + 'ﺻ' => 'ص', + 'ﺼ' => 'ص', + 'ﺽ' => 'ض', + 'ﺾ' => 'ض', + 'ﺿ' => 'ض', + 'ﻀ' => 'ض', + 'ﻁ' => 'ط', + 'ﻂ' => 'ط', + 'ﻃ' => 'ط', + 'ﻄ' => 'ط', + 'ﻅ' => 'ظ', + 'ﻆ' => 'ظ', + 'ﻇ' => 'ظ', + 'ﻈ' => 'ظ', + 'ﻉ' => 'ع', + 'ﻊ' => 'ع', + 'ﻋ' => 'ع', + 'ﻌ' => 'ع', + 'ﻍ' => 'غ', + 'ﻎ' => 'غ', + 'ﻏ' => 'غ', + 'ﻐ' => 'غ', + 'ﻑ' => 'ف', + 'ﻒ' => 'ف', + 'ﻓ' => 'ف', + 'ﻔ' => 'ف', + 'ﻕ' => 'ق', + 'ﻖ' => 'ق', + 'ﻗ' => 'ق', + 'ﻘ' => 'ق', + 'ﻙ' => 'ك', + 'ﻚ' => 'ك', + 'ﻛ' => 'ك', + 'ﻜ' => 'ك', + 'ﻝ' => 'ل', + 'ﻞ' => 'ل', + 'ﻟ' => 'ل', + 'ﻠ' => 'ل', + 'ﻡ' => 'م', + 'ﻢ' => 'م', + 'ﻣ' => 'م', + 'ﻤ' => 'م', + 'ﻥ' => 'ن', + 'ﻦ' => 'ن', + 'ﻧ' => 'ن', + 'ﻨ' => 'ن', + 'ﻩ' => 'ه', + 'ﻪ' => 'ه', + 'ﻫ' => 'ه', + 'ﻬ' => 'ه', + 'ﻭ' => 'و', + 'ﻮ' => 'و', + 'ﻯ' => 'ى', + 'ﻰ' => 'ى', + 'ﻱ' => 'ي', + 'ﻲ' => 'ي', + 'ﻳ' => 'ي', + 'ﻴ' => 'ي', + 'ﻵ' => 'لآ', + 'ﻶ' => 'لآ', + 'ﻷ' => 'لأ', + 'ﻸ' => 'لأ', + 'ﻹ' => 'لإ', + 'ﻺ' => 'لإ', + 'ﻻ' => 'لا', + 'ﻼ' => 'لا', + '!' => '!', + '"' => '"', + '#' => '#', + '$' => '$', + '%' => '%', + '&' => '&', + ''' => '\'', + '(' => '(', + ')' => ')', + '*' => '*', + '+' => '+', + ',' => ',', + '-' => '-', + '.' => '.', + '/' => '/', + '0' => '0', + '1' => '1', + '2' => '2', + '3' => '3', + '4' => '4', + '5' => '5', + '6' => '6', + '7' => '7', + '8' => '8', + '9' => '9', + ':' => ':', + ';' => ';', + '<' => '<', + '=' => '=', + '>' => '>', + '?' => '?', + '@' => '@', + 'A' => 'A', + 'B' => 'B', + 'C' => 'C', + 'D' => 'D', + 'E' => 'E', + 'F' => 'F', + 'G' => 'G', + 'H' => 'H', + 'I' => 'I', + 'J' => 'J', + 'K' => 'K', + 'L' => 'L', + 'M' => 'M', + 'N' => 'N', + 'O' => 'O', + 'P' => 'P', + 'Q' => 'Q', + 'R' => 'R', + 'S' => 'S', + 'T' => 'T', + 'U' => 'U', + 'V' => 'V', + 'W' => 'W', + 'X' => 'X', + 'Y' => 'Y', + 'Z' => 'Z', + '[' => '[', + '\' => '\\', + ']' => ']', + '^' => '^', + '_' => '_', + '`' => '`', + 'a' => 'a', + 'b' => 'b', + 'c' => 'c', + 'd' => 'd', + 'e' => 'e', + 'f' => 'f', + 'g' => 'g', + 'h' => 'h', + 'i' => 'i', + 'j' => 'j', + 'k' => 'k', + 'l' => 'l', + 'm' => 'm', + 'n' => 'n', + 'o' => 'o', + 'p' => 'p', + 'q' => 'q', + 'r' => 'r', + 's' => 's', + 't' => 't', + 'u' => 'u', + 'v' => 'v', + 'w' => 'w', + 'x' => 'x', + 'y' => 'y', + 'z' => 'z', + '{' => '{', + '|' => '|', + '}' => '}', + '~' => '~', + '⦅' => '⦅', + '⦆' => '⦆', + '。' => '。', + '「' => '「', + '」' => '」', + '、' => '、', + '・' => '・', + 'ヲ' => 'ヲ', + 'ァ' => 'ァ', + 'ィ' => 'ィ', + 'ゥ' => 'ゥ', + 'ェ' => 'ェ', + 'ォ' => 'ォ', + 'ャ' => 'ャ', + 'ュ' => 'ュ', + 'ョ' => 'ョ', + 'ッ' => 'ッ', + 'ー' => 'ー', + 'ア' => 'ア', + 'イ' => 'イ', + 'ウ' => 'ウ', + 'エ' => 'エ', + 'オ' => 'オ', + 'カ' => 'カ', + 'キ' => 'キ', + 'ク' => 'ク', + 'ケ' => 'ケ', + 'コ' => 'コ', + 'サ' => 'サ', + 'シ' => 'シ', + 'ス' => 'ス', + 'セ' => 'セ', + 'ソ' => 'ソ', + 'タ' => 'タ', + 'チ' => 'チ', + 'ツ' => 'ツ', + 'テ' => 'テ', + 'ト' => 'ト', + 'ナ' => 'ナ', + 'ニ' => 'ニ', + 'ヌ' => 'ヌ', + 'ネ' => 'ネ', + 'ノ' => 'ノ', + 'ハ' => 'ハ', + 'ヒ' => 'ヒ', + 'フ' => 'フ', + 'ヘ' => 'ヘ', + 'ホ' => 'ホ', + 'マ' => 'マ', + 'ミ' => 'ミ', + 'ム' => 'ム', + 'メ' => 'メ', + 'モ' => 'モ', + 'ヤ' => 'ヤ', + 'ユ' => 'ユ', + 'ヨ' => 'ヨ', + 'ラ' => 'ラ', + 'リ' => 'リ', + 'ル' => 'ル', + 'レ' => 'レ', + 'ロ' => 'ロ', + 'ワ' => 'ワ', + 'ン' => 'ン', + '゙' => '゙', + '゚' => '゚', + 'ᅠ' => 'ᅠ', + 'ᄀ' => 'ᄀ', + 'ᄁ' => 'ᄁ', + 'ᆪ' => 'ᆪ', + 'ᄂ' => 'ᄂ', + 'ᆬ' => 'ᆬ', + 'ᆭ' => 'ᆭ', + 'ᄃ' => 'ᄃ', + 'ᄄ' => 'ᄄ', + 'ᄅ' => 'ᄅ', + 'ᆰ' => 'ᆰ', + 'ᆱ' => 'ᆱ', + 'ᆲ' => 'ᆲ', + 'ᆳ' => 'ᆳ', + 'ᆴ' => 'ᆴ', + 'ᆵ' => 'ᆵ', + 'ᄚ' => 'ᄚ', + 'ᄆ' => 'ᄆ', + 'ᄇ' => 'ᄇ', + 'ᄈ' => 'ᄈ', + 'ᄡ' => 'ᄡ', + 'ᄉ' => 'ᄉ', + 'ᄊ' => 'ᄊ', + 'ᄋ' => 'ᄋ', + 'ᄌ' => 'ᄌ', + 'ᄍ' => 'ᄍ', + 'ᄎ' => 'ᄎ', + 'ᄏ' => 'ᄏ', + 'ᄐ' => 'ᄐ', + 'ᄑ' => 'ᄑ', + 'ᄒ' => 'ᄒ', + 'ᅡ' => 'ᅡ', + 'ᅢ' => 'ᅢ', + 'ᅣ' => 'ᅣ', + 'ᅤ' => 'ᅤ', + 'ᅥ' => 'ᅥ', + 'ᅦ' => 'ᅦ', + 'ᅧ' => 'ᅧ', + 'ᅨ' => 'ᅨ', + 'ᅩ' => 'ᅩ', + 'ᅪ' => 'ᅪ', + 'ᅫ' => 'ᅫ', + 'ᅬ' => 'ᅬ', + 'ᅭ' => 'ᅭ', + 'ᅮ' => 'ᅮ', + 'ᅯ' => 'ᅯ', + 'ᅰ' => 'ᅰ', + 'ᅱ' => 'ᅱ', + 'ᅲ' => 'ᅲ', + 'ᅳ' => 'ᅳ', + 'ᅴ' => 'ᅴ', + 'ᅵ' => 'ᅵ', + '¢' => '¢', + '£' => '£', + '¬' => '¬', + ' ̄' => ' ̄', + '¦' => '¦', + '¥' => '¥', + '₩' => '₩', + '│' => '│', + '←' => '←', + '↑' => '↑', + '→' => '→', + '↓' => '↓', + '■' => '■', + '○' => '○', + '𝐀' => 'A', + '𝐁' => 'B', + '𝐂' => 'C', + '𝐃' => 'D', + '𝐄' => 'E', + '𝐅' => 'F', + '𝐆' => 'G', + '𝐇' => 'H', + '𝐈' => 'I', + '𝐉' => 'J', + '𝐊' => 'K', + '𝐋' => 'L', + '𝐌' => 'M', + '𝐍' => 'N', + '𝐎' => 'O', + '𝐏' => 'P', + '𝐐' => 'Q', + '𝐑' => 'R', + '𝐒' => 'S', + '𝐓' => 'T', + '𝐔' => 'U', + '𝐕' => 'V', + '𝐖' => 'W', + '𝐗' => 'X', + '𝐘' => 'Y', + '𝐙' => 'Z', + '𝐚' => 'a', + '𝐛' => 'b', + '𝐜' => 'c', + '𝐝' => 'd', + '𝐞' => 'e', + '𝐟' => 'f', + '𝐠' => 'g', + '𝐡' => 'h', + '𝐢' => 'i', + '𝐣' => 'j', + '𝐤' => 'k', + '𝐥' => 'l', + '𝐦' => 'm', + '𝐧' => 'n', + '𝐨' => 'o', + '𝐩' => 'p', + '𝐪' => 'q', + '𝐫' => 'r', + '𝐬' => 's', + '𝐭' => 't', + '𝐮' => 'u', + '𝐯' => 'v', + '𝐰' => 'w', + '𝐱' => 'x', + '𝐲' => 'y', + '𝐳' => 'z', + '𝐴' => 'A', + '𝐵' => 'B', + '𝐶' => 'C', + '𝐷' => 'D', + '𝐸' => 'E', + '𝐹' => 'F', + '𝐺' => 'G', + '𝐻' => 'H', + '𝐼' => 'I', + '𝐽' => 'J', + '𝐾' => 'K', + '𝐿' => 'L', + '𝑀' => 'M', + '𝑁' => 'N', + '𝑂' => 'O', + '𝑃' => 'P', + '𝑄' => 'Q', + '𝑅' => 'R', + '𝑆' => 'S', + '𝑇' => 'T', + '𝑈' => 'U', + '𝑉' => 'V', + '𝑊' => 'W', + '𝑋' => 'X', + '𝑌' => 'Y', + '𝑍' => 'Z', + '𝑎' => 'a', + '𝑏' => 'b', + '𝑐' => 'c', + '𝑑' => 'd', + '𝑒' => 'e', + '𝑓' => 'f', + '𝑔' => 'g', + '𝑖' => 'i', + '𝑗' => 'j', + '𝑘' => 'k', + '𝑙' => 'l', + '𝑚' => 'm', + '𝑛' => 'n', + '𝑜' => 'o', + '𝑝' => 'p', + '𝑞' => 'q', + '𝑟' => 'r', + '𝑠' => 's', + '𝑡' => 't', + '𝑢' => 'u', + '𝑣' => 'v', + '𝑤' => 'w', + '𝑥' => 'x', + '𝑦' => 'y', + '𝑧' => 'z', + '𝑨' => 'A', + '𝑩' => 'B', + '𝑪' => 'C', + '𝑫' => 'D', + '𝑬' => 'E', + '𝑭' => 'F', + '𝑮' => 'G', + '𝑯' => 'H', + '𝑰' => 'I', + '𝑱' => 'J', + '𝑲' => 'K', + '𝑳' => 'L', + '𝑴' => 'M', + '𝑵' => 'N', + '𝑶' => 'O', + '𝑷' => 'P', + '𝑸' => 'Q', + '𝑹' => 'R', + '𝑺' => 'S', + '𝑻' => 'T', + '𝑼' => 'U', + '𝑽' => 'V', + '𝑾' => 'W', + '𝑿' => 'X', + '𝒀' => 'Y', + '𝒁' => 'Z', + '𝒂' => 'a', + '𝒃' => 'b', + '𝒄' => 'c', + '𝒅' => 'd', + '𝒆' => 'e', + '𝒇' => 'f', + '𝒈' => 'g', + '𝒉' => 'h', + '𝒊' => 'i', + '𝒋' => 'j', + '𝒌' => 'k', + '𝒍' => 'l', + '𝒎' => 'm', + '𝒏' => 'n', + '𝒐' => 'o', + '𝒑' => 'p', + '𝒒' => 'q', + '𝒓' => 'r', + '𝒔' => 's', + '𝒕' => 't', + '𝒖' => 'u', + '𝒗' => 'v', + '𝒘' => 'w', + '𝒙' => 'x', + '𝒚' => 'y', + '𝒛' => 'z', + '𝒜' => 'A', + '𝒞' => 'C', + '𝒟' => 'D', + '𝒢' => 'G', + '𝒥' => 'J', + '𝒦' => 'K', + '𝒩' => 'N', + '𝒪' => 'O', + '𝒫' => 'P', + '𝒬' => 'Q', + '𝒮' => 'S', + '𝒯' => 'T', + '𝒰' => 'U', + '𝒱' => 'V', + '𝒲' => 'W', + '𝒳' => 'X', + '𝒴' => 'Y', + '𝒵' => 'Z', + '𝒶' => 'a', + '𝒷' => 'b', + '𝒸' => 'c', + '𝒹' => 'd', + '𝒻' => 'f', + '𝒽' => 'h', + '𝒾' => 'i', + '𝒿' => 'j', + '𝓀' => 'k', + '𝓁' => 'l', + '𝓂' => 'm', + '𝓃' => 'n', + '𝓅' => 'p', + '𝓆' => 'q', + '𝓇' => 'r', + '𝓈' => 's', + '𝓉' => 't', + '𝓊' => 'u', + '𝓋' => 'v', + '𝓌' => 'w', + '𝓍' => 'x', + '𝓎' => 'y', + '𝓏' => 'z', + '𝓐' => 'A', + '𝓑' => 'B', + '𝓒' => 'C', + '𝓓' => 'D', + '𝓔' => 'E', + '𝓕' => 'F', + '𝓖' => 'G', + '𝓗' => 'H', + '𝓘' => 'I', + '𝓙' => 'J', + '𝓚' => 'K', + '𝓛' => 'L', + '𝓜' => 'M', + '𝓝' => 'N', + '𝓞' => 'O', + '𝓟' => 'P', + '𝓠' => 'Q', + '𝓡' => 'R', + '𝓢' => 'S', + '𝓣' => 'T', + '𝓤' => 'U', + '𝓥' => 'V', + '𝓦' => 'W', + '𝓧' => 'X', + '𝓨' => 'Y', + '𝓩' => 'Z', + '𝓪' => 'a', + '𝓫' => 'b', + '𝓬' => 'c', + '𝓭' => 'd', + '𝓮' => 'e', + '𝓯' => 'f', + '𝓰' => 'g', + '𝓱' => 'h', + '𝓲' => 'i', + '𝓳' => 'j', + '𝓴' => 'k', + '𝓵' => 'l', + '𝓶' => 'm', + '𝓷' => 'n', + '𝓸' => 'o', + '𝓹' => 'p', + '𝓺' => 'q', + '𝓻' => 'r', + '𝓼' => 's', + '𝓽' => 't', + '𝓾' => 'u', + '𝓿' => 'v', + '𝔀' => 'w', + '𝔁' => 'x', + '𝔂' => 'y', + '𝔃' => 'z', + '𝔄' => 'A', + '𝔅' => 'B', + '𝔇' => 'D', + '𝔈' => 'E', + '𝔉' => 'F', + '𝔊' => 'G', + '𝔍' => 'J', + '𝔎' => 'K', + '𝔏' => 'L', + '𝔐' => 'M', + '𝔑' => 'N', + '𝔒' => 'O', + '𝔓' => 'P', + '𝔔' => 'Q', + '𝔖' => 'S', + '𝔗' => 'T', + '𝔘' => 'U', + '𝔙' => 'V', + '𝔚' => 'W', + '𝔛' => 'X', + '𝔜' => 'Y', + '𝔞' => 'a', + '𝔟' => 'b', + '𝔠' => 'c', + '𝔡' => 'd', + '𝔢' => 'e', + '𝔣' => 'f', + '𝔤' => 'g', + '𝔥' => 'h', + '𝔦' => 'i', + '𝔧' => 'j', + '𝔨' => 'k', + '𝔩' => 'l', + '𝔪' => 'm', + '𝔫' => 'n', + '𝔬' => 'o', + '𝔭' => 'p', + '𝔮' => 'q', + '𝔯' => 'r', + '𝔰' => 's', + '𝔱' => 't', + '𝔲' => 'u', + '𝔳' => 'v', + '𝔴' => 'w', + '𝔵' => 'x', + '𝔶' => 'y', + '𝔷' => 'z', + '𝔸' => 'A', + '𝔹' => 'B', + '𝔻' => 'D', + '𝔼' => 'E', + '𝔽' => 'F', + '𝔾' => 'G', + '𝕀' => 'I', + '𝕁' => 'J', + '𝕂' => 'K', + '𝕃' => 'L', + '𝕄' => 'M', + '𝕆' => 'O', + '𝕊' => 'S', + '𝕋' => 'T', + '𝕌' => 'U', + '𝕍' => 'V', + '𝕎' => 'W', + '𝕏' => 'X', + '𝕐' => 'Y', + '𝕒' => 'a', + '𝕓' => 'b', + '𝕔' => 'c', + '𝕕' => 'd', + '𝕖' => 'e', + '𝕗' => 'f', + '𝕘' => 'g', + '𝕙' => 'h', + '𝕚' => 'i', + '𝕛' => 'j', + '𝕜' => 'k', + '𝕝' => 'l', + '𝕞' => 'm', + '𝕟' => 'n', + '𝕠' => 'o', + '𝕡' => 'p', + '𝕢' => 'q', + '𝕣' => 'r', + '𝕤' => 's', + '𝕥' => 't', + '𝕦' => 'u', + '𝕧' => 'v', + '𝕨' => 'w', + '𝕩' => 'x', + '𝕪' => 'y', + '𝕫' => 'z', + '𝕬' => 'A', + '𝕭' => 'B', + '𝕮' => 'C', + '𝕯' => 'D', + '𝕰' => 'E', + '𝕱' => 'F', + '𝕲' => 'G', + '𝕳' => 'H', + '𝕴' => 'I', + '𝕵' => 'J', + '𝕶' => 'K', + '𝕷' => 'L', + '𝕸' => 'M', + '𝕹' => 'N', + '𝕺' => 'O', + '𝕻' => 'P', + '𝕼' => 'Q', + '𝕽' => 'R', + '𝕾' => 'S', + '𝕿' => 'T', + '𝖀' => 'U', + '𝖁' => 'V', + '𝖂' => 'W', + '𝖃' => 'X', + '𝖄' => 'Y', + '𝖅' => 'Z', + '𝖆' => 'a', + '𝖇' => 'b', + '𝖈' => 'c', + '𝖉' => 'd', + '𝖊' => 'e', + '𝖋' => 'f', + '𝖌' => 'g', + '𝖍' => 'h', + '𝖎' => 'i', + '𝖏' => 'j', + '𝖐' => 'k', + '𝖑' => 'l', + '𝖒' => 'm', + '𝖓' => 'n', + '𝖔' => 'o', + '𝖕' => 'p', + '𝖖' => 'q', + '𝖗' => 'r', + '𝖘' => 's', + '𝖙' => 't', + '𝖚' => 'u', + '𝖛' => 'v', + '𝖜' => 'w', + '𝖝' => 'x', + '𝖞' => 'y', + '𝖟' => 'z', + '𝖠' => 'A', + '𝖡' => 'B', + '𝖢' => 'C', + '𝖣' => 'D', + '𝖤' => 'E', + '𝖥' => 'F', + '𝖦' => 'G', + '𝖧' => 'H', + '𝖨' => 'I', + '𝖩' => 'J', + '𝖪' => 'K', + '𝖫' => 'L', + '𝖬' => 'M', + '𝖭' => 'N', + '𝖮' => 'O', + '𝖯' => 'P', + '𝖰' => 'Q', + '𝖱' => 'R', + '𝖲' => 'S', + '𝖳' => 'T', + '𝖴' => 'U', + '𝖵' => 'V', + '𝖶' => 'W', + '𝖷' => 'X', + '𝖸' => 'Y', + '𝖹' => 'Z', + '𝖺' => 'a', + '𝖻' => 'b', + '𝖼' => 'c', + '𝖽' => 'd', + '𝖾' => 'e', + '𝖿' => 'f', + '𝗀' => 'g', + '𝗁' => 'h', + '𝗂' => 'i', + '𝗃' => 'j', + '𝗄' => 'k', + '𝗅' => 'l', + '𝗆' => 'm', + '𝗇' => 'n', + '𝗈' => 'o', + '𝗉' => 'p', + '𝗊' => 'q', + '𝗋' => 'r', + '𝗌' => 's', + '𝗍' => 't', + '𝗎' => 'u', + '𝗏' => 'v', + '𝗐' => 'w', + '𝗑' => 'x', + '𝗒' => 'y', + '𝗓' => 'z', + '𝗔' => 'A', + '𝗕' => 'B', + '𝗖' => 'C', + '𝗗' => 'D', + '𝗘' => 'E', + '𝗙' => 'F', + '𝗚' => 'G', + '𝗛' => 'H', + '𝗜' => 'I', + '𝗝' => 'J', + '𝗞' => 'K', + '𝗟' => 'L', + '𝗠' => 'M', + '𝗡' => 'N', + '𝗢' => 'O', + '𝗣' => 'P', + '𝗤' => 'Q', + '𝗥' => 'R', + '𝗦' => 'S', + '𝗧' => 'T', + '𝗨' => 'U', + '𝗩' => 'V', + '𝗪' => 'W', + '𝗫' => 'X', + '𝗬' => 'Y', + '𝗭' => 'Z', + '𝗮' => 'a', + '𝗯' => 'b', + '𝗰' => 'c', + '𝗱' => 'd', + '𝗲' => 'e', + '𝗳' => 'f', + '𝗴' => 'g', + '𝗵' => 'h', + '𝗶' => 'i', + '𝗷' => 'j', + '𝗸' => 'k', + '𝗹' => 'l', + '𝗺' => 'm', + '𝗻' => 'n', + '𝗼' => 'o', + '𝗽' => 'p', + '𝗾' => 'q', + '𝗿' => 'r', + '𝘀' => 's', + '𝘁' => 't', + '𝘂' => 'u', + '𝘃' => 'v', + '𝘄' => 'w', + '𝘅' => 'x', + '𝘆' => 'y', + '𝘇' => 'z', + '𝘈' => 'A', + '𝘉' => 'B', + '𝘊' => 'C', + '𝘋' => 'D', + '𝘌' => 'E', + '𝘍' => 'F', + '𝘎' => 'G', + '𝘏' => 'H', + '𝘐' => 'I', + '𝘑' => 'J', + '𝘒' => 'K', + '𝘓' => 'L', + '𝘔' => 'M', + '𝘕' => 'N', + '𝘖' => 'O', + '𝘗' => 'P', + '𝘘' => 'Q', + '𝘙' => 'R', + '𝘚' => 'S', + '𝘛' => 'T', + '𝘜' => 'U', + '𝘝' => 'V', + '𝘞' => 'W', + '𝘟' => 'X', + '𝘠' => 'Y', + '𝘡' => 'Z', + '𝘢' => 'a', + '𝘣' => 'b', + '𝘤' => 'c', + '𝘥' => 'd', + '𝘦' => 'e', + '𝘧' => 'f', + '𝘨' => 'g', + '𝘩' => 'h', + '𝘪' => 'i', + '𝘫' => 'j', + '𝘬' => 'k', + '𝘭' => 'l', + '𝘮' => 'm', + '𝘯' => 'n', + '𝘰' => 'o', + '𝘱' => 'p', + '𝘲' => 'q', + '𝘳' => 'r', + '𝘴' => 's', + '𝘵' => 't', + '𝘶' => 'u', + '𝘷' => 'v', + '𝘸' => 'w', + '𝘹' => 'x', + '𝘺' => 'y', + '𝘻' => 'z', + '𝘼' => 'A', + '𝘽' => 'B', + '𝘾' => 'C', + '𝘿' => 'D', + '𝙀' => 'E', + '𝙁' => 'F', + '𝙂' => 'G', + '𝙃' => 'H', + '𝙄' => 'I', + '𝙅' => 'J', + '𝙆' => 'K', + '𝙇' => 'L', + '𝙈' => 'M', + '𝙉' => 'N', + '𝙊' => 'O', + '𝙋' => 'P', + '𝙌' => 'Q', + '𝙍' => 'R', + '𝙎' => 'S', + '𝙏' => 'T', + '𝙐' => 'U', + '𝙑' => 'V', + '𝙒' => 'W', + '𝙓' => 'X', + '𝙔' => 'Y', + '𝙕' => 'Z', + '𝙖' => 'a', + '𝙗' => 'b', + '𝙘' => 'c', + '𝙙' => 'd', + '𝙚' => 'e', + '𝙛' => 'f', + '𝙜' => 'g', + '𝙝' => 'h', + '𝙞' => 'i', + '𝙟' => 'j', + '𝙠' => 'k', + '𝙡' => 'l', + '𝙢' => 'm', + '𝙣' => 'n', + '𝙤' => 'o', + '𝙥' => 'p', + '𝙦' => 'q', + '𝙧' => 'r', + '𝙨' => 's', + '𝙩' => 't', + '𝙪' => 'u', + '𝙫' => 'v', + '𝙬' => 'w', + '𝙭' => 'x', + '𝙮' => 'y', + '𝙯' => 'z', + '𝙰' => 'A', + '𝙱' => 'B', + '𝙲' => 'C', + '𝙳' => 'D', + '𝙴' => 'E', + '𝙵' => 'F', + '𝙶' => 'G', + '𝙷' => 'H', + '𝙸' => 'I', + '𝙹' => 'J', + '𝙺' => 'K', + '𝙻' => 'L', + '𝙼' => 'M', + '𝙽' => 'N', + '𝙾' => 'O', + '𝙿' => 'P', + '𝚀' => 'Q', + '𝚁' => 'R', + '𝚂' => 'S', + '𝚃' => 'T', + '𝚄' => 'U', + '𝚅' => 'V', + '𝚆' => 'W', + '𝚇' => 'X', + '𝚈' => 'Y', + '𝚉' => 'Z', + '𝚊' => 'a', + '𝚋' => 'b', + '𝚌' => 'c', + '𝚍' => 'd', + '𝚎' => 'e', + '𝚏' => 'f', + '𝚐' => 'g', + '𝚑' => 'h', + '𝚒' => 'i', + '𝚓' => 'j', + '𝚔' => 'k', + '𝚕' => 'l', + '𝚖' => 'm', + '𝚗' => 'n', + '𝚘' => 'o', + '𝚙' => 'p', + '𝚚' => 'q', + '𝚛' => 'r', + '𝚜' => 's', + '𝚝' => 't', + '𝚞' => 'u', + '𝚟' => 'v', + '𝚠' => 'w', + '𝚡' => 'x', + '𝚢' => 'y', + '𝚣' => 'z', + '𝚤' => 'ı', + '𝚥' => 'ȷ', + '𝚨' => 'Α', + '𝚩' => 'Β', + '𝚪' => 'Γ', + '𝚫' => 'Δ', + '𝚬' => 'Ε', + '𝚭' => 'Ζ', + '𝚮' => 'Η', + '𝚯' => 'Θ', + '𝚰' => 'Ι', + '𝚱' => 'Κ', + '𝚲' => 'Λ', + '𝚳' => 'Μ', + '𝚴' => 'Ν', + '𝚵' => 'Ξ', + '𝚶' => 'Ο', + '𝚷' => 'Π', + '𝚸' => 'Ρ', + '𝚹' => 'Θ', + '𝚺' => 'Σ', + '𝚻' => 'Τ', + '𝚼' => 'Υ', + '𝚽' => 'Φ', + '𝚾' => 'Χ', + '𝚿' => 'Ψ', + '𝛀' => 'Ω', + '𝛁' => '∇', + '𝛂' => 'α', + '𝛃' => 'β', + '𝛄' => 'γ', + '𝛅' => 'δ', + '𝛆' => 'ε', + '𝛇' => 'ζ', + '𝛈' => 'η', + '𝛉' => 'θ', + '𝛊' => 'ι', + '𝛋' => 'κ', + '𝛌' => 'λ', + '𝛍' => 'μ', + '𝛎' => 'ν', + '𝛏' => 'ξ', + '𝛐' => 'ο', + '𝛑' => 'π', + '𝛒' => 'ρ', + '𝛓' => 'ς', + '𝛔' => 'σ', + '𝛕' => 'τ', + '𝛖' => 'υ', + '𝛗' => 'φ', + '𝛘' => 'χ', + '𝛙' => 'ψ', + '𝛚' => 'ω', + '𝛛' => '∂', + '𝛜' => 'ε', + '𝛝' => 'θ', + '𝛞' => 'κ', + '𝛟' => 'φ', + '𝛠' => 'ρ', + '𝛡' => 'π', + '𝛢' => 'Α', + '𝛣' => 'Β', + '𝛤' => 'Γ', + '𝛥' => 'Δ', + '𝛦' => 'Ε', + '𝛧' => 'Ζ', + '𝛨' => 'Η', + '𝛩' => 'Θ', + '𝛪' => 'Ι', + '𝛫' => 'Κ', + '𝛬' => 'Λ', + '𝛭' => 'Μ', + '𝛮' => 'Ν', + '𝛯' => 'Ξ', + '𝛰' => 'Ο', + '𝛱' => 'Π', + '𝛲' => 'Ρ', + '𝛳' => 'Θ', + '𝛴' => 'Σ', + '𝛵' => 'Τ', + '𝛶' => 'Υ', + '𝛷' => 'Φ', + '𝛸' => 'Χ', + '𝛹' => 'Ψ', + '𝛺' => 'Ω', + '𝛻' => '∇', + '𝛼' => 'α', + '𝛽' => 'β', + '𝛾' => 'γ', + '𝛿' => 'δ', + '𝜀' => 'ε', + '𝜁' => 'ζ', + '𝜂' => 'η', + '𝜃' => 'θ', + '𝜄' => 'ι', + '𝜅' => 'κ', + '𝜆' => 'λ', + '𝜇' => 'μ', + '𝜈' => 'ν', + '𝜉' => 'ξ', + '𝜊' => 'ο', + '𝜋' => 'π', + '𝜌' => 'ρ', + '𝜍' => 'ς', + '𝜎' => 'σ', + '𝜏' => 'τ', + '𝜐' => 'υ', + '𝜑' => 'φ', + '𝜒' => 'χ', + '𝜓' => 'ψ', + '𝜔' => 'ω', + '𝜕' => '∂', + '𝜖' => 'ε', + '𝜗' => 'θ', + '𝜘' => 'κ', + '𝜙' => 'φ', + '𝜚' => 'ρ', + '𝜛' => 'π', + '𝜜' => 'Α', + '𝜝' => 'Β', + '𝜞' => 'Γ', + '𝜟' => 'Δ', + '𝜠' => 'Ε', + '𝜡' => 'Ζ', + '𝜢' => 'Η', + '𝜣' => 'Θ', + '𝜤' => 'Ι', + '𝜥' => 'Κ', + '𝜦' => 'Λ', + '𝜧' => 'Μ', + '𝜨' => 'Ν', + '𝜩' => 'Ξ', + '𝜪' => 'Ο', + '𝜫' => 'Π', + '𝜬' => 'Ρ', + '𝜭' => 'Θ', + '𝜮' => 'Σ', + '𝜯' => 'Τ', + '𝜰' => 'Υ', + '𝜱' => 'Φ', + '𝜲' => 'Χ', + '𝜳' => 'Ψ', + '𝜴' => 'Ω', + '𝜵' => '∇', + '𝜶' => 'α', + '𝜷' => 'β', + '𝜸' => 'γ', + '𝜹' => 'δ', + '𝜺' => 'ε', + '𝜻' => 'ζ', + '𝜼' => 'η', + '𝜽' => 'θ', + '𝜾' => 'ι', + '𝜿' => 'κ', + '𝝀' => 'λ', + '𝝁' => 'μ', + '𝝂' => 'ν', + '𝝃' => 'ξ', + '𝝄' => 'ο', + '𝝅' => 'π', + '𝝆' => 'ρ', + '𝝇' => 'ς', + '𝝈' => 'σ', + '𝝉' => 'τ', + '𝝊' => 'υ', + '𝝋' => 'φ', + '𝝌' => 'χ', + '𝝍' => 'ψ', + '𝝎' => 'ω', + '𝝏' => '∂', + '𝝐' => 'ε', + '𝝑' => 'θ', + '𝝒' => 'κ', + '𝝓' => 'φ', + '𝝔' => 'ρ', + '𝝕' => 'π', + '𝝖' => 'Α', + '𝝗' => 'Β', + '𝝘' => 'Γ', + '𝝙' => 'Δ', + '𝝚' => 'Ε', + '𝝛' => 'Ζ', + '𝝜' => 'Η', + '𝝝' => 'Θ', + '𝝞' => 'Ι', + '𝝟' => 'Κ', + '𝝠' => 'Λ', + '𝝡' => 'Μ', + '𝝢' => 'Ν', + '𝝣' => 'Ξ', + '𝝤' => 'Ο', + '𝝥' => 'Π', + '𝝦' => 'Ρ', + '𝝧' => 'Θ', + '𝝨' => 'Σ', + '𝝩' => 'Τ', + '𝝪' => 'Υ', + '𝝫' => 'Φ', + '𝝬' => 'Χ', + '𝝭' => 'Ψ', + '𝝮' => 'Ω', + '𝝯' => '∇', + '𝝰' => 'α', + '𝝱' => 'β', + '𝝲' => 'γ', + '𝝳' => 'δ', + '𝝴' => 'ε', + '𝝵' => 'ζ', + '𝝶' => 'η', + '𝝷' => 'θ', + '𝝸' => 'ι', + '𝝹' => 'κ', + '𝝺' => 'λ', + '𝝻' => 'μ', + '𝝼' => 'ν', + '𝝽' => 'ξ', + '𝝾' => 'ο', + '𝝿' => 'π', + '𝞀' => 'ρ', + '𝞁' => 'ς', + '𝞂' => 'σ', + '𝞃' => 'τ', + '𝞄' => 'υ', + '𝞅' => 'φ', + '𝞆' => 'χ', + '𝞇' => 'ψ', + '𝞈' => 'ω', + '𝞉' => '∂', + '𝞊' => 'ε', + '𝞋' => 'θ', + '𝞌' => 'κ', + '𝞍' => 'φ', + '𝞎' => 'ρ', + '𝞏' => 'π', + '𝞐' => 'Α', + '𝞑' => 'Β', + '𝞒' => 'Γ', + '𝞓' => 'Δ', + '𝞔' => 'Ε', + '𝞕' => 'Ζ', + '𝞖' => 'Η', + '𝞗' => 'Θ', + '𝞘' => 'Ι', + '𝞙' => 'Κ', + '𝞚' => 'Λ', + '𝞛' => 'Μ', + '𝞜' => 'Ν', + '𝞝' => 'Ξ', + '𝞞' => 'Ο', + '𝞟' => 'Π', + '𝞠' => 'Ρ', + '𝞡' => 'Θ', + '𝞢' => 'Σ', + '𝞣' => 'Τ', + '𝞤' => 'Υ', + '𝞥' => 'Φ', + '𝞦' => 'Χ', + '𝞧' => 'Ψ', + '𝞨' => 'Ω', + '𝞩' => '∇', + '𝞪' => 'α', + '𝞫' => 'β', + '𝞬' => 'γ', + '𝞭' => 'δ', + '𝞮' => 'ε', + '𝞯' => 'ζ', + '𝞰' => 'η', + '𝞱' => 'θ', + '𝞲' => 'ι', + '𝞳' => 'κ', + '𝞴' => 'λ', + '𝞵' => 'μ', + '𝞶' => 'ν', + '𝞷' => 'ξ', + '𝞸' => 'ο', + '𝞹' => 'π', + '𝞺' => 'ρ', + '𝞻' => 'ς', + '𝞼' => 'σ', + '𝞽' => 'τ', + '𝞾' => 'υ', + '𝞿' => 'φ', + '𝟀' => 'χ', + '𝟁' => 'ψ', + '𝟂' => 'ω', + '𝟃' => '∂', + '𝟄' => 'ε', + '𝟅' => 'θ', + '𝟆' => 'κ', + '𝟇' => 'φ', + '𝟈' => 'ρ', + '𝟉' => 'π', + '𝟊' => 'Ϝ', + '𝟋' => 'ϝ', + '𝟎' => '0', + '𝟏' => '1', + '𝟐' => '2', + '𝟑' => '3', + '𝟒' => '4', + '𝟓' => '5', + '𝟔' => '6', + '𝟕' => '7', + '𝟖' => '8', + '𝟗' => '9', + '𝟘' => '0', + '𝟙' => '1', + '𝟚' => '2', + '𝟛' => '3', + '𝟜' => '4', + '𝟝' => '5', + '𝟞' => '6', + '𝟟' => '7', + '𝟠' => '8', + '𝟡' => '9', + '𝟢' => '0', + '𝟣' => '1', + '𝟤' => '2', + '𝟥' => '3', + '𝟦' => '4', + '𝟧' => '5', + '𝟨' => '6', + '𝟩' => '7', + '𝟪' => '8', + '𝟫' => '9', + '𝟬' => '0', + '𝟭' => '1', + '𝟮' => '2', + '𝟯' => '3', + '𝟰' => '4', + '𝟱' => '5', + '𝟲' => '6', + '𝟳' => '7', + '𝟴' => '8', + '𝟵' => '9', + '𝟶' => '0', + '𝟷' => '1', + '𝟸' => '2', + '𝟹' => '3', + '𝟺' => '4', + '𝟻' => '5', + '𝟼' => '6', + '𝟽' => '7', + '𝟾' => '8', + '𝟿' => '9', + '𞸀' => 'ا', + '𞸁' => 'ب', + '𞸂' => 'ج', + '𞸃' => 'د', + '𞸅' => 'و', + '𞸆' => 'ز', + '𞸇' => 'ح', + '𞸈' => 'ط', + '𞸉' => 'ي', + '𞸊' => 'ك', + '𞸋' => 'ل', + '𞸌' => 'م', + '𞸍' => 'ن', + '𞸎' => 'س', + '𞸏' => 'ع', + '𞸐' => 'ف', + '𞸑' => 'ص', + '𞸒' => 'ق', + '𞸓' => 'ر', + '𞸔' => 'ش', + '𞸕' => 'ت', + '𞸖' => 'ث', + '𞸗' => 'خ', + '𞸘' => 'ذ', + '𞸙' => 'ض', + '𞸚' => 'ظ', + '𞸛' => 'غ', + '𞸜' => 'ٮ', + '𞸝' => 'ں', + '𞸞' => 'ڡ', + '𞸟' => 'ٯ', + '𞸡' => 'ب', + '𞸢' => 'ج', + '𞸤' => 'ه', + '𞸧' => 'ح', + '𞸩' => 'ي', + '𞸪' => 'ك', + '𞸫' => 'ل', + '𞸬' => 'م', + '𞸭' => 'ن', + '𞸮' => 'س', + '𞸯' => 'ع', + '𞸰' => 'ف', + '𞸱' => 'ص', + '𞸲' => 'ق', + '𞸴' => 'ش', + '𞸵' => 'ت', + '𞸶' => 'ث', + '𞸷' => 'خ', + '𞸹' => 'ض', + '𞸻' => 'غ', + '𞹂' => 'ج', + '𞹇' => 'ح', + '𞹉' => 'ي', + '𞹋' => 'ل', + '𞹍' => 'ن', + '𞹎' => 'س', + '𞹏' => 'ع', + '𞹑' => 'ص', + '𞹒' => 'ق', + '𞹔' => 'ش', + '𞹗' => 'خ', + '𞹙' => 'ض', + '𞹛' => 'غ', + '𞹝' => 'ں', + '𞹟' => 'ٯ', + '𞹡' => 'ب', + '𞹢' => 'ج', + '𞹤' => 'ه', + '𞹧' => 'ح', + '𞹨' => 'ط', + '𞹩' => 'ي', + '𞹪' => 'ك', + '𞹬' => 'م', + '𞹭' => 'ن', + '𞹮' => 'س', + '𞹯' => 'ع', + '𞹰' => 'ف', + '𞹱' => 'ص', + '𞹲' => 'ق', + '𞹴' => 'ش', + '𞹵' => 'ت', + '𞹶' => 'ث', + '𞹷' => 'خ', + '𞹹' => 'ض', + '𞹺' => 'ظ', + '𞹻' => 'غ', + '𞹼' => 'ٮ', + '𞹾' => 'ڡ', + '𞺀' => 'ا', + '𞺁' => 'ب', + '𞺂' => 'ج', + '𞺃' => 'د', + '𞺄' => 'ه', + '𞺅' => 'و', + '𞺆' => 'ز', + '𞺇' => 'ح', + '𞺈' => 'ط', + '𞺉' => 'ي', + '𞺋' => 'ل', + '𞺌' => 'م', + '𞺍' => 'ن', + '𞺎' => 'س', + '𞺏' => 'ع', + '𞺐' => 'ف', + '𞺑' => 'ص', + '𞺒' => 'ق', + '𞺓' => 'ر', + '𞺔' => 'ش', + '𞺕' => 'ت', + '𞺖' => 'ث', + '𞺗' => 'خ', + '𞺘' => 'ذ', + '𞺙' => 'ض', + '𞺚' => 'ظ', + '𞺛' => 'غ', + '𞺡' => 'ب', + '𞺢' => 'ج', + '𞺣' => 'د', + '𞺥' => 'و', + '𞺦' => 'ز', + '𞺧' => 'ح', + '𞺨' => 'ط', + '𞺩' => 'ي', + '𞺫' => 'ل', + '𞺬' => 'م', + '𞺭' => 'ن', + '𞺮' => 'س', + '𞺯' => 'ع', + '𞺰' => 'ف', + '𞺱' => 'ص', + '𞺲' => 'ق', + '𞺳' => 'ر', + '𞺴' => 'ش', + '𞺵' => 'ت', + '𞺶' => 'ث', + '𞺷' => 'خ', + '𞺸' => 'ذ', + '𞺹' => 'ض', + '𞺺' => 'ظ', + '𞺻' => 'غ', + '🄀' => '0.', + '🄁' => '0,', + '🄂' => '1,', + '🄃' => '2,', + '🄄' => '3,', + '🄅' => '4,', + '🄆' => '5,', + '🄇' => '6,', + '🄈' => '7,', + '🄉' => '8,', + '🄊' => '9,', + '🄐' => '(A)', + '🄑' => '(B)', + '🄒' => '(C)', + '🄓' => '(D)', + '🄔' => '(E)', + '🄕' => '(F)', + '🄖' => '(G)', + '🄗' => '(H)', + '🄘' => '(I)', + '🄙' => '(J)', + '🄚' => '(K)', + '🄛' => '(L)', + '🄜' => '(M)', + '🄝' => '(N)', + '🄞' => '(O)', + '🄟' => '(P)', + '🄠' => '(Q)', + '🄡' => '(R)', + '🄢' => '(S)', + '🄣' => '(T)', + '🄤' => '(U)', + '🄥' => '(V)', + '🄦' => '(W)', + '🄧' => '(X)', + '🄨' => '(Y)', + '🄩' => '(Z)', + '🄪' => '〔S〕', + '🄫' => 'C', + '🄬' => 'R', + '🄭' => 'CD', + '🄮' => 'WZ', + '🄰' => 'A', + '🄱' => 'B', + '🄲' => 'C', + '🄳' => 'D', + '🄴' => 'E', + '🄵' => 'F', + '🄶' => 'G', + '🄷' => 'H', + '🄸' => 'I', + '🄹' => 'J', + '🄺' => 'K', + '🄻' => 'L', + '🄼' => 'M', + '🄽' => 'N', + '🄾' => 'O', + '🄿' => 'P', + '🅀' => 'Q', + '🅁' => 'R', + '🅂' => 'S', + '🅃' => 'T', + '🅄' => 'U', + '🅅' => 'V', + '🅆' => 'W', + '🅇' => 'X', + '🅈' => 'Y', + '🅉' => 'Z', + '🅊' => 'HV', + '🅋' => 'MV', + '🅌' => 'SD', + '🅍' => 'SS', + '🅎' => 'PPV', + '🅏' => 'WC', + '🅪' => 'MC', + '🅫' => 'MD', + '🅬' => 'MR', + '🆐' => 'DJ', + '🈀' => 'ほか', + '🈁' => 'ココ', + '🈂' => 'サ', + '🈐' => '手', + '🈑' => '字', + '🈒' => '双', + '🈓' => 'デ', + '🈔' => '二', + '🈕' => '多', + '🈖' => '解', + '🈗' => '天', + '🈘' => '交', + '🈙' => '映', + '🈚' => '無', + '🈛' => '料', + '🈜' => '前', + '🈝' => '後', + '🈞' => '再', + '🈟' => '新', + '🈠' => '初', + '🈡' => '終', + '🈢' => '生', + '🈣' => '販', + '🈤' => '声', + '🈥' => '吹', + '🈦' => '演', + '🈧' => '投', + '🈨' => '捕', + '🈩' => '一', + '🈪' => '三', + '🈫' => '遊', + '🈬' => '左', + '🈭' => '中', + '🈮' => '右', + '🈯' => '指', + '🈰' => '走', + '🈱' => '打', + '🈲' => '禁', + '🈳' => '空', + '🈴' => '合', + '🈵' => '満', + '🈶' => '有', + '🈷' => '月', + '🈸' => '申', + '🈹' => '割', + '🈺' => '営', + '🈻' => '配', + '🉀' => '〔本〕', + '🉁' => '〔三〕', + '🉂' => '〔二〕', + '🉃' => '〔安〕', + '🉄' => '〔点〕', + '🉅' => '〔打〕', + '🉆' => '〔盗〕', + '🉇' => '〔勝〕', + '🉈' => '〔敗〕', + '🉐' => '得', + '🉑' => '可', + '🯰' => '0', + '🯱' => '1', + '🯲' => '2', + '🯳' => '3', + '🯴' => '4', + '🯵' => '5', + '🯶' => '6', + '🯷' => '7', + '🯸' => '8', + '🯹' => '9', +); diff --git a/vendor/symfony/polyfill-intl-normalizer/bootstrap.php b/vendor/symfony/polyfill-intl-normalizer/bootstrap.php new file mode 100644 index 0000000..ba62006 --- /dev/null +++ b/vendor/symfony/polyfill-intl-normalizer/bootstrap.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Intl\Normalizer as p; + +if (!function_exists('normalizer_is_normalized')) { + function normalizer_is_normalized($s, $form = p\Normalizer::NFC) { return p\Normalizer::isNormalized($s, $form); } +} +if (!function_exists('normalizer_normalize')) { + function normalizer_normalize($s, $form = p\Normalizer::NFC) { return p\Normalizer::normalize($s, $form); } +} diff --git a/vendor/symfony/polyfill-intl-normalizer/composer.json b/vendor/symfony/polyfill-intl-normalizer/composer.json new file mode 100644 index 0000000..b0986a8 --- /dev/null +++ b/vendor/symfony/polyfill-intl-normalizer/composer.json @@ -0,0 +1,39 @@ +{ + "name": "symfony/polyfill-intl-normalizer", + "type": "library", + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "keywords": ["polyfill", "shim", "compatibility", "portable", "intl", "normalizer"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.3" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Intl\\Normalizer\\": "" }, + "files": [ "bootstrap.php" ], + "classmap": [ "Resources/stubs" ] + }, + "suggest": { + "ext-intl": "For best performance" + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/vendor/symfony/polyfill-php70/LICENSE b/vendor/symfony/polyfill-php70/LICENSE new file mode 100644 index 0000000..4cd8bdd --- /dev/null +++ b/vendor/symfony/polyfill-php70/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015-2019 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/polyfill-php70/Php70.php b/vendor/symfony/polyfill-php70/Php70.php new file mode 100644 index 0000000..7f1ad08 --- /dev/null +++ b/vendor/symfony/polyfill-php70/Php70.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php70; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class Php70 +{ + public static function intdiv($dividend, $divisor) + { + $dividend = self::intArg($dividend, __FUNCTION__, 1); + $divisor = self::intArg($divisor, __FUNCTION__, 2); + + if (0 === $divisor) { + throw new \DivisionByZeroError('Division by zero'); + } + if (-1 === $divisor && ~PHP_INT_MAX === $dividend) { + throw new \ArithmeticError('Division of PHP_INT_MIN by -1 is not an integer'); + } + + return ($dividend - ($dividend % $divisor)) / $divisor; + } + + public static function preg_replace_callback_array(array $patterns, $subject, $limit = -1, &$count = 0) + { + $count = 0; + $result = (string) $subject; + if (0 === $limit = self::intArg($limit, __FUNCTION__, 3)) { + return $result; + } + + foreach ($patterns as $pattern => $callback) { + $result = preg_replace_callback($pattern, $callback, $result, $limit, $c); + $count += $c; + } + + return $result; + } + + public static function error_clear_last() + { + static $handler; + if (!$handler) { + $handler = function () { return false; }; + } + set_error_handler($handler); + @trigger_error(''); + restore_error_handler(); + } + + private static function intArg($value, $caller, $pos) + { + if (\is_int($value)) { + return $value; + } + if (!\is_numeric($value) || PHP_INT_MAX <= ($value += 0) || ~PHP_INT_MAX >= $value) { + throw new \TypeError(sprintf('%s() expects parameter %d to be integer, %s given', $caller, $pos, \gettype($value))); + } + + return (int) $value; + } +} diff --git a/vendor/symfony/polyfill-php70/README.md b/vendor/symfony/polyfill-php70/README.md new file mode 100644 index 0000000..abd5488 --- /dev/null +++ b/vendor/symfony/polyfill-php70/README.md @@ -0,0 +1,28 @@ +Symfony Polyfill / Php70 +======================== + +This component provides features unavailable in releases prior to PHP 7.0: + +- [`intdiv`](https://php.net/intdiv) +- [`preg_replace_callback_array`](https://php.net/preg_replace_callback_array) +- [`error_clear_last`](https://php.net/error_clear_last) +- `random_bytes` and `random_int` (from [paragonie/random_compat](https://github.com/paragonie/random_compat)) +- [`*Error` throwable classes](https://php.net/Error) +- [`PHP_INT_MIN`](https://php.net/reserved.constants#constant.php-int-min) +- `SessionUpdateTimestampHandlerInterface` + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). + +Compatibility notes +=================== + +To write portable code between PHP5 and PHP7, some care must be taken: +- `\*Error` exceptions must be caught before `\Exception`; +- after calling `error_clear_last()`, the result of `$e = error_get_last()` must be + verified using `isset($e['message'][0])` instead of `null !== $e`. + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php b/vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php new file mode 100644 index 0000000..6819124 --- /dev/null +++ b/vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php @@ -0,0 +1,5 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Php70 as p; + +if (PHP_VERSION_ID >= 70000) { + return; +} + +if (!defined('PHP_INT_MIN')) { + define('PHP_INT_MIN', ~PHP_INT_MAX); +} + +if (!function_exists('intdiv')) { + function intdiv($dividend, $divisor) { return p\Php70::intdiv($dividend, $divisor); } +} +if (!function_exists('preg_replace_callback_array')) { + function preg_replace_callback_array(array $patterns, $subject, $limit = -1, &$count = 0) { return p\Php70::preg_replace_callback_array($patterns, $subject, $limit, $count); } +} +if (!function_exists('error_clear_last')) { + function error_clear_last() { return p\Php70::error_clear_last(); } +} diff --git a/vendor/symfony/polyfill-php70/composer.json b/vendor/symfony/polyfill-php70/composer.json new file mode 100644 index 0000000..771a6f6 --- /dev/null +++ b/vendor/symfony/polyfill-php70/composer.json @@ -0,0 +1,37 @@ +{ + "name": "symfony/polyfill-php70", + "type": "library", + "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "keywords": ["polyfill", "shim", "compatibility", "portable"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.3", + "paragonie/random_compat": "~1.0|~2.0|~9.99" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Php70\\": "" }, + "files": [ "bootstrap.php" ], + "classmap": [ "Resources/stubs" ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/vendor/symfony/polyfill-php72/LICENSE b/vendor/symfony/polyfill-php72/LICENSE new file mode 100644 index 0000000..4cd8bdd --- /dev/null +++ b/vendor/symfony/polyfill-php72/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015-2019 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/polyfill-php72/Php72.php b/vendor/symfony/polyfill-php72/Php72.php new file mode 100644 index 0000000..9b3edc7 --- /dev/null +++ b/vendor/symfony/polyfill-php72/Php72.php @@ -0,0 +1,217 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php72; + +/** + * @author Nicolas Grekas + * @author Dariusz Rumiński + * + * @internal + */ +final class Php72 +{ + private static $hashMask; + + public static function utf8_encode($s) + { + $s .= $s; + $len = \strlen($s); + + for ($i = $len >> 1, $j = 0; $i < $len; ++$i, ++$j) { + switch (true) { + case $s[$i] < "\x80": $s[$j] = $s[$i]; break; + case $s[$i] < "\xC0": $s[$j] = "\xC2"; $s[++$j] = $s[$i]; break; + default: $s[$j] = "\xC3"; $s[++$j] = \chr(\ord($s[$i]) - 64); break; + } + } + + return substr($s, 0, $j); + } + + public static function utf8_decode($s) + { + $s = (string) $s; + $len = \strlen($s); + + for ($i = 0, $j = 0; $i < $len; ++$i, ++$j) { + switch ($s[$i] & "\xF0") { + case "\xC0": + case "\xD0": + $c = (\ord($s[$i] & "\x1F") << 6) | \ord($s[++$i] & "\x3F"); + $s[$j] = $c < 256 ? \chr($c) : '?'; + break; + + case "\xF0": + ++$i; + // no break + + case "\xE0": + $s[$j] = '?'; + $i += 2; + break; + + default: + $s[$j] = $s[$i]; + } + } + + return substr($s, 0, $j); + } + + public static function php_os_family() + { + if ('\\' === \DIRECTORY_SEPARATOR) { + return 'Windows'; + } + + $map = array( + 'Darwin' => 'Darwin', + 'DragonFly' => 'BSD', + 'FreeBSD' => 'BSD', + 'NetBSD' => 'BSD', + 'OpenBSD' => 'BSD', + 'Linux' => 'Linux', + 'SunOS' => 'Solaris', + ); + + return isset($map[PHP_OS]) ? $map[PHP_OS] : 'Unknown'; + } + + public static function spl_object_id($object) + { + if (null === self::$hashMask) { + self::initHashMask(); + } + if (null === $hash = spl_object_hash($object)) { + return; + } + + // On 32-bit systems, PHP_INT_SIZE is 4, + return self::$hashMask ^ hexdec(substr($hash, 16 - (\PHP_INT_SIZE * 2 - 1), (\PHP_INT_SIZE * 2 - 1))); + } + + public static function sapi_windows_vt100_support($stream, $enable = null) + { + if (!\is_resource($stream)) { + trigger_error('sapi_windows_vt100_support() expects parameter 1 to be resource, '.\gettype($stream).' given', E_USER_WARNING); + + return false; + } + + $meta = stream_get_meta_data($stream); + + if ('STDIO' !== $meta['stream_type']) { + trigger_error('sapi_windows_vt100_support() was not able to analyze the specified stream', E_USER_WARNING); + + return false; + } + + // We cannot actually disable vt100 support if it is set + if (false === $enable || !self::stream_isatty($stream)) { + return false; + } + + // The native function does not apply to stdin + $meta = array_map('strtolower', $meta); + $stdin = 'php://stdin' === $meta['uri'] || 'php://fd/0' === $meta['uri']; + + return !$stdin + && (false !== getenv('ANSICON') + || 'ON' === getenv('ConEmuANSI') + || 'xterm' === getenv('TERM') + || 'Hyper' === getenv('TERM_PROGRAM')); + } + + public static function stream_isatty($stream) + { + if (!\is_resource($stream)) { + trigger_error('stream_isatty() expects parameter 1 to be resource, '.\gettype($stream).' given', E_USER_WARNING); + + return false; + } + + if ('\\' === \DIRECTORY_SEPARATOR) { + $stat = @fstat($stream); + // Check if formatted mode is S_IFCHR + return $stat ? 0020000 === ($stat['mode'] & 0170000) : false; + } + + return \function_exists('posix_isatty') && @posix_isatty($stream); + } + + private static function initHashMask() + { + $obj = (object) array(); + self::$hashMask = -1; + + // check if we are nested in an output buffering handler to prevent a fatal error with ob_start() below + $obFuncs = array('ob_clean', 'ob_end_clean', 'ob_flush', 'ob_end_flush', 'ob_get_contents', 'ob_get_flush'); + foreach (debug_backtrace(\PHP_VERSION_ID >= 50400 ? DEBUG_BACKTRACE_IGNORE_ARGS : false) as $frame) { + if (isset($frame['function'][0]) && !isset($frame['class']) && 'o' === $frame['function'][0] && \in_array($frame['function'], $obFuncs)) { + $frame['line'] = 0; + break; + } + } + if (!empty($frame['line'])) { + ob_start(); + debug_zval_dump($obj); + self::$hashMask = (int) substr(ob_get_clean(), 17); + } + + self::$hashMask ^= hexdec(substr(spl_object_hash($obj), 16 - (\PHP_INT_SIZE * 2 - 1), (\PHP_INT_SIZE * 2 - 1))); + } + + public static function mb_chr($code, $encoding = null) + { + if (0x80 > $code %= 0x200000) { + $s = \chr($code); + } elseif (0x800 > $code) { + $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F); + } elseif (0x10000 > $code) { + $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); + } else { + $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); + } + + if ('UTF-8' !== $encoding) { + $s = mb_convert_encoding($s, $encoding, 'UTF-8'); + } + + return $s; + } + + public static function mb_ord($s, $encoding = null) + { + if (null == $encoding) { + $s = mb_convert_encoding($s, 'UTF-8'); + } elseif ('UTF-8' !== $encoding) { + $s = mb_convert_encoding($s, 'UTF-8', $encoding); + } + + if (1 === \strlen($s)) { + return \ord($s); + } + + $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0; + if (0xF0 <= $code) { + return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80; + } + if (0xE0 <= $code) { + return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80; + } + if (0xC0 <= $code) { + return (($code - 0xC0) << 6) + $s[2] - 0x80; + } + + return $code; + } +} diff --git a/vendor/symfony/polyfill-php72/README.md b/vendor/symfony/polyfill-php72/README.md new file mode 100644 index 0000000..59dec8a --- /dev/null +++ b/vendor/symfony/polyfill-php72/README.md @@ -0,0 +1,28 @@ +Symfony Polyfill / Php72 +======================== + +This component provides functions added to PHP 7.2 core: + +- [`spl_object_id`](https://php.net/spl_object_id) +- [`stream_isatty`](https://php.net/stream_isatty) + +On Windows only: + +- [`sapi_windows_vt100_support`](https://php.net/sapi_windows_vt100_support) + +Moved to core since 7.2 (was in the optional XML extension earlier): + +- [`utf8_encode`](https://php.net/utf8_encode) +- [`utf8_decode`](https://php.net/utf8_decode) + +Also, it provides constants added to PHP 7.2: +- [`PHP_FLOAT_*`](https://php.net/reserved.constants#constant.php-float-dig) +- [`PHP_OS_FAMILY`](https://php.net/reserved.constants#constant.php-os-family) + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-php72/bootstrap.php b/vendor/symfony/polyfill-php72/bootstrap.php new file mode 100644 index 0000000..a27a900 --- /dev/null +++ b/vendor/symfony/polyfill-php72/bootstrap.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Php72 as p; + +if (PHP_VERSION_ID >= 70200) { + return; +} + +if (!defined('PHP_FLOAT_DIG')) { + define('PHP_FLOAT_DIG', 15); +} +if (!defined('PHP_FLOAT_EPSILON')) { + define('PHP_FLOAT_EPSILON', 2.2204460492503E-16); +} +if (!defined('PHP_FLOAT_MIN')) { + define('PHP_FLOAT_MIN', 2.2250738585072E-308); +} +if (!defined('PHP_FLOAT_MAX')) { + define('PHP_FLOAT_MAX', 1.7976931348623157E+308); +} +if (!defined('PHP_OS_FAMILY')) { + define('PHP_OS_FAMILY', p\Php72::php_os_family()); +} + +if ('\\' === DIRECTORY_SEPARATOR && !function_exists('sapi_windows_vt100_support')) { + function sapi_windows_vt100_support($stream, $enable = null) { return p\Php72::sapi_windows_vt100_support($stream, $enable); } +} +if (!function_exists('stream_isatty')) { + function stream_isatty($stream) { return p\Php72::stream_isatty($stream); } +} +if (!function_exists('utf8_encode')) { + function utf8_encode($s) { return p\Php72::utf8_encode($s); } +} +if (!function_exists('utf8_decode')) { + function utf8_decode($s) { return p\Php72::utf8_decode($s); } +} +if (!function_exists('spl_object_id')) { + function spl_object_id($s) { return p\Php72::spl_object_id($s); } +} +if (!function_exists('mb_ord')) { + function mb_ord($s, $enc = null) { return p\Php72::mb_ord($s, $enc); } +} +if (!function_exists('mb_chr')) { + function mb_chr($code, $enc = null) { return p\Php72::mb_chr($code, $enc); } +} +if (!function_exists('mb_scrub')) { + function mb_scrub($s, $enc = null) { $enc = null === $enc ? mb_internal_encoding() : $enc; return mb_convert_encoding($s, $enc, $enc); } +} diff --git a/vendor/symfony/polyfill-php72/composer.json b/vendor/symfony/polyfill-php72/composer.json new file mode 100644 index 0000000..e295cab --- /dev/null +++ b/vendor/symfony/polyfill-php72/composer.json @@ -0,0 +1,35 @@ +{ + "name": "symfony/polyfill-php72", + "type": "library", + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "keywords": ["polyfill", "shim", "compatibility", "portable"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.3" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Php72\\": "" }, + "files": [ "bootstrap.php" ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "1.18-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/vendor/webonyx/graphql-php/CHANGELOG.md b/vendor/webonyx/graphql-php/CHANGELOG.md new file mode 100644 index 0000000..dcfdd39 --- /dev/null +++ b/vendor/webonyx/graphql-php/CHANGELOG.md @@ -0,0 +1,208 @@ +# Changelog +### v0.13.8 +- Don't call global field resolver on introspection fields (#481) + +### v0.13.7 +- Added retrieving query complexity once query has been completed (#316) +- Allow input types to be passed in from variables using \stdClass instead of associative arrays (#535) + +#### v0.13.6 +- QueryPlan can now be used on interfaces not only objects. (#495) +- Array in variables in place of object shouldn't cause fatal error (fixes #467) +- Scalar type ResolverInfo::getFieldSelection support (#529) + +#### v0.13.5 +- Fix coroutine executor when using with promise (#486) + +#### v0.13.4 +- Force int when setting max query depth (#477) + +#### v0.13.3 +- Reverted minor possible breaking change (#476) + +#### v0.13.2 +- Added QueryPlan support (#436) +- Fixed an issue with NodeList iteration over missing keys (#475) + +#### v0.13.1 +- Better validation of field/directive arguments +- Support for apollo client/server persisted queries +- Minor tweaks and fixes + +## v0.13.0 +This release brings several breaking changes. Please refer to [UPGRADE](UPGRADE.md) document for details. + +New features and notable changes: +- PHP version required: 7.1+ +- Spec compliance: error `category` and extensions are displayed under `extensions` key when using default formatting (#389) +- New experimental executor with improved performance (#314).
+It is a one-line switch: `GraphQL::useExperimentalExecutor()`.
+
+**Please try it and post your feedback at https://github.com/webonyx/graphql-php/issues/397** +(as it may become the default one in future) +
+
+- Ported `extendSchema` from the reference implementation under `GraphQL\Utils\SchemaExtender` (#362) +- Added ability to override standard types via `GraphQL::overrideStandardTypes(array $types)` (#401) +- Added flag `Debug::RETHROW_UNSAFE_EXCEPTIONS` which would only rethrow app-specific exceptions (#337) +- Several classes were renamed (see [UPGRADE.md](UPGRADE.md)) +- Schema Validation improvements + +#### v0.12.6 +- Bugfix: Call to a member function getLocation() on null (#336) +- Fixed several errors discovered by static analysis (#329) + +#### v0.12.5 +- Execution performance optimization for lists + +#### v0.12.4 +- Allow stringeable objects to be serialized by StringType (#303) + +#### v0.12.3 +- StandardServer: add support for the multipart/form-data content type (#300) + +#### v0.12.2 +- SchemaPrinter: Use multi-line block for trailing quote (#294) + +#### v0.12.1 +- Fixed bug in validation rule OverlappingFieldsCanBeMerged (#292) +- Added one more breaking change note in UPGRADE.md (#291) +- Spec compliance: remove `data` entry from response on top-level error (#281) + +## v0.12.0 +- RFC: Block String (multi-line strings via triple-quote """string""") +- GraphQL Schema SDL: Descriptions as strings (including multi-line) +- Changed minimum required PHP version to 5.6 + +Improvements: +- Allow extending GraphQL errors with additional properties +- Fixed parsing of default values in Schema SDL +- Handling several more cases in findBreakingChanges +- StandardServer: expect `operationName` (instead of `operation`) in input + + +#### v0.11.5 +- Allow objects with __toString in IDType + +#### v0.11.4 +- findBreakingChanges utility (see #199) + +#### v0.11.3 +- StandardServer: Support non pre-parsed PSR-7 request body (see #202) + +#### v0.11.2 +- Bugfix: provide descriptions to custom scalars (see #181) + +#### v0.11.1 +- Ability to override internal types via `types` option of the schema (see #174). + +## v0.11.0 +This release brings little changes but there are two reasons why it is released as major version: + +1. To follow reference implementation versions (it matches 0.11.x series of graphql-js) +2. It may break existing applications because scalar input coercion rules are stricter now:
+In previous versions sloppy client input could leak through with unexpected results. +For example string `"false"` accidentally sent in variables was converted to boolean `true` +and passed to field arguments. In the new version, such input will produce an error +(which is a spec-compliant behavior). + +Improvements: +- Stricter input coercion (see #171) +- Types built with `BuildSchema` now have reference to AST node with corresponding AST definition (in $astNode property) +- Account for query offset for error locations (e.g. when query is stored in `.graphql` file) + +#### v0.10.2 +- StandardServer improvement: do not raise an error when variables are passed as empty string (see #156) + +#### v0.10.1 +- Fixed infinite loop in the server (see #153) + +## v0.10.0 +This release brings several breaking changes. Please refer to [UPGRADE](UPGRADE.md) document for details. + +New features and notable changes: +- Changed minimum PHP version from 5.4 to 5.5 +- Lazy loading of types without separate build step (see #69, see [docs](http://webonyx.github.io/graphql-php/type-system/schema/#lazy-loading-of-types)) +- PSR-7 compliant Standard Server (see [docs](http://webonyx.github.io/graphql-php/executing-queries/#using-server)) +- New default error formatting, which does not expose sensitive data (see [docs](http://webonyx.github.io/graphql-php/error-handling/)) +- Ability to define custom error handler to filter/log/re-throw exceptions after execution (see [docs](http://webonyx.github.io/graphql-php/error-handling/#custom-error-handling-and-formatting)) +- Allow defining schema configuration using objects with fluent setters vs array (see [docs](http://webonyx.github.io/graphql-php/type-system/schema/#using-config-class)) +- Allow serializing AST to array and re-creating AST from array lazily (see [docs](http://webonyx.github.io/graphql-php/reference/#graphqlutilsast)) +- [Apollo-style](https://dev-blog.apollodata.com/query-batching-in-apollo-63acfd859862) query batching support via server (see [docs](http://webonyx.github.io/graphql-php/executing-queries/#query-batching)) +- Schema validation, including validation of interface implementations (see [docs](http://webonyx.github.io/graphql-php/type-system/schema/#schema-validation)) +- Ability to pass custom config formatter when defining schema using [GraphQL type language](http://graphql.org/learn/schema/#type-language) (see [docs](http://webonyx.github.io/graphql-php/type-system/type-language/)) + +Improvements: +- Significantly improved parser performance (see #137 and #128) +- Support for PHP7 exceptions everywhere (see #127) +- Improved [documentation](http://webonyx.github.io/graphql-php/) and docblock comments + +Deprecations and breaking changes - see [UPGRADE](UPGRADE.md) document. + +#### v0.9.14 +- Minor change to assist DataLoader project in fixing #150 + +#### v0.9.13 +- Fixed PHP notice and invalid conversion when non-scalar value is passed as ID or String type (see #121) + +#### v0.9.12 +- Fixed bug occurring when enum `value` is bool, null or float (see #141) + +#### v0.9.11 +- Ability to disable introspection (see #131) + +#### v0.9.10 +- Fixed issue with query complexity throwing on invalid queries (see #125) +- Fixed "Out of memory" error when `resolveType` returns unexpected result (see #119) + +#### v0.9.9 +- Bugfix: throw UserError vs InvariantViolationError for errors caused by client (see #123) + +#### v0.9.8 +- Bugfix: use directives when calculating query complexity (see #113) +- Bugfix: `AST\Node::__toString()` will convert node to array recursively to encode to json without errors + +#### v0.9.7 +- Bugfix: `ResolveInfo::getFieldSelection()` now correctly merges fragment selections (see #98) + +#### v0.9.6 +- Bugfix: `ResolveInfo::getFieldSelection()` now respects inline fragments + +#### v0.9.5 +- Fixed SyncPromiseAdapter::all() to not change the order of arrays (see #92) + +#### v0.9.4 +- Tools to help building schema out of Schema definition language as well as printing existing +schema in Schema definition language (see #91) + +#### v0.9.3 +- Fixed Utils::assign() bug related to detecting missing required keys (see #89) + +#### v0.9.2 +- Schema Definition Language: element descriptions can be set through comments (see #88) + +#### v0.9.1 +- Fixed: `GraphQL\Server` now properly sets promise adapter before executing query + +## v0.9.0 +- Deferred resolvers (see #66, see [docs](docs/data-fetching.md#solving-n1-problem)) +- New Facade class with fluid interface: `GraphQL\Server` (see #82) +- Experimental: ability to load types in Schema lazily via custom `TypeResolutionStrategy` (see #69) + + +## v0.8.0 +This release brings several minor breaking changes. Please refer to [UPGRADE](UPGRADE.md) document for details. + +New features: +- Support for `null` value (as required by latest GraphQL spec) +- Shorthand definitions for field and argument types (see #47) +- `path` entry in errors produced by resolvers for better debugging +- `resolveType` for interface/union is now allowed to return string name of type +- Ability to omit name when extending type class (vs defining inline) + +Improvements: +- Spec compliance improvements +- New docs and examples + +## Older versions +Look at [GitHub Releases Page](https://github.com/webonyx/graphql-php/releases). diff --git a/vendor/webonyx/graphql-php/LICENSE b/vendor/webonyx/graphql-php/LICENSE new file mode 100644 index 0000000..8671fe4 --- /dev/null +++ b/vendor/webonyx/graphql-php/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2015-present, Webonyx, LLC. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/webonyx/graphql-php/README.md b/vendor/webonyx/graphql-php/README.md new file mode 100644 index 0000000..2cf46ba --- /dev/null +++ b/vendor/webonyx/graphql-php/README.md @@ -0,0 +1,52 @@ +# graphql-php +[![Build Status](https://travis-ci.org/webonyx/graphql-php.svg?branch=master)](https://travis-ci.org/webonyx/graphql-php) +[![Code Coverage](https://scrutinizer-ci.com/g/webonyx/graphql-php/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/webonyx/graphql-php) +[![Latest Stable Version](https://poser.pugx.org/webonyx/graphql-php/version)](https://packagist.org/packages/webonyx/graphql-php) +[![License](https://poser.pugx.org/webonyx/graphql-php/license)](https://packagist.org/packages/webonyx/graphql-php) + +This is a PHP implementation of the GraphQL [specification](https://github.com/facebook/graphql) +based on the [reference implementation in JavaScript](https://github.com/graphql/graphql-js). + +## Installation +Via composer: +``` +composer require webonyx/graphql-php +``` + +## Documentation +Full documentation is available on the [Documentation site](https://webonyx.github.io/graphql-php/) as well +as in the [docs](docs/) folder of the distribution. + +If you don't know what GraphQL is, visit this [official website](http://graphql.org) +by the Facebook engineering team. + +## Examples +There are several ready examples in the [examples](examples/) folder of the distribution with specific +README file per example. + +## Contributors + +This project exists thanks to [all the people](https://github.com/webonyx/graphql-php/graphs/contributors) who contribute. [[Contribute](CONTRIBUTING.md)]. + +## Backers + + + +## Sponsors + +Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/webonyx-graphql-php#sponsor)] + + + + + + + + + + + + +## License + +See [LICENCE](LICENSE). diff --git a/vendor/webonyx/graphql-php/UPGRADE.md b/vendor/webonyx/graphql-php/UPGRADE.md new file mode 100644 index 0000000..a9d7256 --- /dev/null +++ b/vendor/webonyx/graphql-php/UPGRADE.md @@ -0,0 +1,527 @@ +## Upgrade v0.12.x > v0.13.x + +### Breaking (major): minimum supported version of PHP +New minimum required version of PHP is **7.1+** + +### Breaking (major): default errors formatting changed according to spec +**Category** and extensions assigned to errors are shown under `extensions` key +```php +$e = new Error( + 'msg', + null, + null, + null, + null, + null, + ['foo' => 'bar'] +); +``` +Formatting before the change: +``` +'errors' => [ + [ + 'message' => 'msg', + 'category' => 'graphql', + 'foo' => 'bar' + ] +] +``` +After the change: +``` +'errors' => [ + [ + 'message' => 'msg', + 'extensions' => [ + 'category' => 'graphql', + 'foo' => 'bar', + ], + ] +] +``` + +Note: if error extensions contain `category` key - it has a priority over default category. + +You can always switch to [custom error formatting](https://webonyx.github.io/graphql-php/error-handling/#custom-error-handling-and-formatting) to revert to the old format. + +### Try it: Experimental Executor with improved performance +It is disabled by default. To enable it, do the following +```php + true]) +``` + +### Breaking: several classes renamed + +- `AbstractValidationRule` renamed to `ValidationRule` (NS `GraphQL\Validator\Rules`) +- `AbstractQuerySecurity` renamed to `QuerySecurityRule` (NS `GraphQL\Validator\Rules`) +- `FindBreakingChanges` renamed to `BreakingChangesFinder` (NS `GraphQL\Utils`) + +### Breaking: new constructors + +`GraphQL\Type\Definition\ResolveInfo` now takes 10 arguments instead of one array. + +## Upgrade v0.11.x > v0.12.x + +### Breaking: Minimum supported version is PHP5.6 +Dropped support for PHP 5.5. This release still supports PHP 5.6 and PHP 7.0 +**But the next major release will require PHP7.1+** + +### Breaking: Custom scalar types need to throw on invalid value +As null might be a valid value custom types need to throw an +Exception inside `parseLiteral()`, `parseValue()` and `serialize()`. + +Returning null from any of these methods will now be treated as valid result. + +### Breaking: Custom scalar types parseLiteral() declaration changed +A new parameter was added to `parseLiteral()`, which also needs to be added to any custom scalar type extending from `ScalarType` + +Before: +```php +class MyType extends ScalarType { + + ... + + public function parseLiteral($valueNode) { + //custom implementation + } +} +``` + +After: +```php +class MyType extends ScalarType { + + ... + + public function parseLiteral($valueNode, array $variables = null) { + //custom implementation + } +} +``` + +### Breaking: Descriptions in comments are not used as descriptions by default anymore +Descriptions now need to be inside Strings or BlockStrings in order to be picked up as +description. If you want to keep the old behaviour you can supply the option `commentDescriptions` +to BuildSchema::buildAST(), BuildSchema::build() or Printer::doPrint(). + +Here is the official way now to define descriptions in the graphQL language: + +Old: + +```graphql +# Description +type Dog { + ... +} +``` + +New: + +```graphql +"Description" +type Dog { + ... +} + +""" +Long Description +""" +type Dog { + ... +} +``` + +### Breaking: Cached AST of version 0.11.x is not compatible with 0.12.x. +That's because description in AST is now a separate node, not just a string. +Make sure to renew caches. + +### Breaking: Most of previously deprecated classes and methods were removed +See deprecation notices for previous versions in details. + +### Breaking: Standard server expects `operationName` vs `operation` for multi-op queries +Before the change: +```json +{ + "queryId": "persisted-query-id", + "operation": "QueryFromPersistedDocument", + "variables": {} +} +``` +After the change: +```json +{ + "queryId": "persisted-query-id", + "operationName": "QueryFromPersistedDocument", + "variables": {} +} +``` +This naming is aligned with graphql-express version. + +### Possibly Breaking: AST to array serialization excludes nulls +Most users won't be affected. It *may* affect you only if you do your own manipulations +with exported AST. + +Example of json-serialized AST before the change: +```json +{ + "kind": "Field", + "loc": null, + "name": { + "kind": "Name", + "loc": null, + "value": "id" + }, + "alias": null, + "arguments": [], + "directives": [], + "selectionSet": null +} +``` +After the change: +```json +{ + "kind": "Field", + "name": { + "kind": "Name", + "value": "id" + }, + "arguments": [], + "directives": [] +} +``` + +## Upgrade v0.8.x, v0.9.x > v0.10.x + +### Breaking: changed minimum PHP version from 5.4 to 5.5 +It allows us to leverage `::class` constant, `generators` and other features of newer PHP versions. + +### Breaking: default error formatting +By default exceptions thrown in resolvers will be reported with generic message `"Internal server error"`. +Only exceptions implementing interface `GraphQL\Error\ClientAware` and claiming themselves as `safe` will +be reported with full error message. + +This breaking change is done to avoid information leak in production when unhandled +exceptions were reported to clients (e.g. database connection errors, file access errors, etc). + +Also every error reported to client now has new `category` key which is either `graphql` or `internal`. +Exceptions implementing `ClientAware` interface may define their own custom categories. + +During development or debugging use `$executionResult->toArray(true)`. It will add `debugMessage` key to +each error entry in result. If you also want to add `trace` for each error - pass flags instead: + +``` +use GraphQL\Error\FormattedError; +$debug = FormattedError::INCLUDE_DEBUG_MESSAGE | FormattedError::INCLUDE_TRACE; +$result = GraphQL::executeAndReturnResult(/*args*/)->toArray($debug); +``` + +To change default `"Internal server error"` message to something else, use: +``` +GraphQL\Error\FormattedError::setInternalErrorMessage("Unexpected error"); +``` + +**This change only affects default error reporting mechanism. If you set your own error formatter using +`$executionResult->setErrorFormatter($myFormatter)` you won't be affected by this change.** + +If you need to revert to old behavior temporary, use: + +```php +GraphQL::executeAndReturnResult(/**/) + ->setErrorFormatter('\GraphQL\Error\Error::formatError') + ->toArray(); +``` +But note that this is deprecated format and will be removed in future versions. + +In general, if new default formatting doesn't work for you - just set [your own error +formatter](http://webonyx.github.io/graphql-php/error-handling/#custom-error-handling-and-formatting). + +### Breaking: Validation rules now have abstract base class +Previously any callable was accepted by DocumentValidator as validation rule. Now only instances of +`GraphQL\Validator\Rules\AbstractValidationRule` are allowed. + +If you were using custom validation rules, just wrap them with +`GraphQL\Validator\Rules\CustomValidationRule` (created for backwards compatibility). + +Before: +```php +use GraphQL\Validator\DocumentValidator; + +$myRule = function(ValidationContext $context) {}; +DocumentValidator::validate($schema, $ast, [$myRule]); +``` + +After: +```php +use GraphQL\Validator\Rules\CustomValidationRule; +use GraphQL\Validator\DocumentValidator; + +$myRule = new CustomValidationRule('MyRule', function(ValidationContext $context) {}); +DocumentValidator::validate($schema, $ast, [$myRule]); +``` + +Also `DocumentValidator::addRule()` signature changed. + +Before the change: +```php +use GraphQL\Validator\DocumentValidator; + +$myRule = function(ValidationContext $context) {}; +DocumentValidator::addRule('MyRuleName', $myRule); +``` + +After the change: +```php +use GraphQL\Validator\DocumentValidator; + +$myRule = new CustomValidationRulefunction('MyRule', ValidationContext $context) {}); +DocumentValidator::addRule($myRule); +``` + + +### Breaking: AST now uses `NodeList` vs array for lists of nodes +It helps us unserialize AST from array lazily. This change affects you only if you use `array_` +functions with AST or mutate AST directly. + +Before the change: +```php +new GraphQL\Language\AST\DocumentNode([ + 'definitions' => array(/*...*/) +]); +``` +After the change: +``` +new GraphQL\Language\AST\DocumentNode([ + 'definitions' => new NodeList([/*...*/]) +]); +``` + + +### Breaking: scalar types now throw different exceptions when parsing and serializing +On invalid client input (`parseValue` and `parseLiteral`) they throw standard `GraphQL\Error\Error` +but when they encounter invalid output (in `serialize`) they throw `GraphQL\Error\InvariantViolation`. + +Previously they were throwing `GraphQL\Error\UserError`. This exception is no longer used so make sure +to adjust if you were checking for this error in your custom error formatters. + +### Breaking: removed previously deprecated ability to define type as callable +See https://github.com/webonyx/graphql-php/issues/35 + +### Deprecated: `GraphQL\GraphQL::executeAndReturnResult` +Method is renamed to `GraphQL\GraphQL::executeQuery`. Old method name is still available, +but will trigger deprecation warning in the next version. + +### Deprecated: `GraphQL\GraphQL::execute` +Use `GraphQL\GraphQL::executeQuery()->toArray()` instead. +Old method still exists, but will trigger deprecation warning in next version. + +### Deprecated: `GraphQL\Schema` moved to `GraphQL\Type\Schema` +Old class still exists, but will trigger deprecation warning in next version. + +### Deprecated: `GraphQL\Utils` moved to `GraphQL\Utils\Utils` +Old class still exists, but triggers deprecation warning when referenced. + +### Deprecated: `GraphQL\Type\Definition\Config` +If you were using config validation in previous versions, replace: +```php +GraphQL\Type\Definition\Config::enableValidation(); +``` +with: +```php +$schema->assertValid(); +``` +See https://github.com/webonyx/graphql-php/issues/148 + +### Deprecated: experimental `GraphQL\Server` +Use [new PSR-7 compliant implementation](docs/executing-queries.md#using-server) instead. + +### Deprecated: experimental `GraphQL\Type\Resolution` interface and implementations +Use schema [**typeLoader** option](docs/type-system/schema.md#lazy-loading-of-types) instead. + +### Non-breaking: usage on async platforms +When using the library on async platforms use separate method `GraphQL::promiseToExecute()`. +It requires promise adapter in it's first argument and always returns a `Promise`. + +Old methods `GraphQL::execute` and `GraphQL::executeAndReturnResult` still work in backwards-compatible manner, +but they are deprecated and will be removed eventually. + +Same applies to Executor: use `Executor::promiseToExecute()` vs `Executor::execute()`. + +## Upgrade v0.7.x > v0.8.x +All of those changes apply to those who extends various parts of this library. +If you only use the library and don't try to extend it - everything should work without breaks. + + +### Breaking: Custom directives handling +When passing custom directives to schema, default directives (like `@skip` and `@include`) +are not added to schema automatically anymore. If you need them - add them explicitly with +your other directives. + +Before the change: +```php +$schema = new Schema([ + // ... + 'directives' => [$myDirective] +]); +``` + +After the change: +```php +$schema = new Schema([ + // ... + 'directives' => array_merge(GraphQL::getInternalDirectives(), [$myDirective]) +]); +``` + +### Breaking: Schema protected property and methods visibility +Most of the `protected` properties and methods of `GraphQL\Schema` were changed to `private`. +Please use public interface instead. + +### Breaking: Node kind constants +Node kind constants were extracted from `GraphQL\Language\AST\Node` to +separate class `GraphQL\Language\AST\NodeKind` + +### Non-breaking: AST node classes renamed +AST node classes were renamed to disambiguate with types. e.g.: + +``` +GraphQL\Language\AST\Field -> GraphQL\Language\AST\FieldNode +GraphQL\Language\AST\OjbectValue -> GraphQL\Language\AST\OjbectValueNode +``` +etc. + +Old names are still available via `class_alias` defined in `src/deprecated.php`. +This file is included automatically when using composer autoloading. + +### Deprecations +There are several deprecations which still work, but trigger `E_USER_DEPRECATED` when used. + +For example `GraphQL\Executor\Executor::setDefaultResolveFn()` is renamed to `setDefaultResolver()` +but still works with old name. + +## Upgrade v0.6.x > v0.7.x + +There are a few new breaking changes in v0.7.0 that were added to the graphql-js reference implementation +with the spec of April2016 + +### 1. Context for resolver + +You can now pass a custom context to the `GraphQL::execute` function that is available in all resolvers as 3rd argument. +This can for example be used to pass the current user etc. + +Make sure to update all calls to `GraphQL::execute`, `GraphQL::executeAndReturnResult`, `Executor::execute` and all +`'resolve'` callbacks in your app. + +Before v0.7.0 `GraphQL::execute` signature looked this way: + ```php + GraphQL::execute( + $schema, + $query, + $rootValue, + $variables, + $operationName + ); + ``` + +Starting from v0.7.0 the signature looks this way (note the new `$context` argument): +```php +GraphQL::execute( + $schema, + $query, + $rootValue, + $context, + $variables, + $operationName +); +``` + +Before v.0.7.0 resolve callbacks had following signature: +```php +/** + * @param mixed $object The parent resolved object + * @param array $args Input arguments + * @param ResolveInfo $info ResolveInfo object + * @return mixed + */ +function resolveMyField($object, array $args, ResolveInfo $info) { + //... +} +``` + +Starting from v0.7.0 the signature has changed to (note the new `$context` argument): +```php +/** + * @param mixed $object The parent resolved object + * @param array $args Input arguments + * @param mixed $context The context object hat was passed to GraphQL::execute + * @param ResolveInfo $info ResolveInfo object + * @return mixed + */ +function resolveMyField($object, array $args, $context, ResolveInfo $info){ + //... +} +``` + +### 2. Schema constructor signature + +The signature of the Schema constructor now accepts an associative config array instead of positional arguments: + +Before v0.7.0: +```php +$schema = new Schema($queryType, $mutationType); +``` + +Starting from v0.7.0: +```php +$schema = new Schema([ + 'query' => $queryType, + 'mutation' => $mutationType, + 'types' => $arrayOfTypesWithInterfaces // See 3. +]); +``` + +### 3. Types can be directly passed to schema + +There are edge cases when GraphQL cannot infer some types from your schema. +One example is when you define a field of interface type and object types implementing +this interface are not referenced anywhere else. + +In such case object types might not be available when an interface is queried and query +validation will fail. In that case, you need to pass the types that implement the +interfaces directly to the schema, so that GraphQL knows of their existence during query validation. + +For example: +```php +$schema = new Schema([ + 'query' => $queryType, + 'mutation' => $mutationType, + 'types' => $arrayOfTypesWithInterfaces +]); +``` + +Note that you don't need to pass all types here - only those types that GraphQL "doesn't see" +automatically. Before v7.0.0 the workaround for this was to create a dumb (non-used) field per +each "invisible" object type. + +Also see [webonyx/graphql-php#38](https://github.com/webonyx/graphql-php/issues/38) diff --git a/vendor/webonyx/graphql-php/composer.json b/vendor/webonyx/graphql-php/composer.json new file mode 100644 index 0000000..113e79d --- /dev/null +++ b/vendor/webonyx/graphql-php/composer.json @@ -0,0 +1,56 @@ +{ + "name": "webonyx/graphql-php", + "description": "A PHP port of GraphQL reference implementation", + "type": "library", + "license": "MIT", + "homepage": "https://github.com/webonyx/graphql-php", + "keywords": [ + "graphql", + "API" + ], + "require": { + "php": "^7.1||^8.0", + "ext-json": "*", + "ext-mbstring": "*" + }, + "require-dev": { + "doctrine/coding-standard": "^6.0", + "phpbench/phpbench": "^0.14.0", + "phpstan/phpstan": "^0.11.4", + "phpstan/phpstan-phpunit": "^0.11.0", + "phpstan/phpstan-strict-rules": "^0.11.0", + "phpunit/phpcov": "^5.0", + "phpunit/phpunit": "^7.2", + "psr/http-message": "^1.0", + "react/promise": "2.*" + }, + "config": { + "preferred-install": "dist", + "sort-packages": true + }, + "autoload": { + "psr-4": { + "GraphQL\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "GraphQL\\Tests\\": "tests/", + "GraphQL\\Benchmarks\\": "benchmarks/", + "GraphQL\\Examples\\Blog\\": "examples/01-blog/Blog/" + } + }, + "suggest": { + "react/promise": "To leverage async resolving on React PHP platform", + "psr/http-message": "To use standard GraphQL server" + }, + "scripts": { + "api-docs": "php tools/gendocs.php", + "bench": "phpbench run .", + "test": "phpunit", + "lint" : "phpcs", + "fix-style" : "phpcbf", + "static-analysis": "phpstan analyse --ansi --memory-limit 256M", + "check-all": "composer lint && composer static-analysis && composer test" + } +} diff --git a/vendor/webonyx/graphql-php/docs/best-practices.md b/vendor/webonyx/graphql-php/docs/best-practices.md new file mode 100644 index 0000000..a5f135e --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/best-practices.md @@ -0,0 +1,19 @@ +# Config Validation +Defining types using arrays may be error-prone, but **graphql-php** provides config validation +tool to report when config has unexpected structure. + +This validation tool is **disabled by default** because it is time-consuming operation which only +makes sense during development. + +To enable validation - call: `GraphQL\Type\Definition\Config::enableValidation();` in your bootstrap +but make sure to restrict it to debug/development mode only. + +# Type Registry +**graphql-php** expects that each type in Schema is presented by single instance. Therefore +if you define your types as separate PHP classes you need to ensure that each type is referenced only once. + +Technically you can create several instances of your type (for example for tests), but `GraphQL\Type\Schema` +will throw on attempt to add different instances with the same name. + +There are several ways to achieve this depending on your preferences. We provide reference +implementation below that introduces TypeRegistry class: \ No newline at end of file diff --git a/vendor/webonyx/graphql-php/docs/complementary-tools.md b/vendor/webonyx/graphql-php/docs/complementary-tools.md new file mode 100644 index 0000000..4710ebd --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/complementary-tools.md @@ -0,0 +1,25 @@ +# Integrations + +* [Standard Server](executing-queries.md/#using-server) – Out of the box integration with any PSR-7 compatible framework (like [Slim](http://slimframework.com) or [Zend Expressive](http://zendframework.github.io/zend-expressive/)). +* [Relay Library for graphql-php](https://github.com/ivome/graphql-relay-php) – Helps construct Relay related schema definitions. +* [Lighthouse](https://github.com/nuwave/lighthouse) – Laravel based, uses Schema Definition Language +* [OverblogGraphQLBundle](https://github.com/overblog/GraphQLBundle) – Bundle for Symfony +* [WP-GraphQL](https://github.com/wp-graphql/wp-graphql) - GraphQL API for WordPress + +# GraphQL PHP Tools + +* [GraphQLite](https://graphqlite.thecodingmachine.io) – Define your complete schema with annotations +* [GraphQL Doctrine](https://github.com/Ecodev/graphql-doctrine) – Define types with Doctrine ORM annotations +* [DataLoaderPHP](https://github.com/overblog/dataloader-php) – as a ready implementation for [deferred resolvers](data-fetching.md#solving-n1-problem) +* [GraphQL Uploads](https://github.com/Ecodev/graphql-upload) – A PSR-15 middleware to support file uploads in GraphQL. +* [GraphQL Batch Processor](https://github.com/vasily-kartashov/graphql-batch-processing) – Provides a builder interface for defining collection, querying, filtering, and post-processing logic of batched data fetches. +* [GraphQL Utils](https://github.com/simPod/GraphQL-Utils) – Objective schema definition builders (no need for arrays anymore) and `DateTime` scalar +* [PSR 15 compliant middleware](https://github.com/phps-cans/psr7-middleware-graphql) for the Standard Server _(experimental)_ + +# General GraphQL Tools + +* [GraphQL Playground](https://github.com/prismagraphql/graphql-playground) – GraphQL IDE for better development workflows (GraphQL Subscriptions, interactive docs & collaboration). +* [GraphiQL](https://github.com/graphql/graphiql) – An in-browser IDE for exploring GraphQL +* [ChromeiQL](https://chrome.google.com/webstore/detail/chromeiql/fkkiamalmpiidkljmicmjfbieiclmeij) + or [GraphiQL Feen](https://chrome.google.com/webstore/detail/graphiql-feen/mcbfdonlkfpbfdpimkjilhdneikhfklp) – + GraphiQL as Google Chrome extension diff --git a/vendor/webonyx/graphql-php/docs/concepts.md b/vendor/webonyx/graphql-php/docs/concepts.md new file mode 100644 index 0000000..91fe642 --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/concepts.md @@ -0,0 +1,139 @@ +# Overview +GraphQL is data-centric. On the very top level it is built around three major concepts: +**Schema**, **Query** and **Mutation**. + +You are expected to express your application as **Schema** (aka Type System) and expose it +with single HTTP endpoint (e.g. using our [standard server](executing-queries.md#using-server)). +Application clients (e.g. web or mobile clients) send **Queries** +to this endpoint to request structured data and **Mutations** to perform changes (usually with HTTP POST method). + +## Queries +Queries are expressed in simple language that resembles JSON: + +```graphql +{ + hero { + name + friends { + name + } + } +} +``` + +It was designed to mirror the structure of expected response: +```json +{ + "hero": { + "name": "R2-D2", + "friends": [ + {"name": "Luke Skywalker"}, + {"name": "Han Solo"}, + {"name": "Leia Organa"} + ] + } +} +``` +**graphql-php** runtime parses Queries, makes sure that they are valid for given Type System +and executes using [data fetching tools](data-fetching.md) provided by you +as a part of integration. Queries are supposed to be idempotent. + +## Mutations +Mutations use advanced features of the very same query language (like arguments and variables) +and have only semantic difference from Queries: + +```graphql +mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) { + createReview(episode: $ep, review: $review) { + stars + commentary + } +} +``` +Variables `$ep` and `$review` are sent alongside with mutation. Full HTTP request might look like this: +```json +// POST /graphql-endpoint +// Content-Type: application/javascript +// +{ + "query": "mutation CreateReviewForEpisode...", + "variables": { + "ep": "JEDI", + "review": { + "stars": 5, + "commentary": "This is a great movie!" + } + } +} +``` +As you see variables may include complex objects and they will be correctly validated by +**graphql-php** runtime. + +Another nice feature of GraphQL mutations is that they also hold the query for data to be +returned after mutation. In our example mutation will return: +``` +{ + "createReview": { + "stars": 5, + "commentary": "This is a great movie!" + } +} +``` + +# Type System +Conceptually GraphQL type is a collection of fields. Each field in turn +has it's own type which allows to build complex hierarchies. + +Quick example on pseudo-language: +``` +type BlogPost { + title: String! + author: User + body: String +} + +type User { + id: Id! + firstName: String + lastName: String +} +``` + +Type system is a heart of GraphQL integration. That's where **graphql-php** comes into play. + +It provides following tools and primitives to describe your App as hierarchy of types: + + * Primitives for defining **objects** and **interfaces** + * Primitives for defining **enumerations** and **unions** + * Primitives for defining custom **scalar types** + * Built-in scalar types: `ID`, `String`, `Int`, `Float`, `Boolean` + * Built-in type modifiers: `ListOf` and `NonNull` + +Same example expressed in **graphql-php**: +```php + 'User', + 'fields' => [ + 'id' => Type::nonNull(Type::id()), + 'firstName' => Type::string(), + 'lastName' => Type::string() + ] +]); + +$blogPostType = new ObjectType([ + 'name' => 'BlogPost', + 'fields' => [ + 'title' => Type::nonNull(Type::string()), + 'author' => $userType + ] +]); +``` + +# Further Reading +To get deeper understanding of GraphQL concepts - [read the docs on official GraphQL website](http://graphql.org/learn/) + +To get started with **graphql-php** - continue to next section ["Getting Started"](getting-started.md) diff --git a/vendor/webonyx/graphql-php/docs/data-fetching.md b/vendor/webonyx/graphql-php/docs/data-fetching.md new file mode 100644 index 0000000..4bc0cfb --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/data-fetching.md @@ -0,0 +1,273 @@ +# Overview +GraphQL is data-storage agnostic. You can use any underlying data storage engine, including SQL or NoSQL database, +plain files or in-memory data structures. + +In order to convert the GraphQL query to PHP array, **graphql-php** traverses query fields (using depth-first algorithm) and +runs special **resolve** function on each field. This **resolve** function is provided by you as a part of +[field definition](type-system/object-types.md#field-configuration-options) or [query execution call](executing-queries.md#overview). + +Result returned by **resolve** function is directly included in the response (for scalars and enums) +or passed down to nested fields (for objects). + +Let's walk through an example. Consider following GraphQL query: + +```graphql +{ + lastStory { + title + author { + name + } + } +} +``` + +We need a Schema that can fulfill it. On the very top level the Schema contains Query type: + +```php + 'Query', + 'fields' => [ + + 'lastStory' => [ + 'type' => $blogStoryType, + 'resolve' => function() { + return [ + 'id' => 1, + 'title' => 'Example blog post', + 'authorId' => 1 + ]; + } + ] + + ] +]); +``` + +As we see field **lastStory** has **resolve** function that is responsible for fetching data. + +In our example, we simply return array value, but in the real-world application you would query +your database/cache/search index and return the result. + +Since **lastStory** is of composite type **BlogStory** this result is passed down to fields of this type: + +```php + 'BlogStory', + 'fields' => [ + + 'author' => [ + 'type' => $userType, + 'resolve' => function($blogStory) { + $users = [ + 1 => [ + 'id' => 1, + 'name' => 'Smith' + ], + 2 => [ + 'id' => 2, + 'name' => 'Anderson' + ] + ]; + return $users[$blogStory['authorId']]; + } + ], + + 'title' => [ + 'type' => Type::string() + ] + + ] +]); +``` + +Here **$blogStory** is the array returned by **lastStory** field above. + +Again: in the real-world applications you would fetch user data from data store by **authorId** and return it. +Also, note that you don't have to return arrays. You can return any value, **graphql-php** will pass it untouched +to nested resolvers. + +But then the question appears - field **title** has no **resolve** option. How is it resolved? + +There is a default resolver for all fields. When you define your own **resolve** function +for a field you simply override this default resolver. + +# Default Field Resolver +**graphql-php** provides following default field resolver: +```php +fieldName; + $property = null; + + if (is_array($source) || $source instanceof \ArrayAccess) { + if (isset($source[$fieldName])) { + $property = $source[$fieldName]; + } + } else if (is_object($source)) { + if (isset($source->{$fieldName})) { + $property = $source->{$fieldName}; + } + } + + return $property instanceof Closure ? $property($source, $args, $context, $info) : $property; +} +``` + +As you see it returns value by key (for arrays) or property (for objects). +If the value is not set - it returns **null**. + +To override the default resolver, pass it as an argument of [executeQuery](executing-queries.md) call. + +# Default Field Resolver per Type +Sometimes it might be convenient to set default field resolver per type. You can do so by providing +[resolveField option in type config](type-system/object-types.md#configuration-options). For example: + +```php + 'User', + 'fields' => [ + + 'name' => Type::string(), + 'email' => Type::string() + + ], + 'resolveField' => function(User $user, $args, $context, ResolveInfo $info) { + switch ($info->fieldName) { + case 'name': + return $user->getName(); + case 'email': + return $user->getEmail(); + default: + return null; + } + } +]); +``` + +Keep in mind that **field resolver** has precedence over **default field resolver per type** which in turn + has precedence over **default field resolver**. + + +# Solving N+1 Problem +Since: 0.9.0 + +One of the most annoying problems with data fetching is a so-called +[N+1 problem](https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/).
+Consider following GraphQL query: +``` +{ + topStories(limit: 10) { + title + author { + name + email + } + } +} +``` + +Naive field resolution process would require up to 10 calls to the underlying data store to fetch authors for all 10 stories. + +**graphql-php** provides tools to mitigate this problem: it allows you to defer actual field resolution to a later stage +when one batched query could be executed instead of 10 distinct queries. + +Here is an example of **BlogStory** resolver for field **author** that uses deferring: +```php + function($blogStory) { + MyUserBuffer::add($blogStory['authorId']); + + return new GraphQL\Deferred(function () use ($blogStory) { + MyUserBuffer::loadBuffered(); + return MyUserBuffer::get($blogStory['authorId']); + }); +} +``` + +In this example, we fill up the buffer with 10 author ids first. Then **graphql-php** continues +resolving other non-deferred fields until there are none of them left. + +After that, it calls closures wrapped by `GraphQL\Deferred` which in turn load all buffered +ids once (using SQL IN(?), Redis MGET or other similar tools) and returns final field value. + +Originally this approach was advocated by Facebook in their [Dataloader](https://github.com/facebook/dataloader) +project. This solution enables very interesting optimizations at no cost. Consider the following query: + +```graphql +{ + topStories(limit: 10) { + author { + email + } + } + category { + stories(limit: 10) { + author { + email + } + } + } +} +``` + +Even though **author** field is located on different levels of the query - it can be buffered in the same buffer. +In this example, only one query will be executed for all story authors comparing to 20 queries +in a naive implementation. + +# Async PHP +Since: 0.10.0 (version 0.9.0 had slightly different API which still works, but is deprecated) + +If your project runs in an environment that supports async operations +(like HHVM, ReactPHP, Icicle.io, appserver.io, PHP threads, etc) +you can leverage the power of your platform to resolve some fields asynchronously. + +The only requirement: your platform must support the concept of Promises compatible with +[Promises A+](https://promisesaplus.com/) specification. + +To start using this feature, switch facade method for query execution from +**executeQuery** to **promiseToExecute**: + +```php +then(function(ExecutionResult $result) { + return $result->toArray(); +}); +``` + +Where **$promiseAdapter** is an instance of: + +* For [ReactPHP](https://github.com/reactphp/react) (requires **react/promise** as composer dependency):
+ `GraphQL\Executor\Promise\Adapter\ReactPromiseAdapter` + +* Other platforms: write your own class implementing interface:
+ [`GraphQL\Executor\Promise\PromiseAdapter`](reference.md#graphqlexecutorpromisepromiseadapter). + +Then your **resolve** functions should return promises of your platform instead of `GraphQL\Deferred`s. diff --git a/vendor/webonyx/graphql-php/docs/error-handling.md b/vendor/webonyx/graphql-php/docs/error-handling.md new file mode 100644 index 0000000..17b0a2a --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/error-handling.md @@ -0,0 +1,193 @@ +# Errors in GraphQL + +Query execution process never throws exceptions. Instead, all errors are caught and collected. +After execution, they are available in **$errors** prop of +[`GraphQL\Executor\ExecutionResult`](reference.md#graphqlexecutorexecutionresult). + +When the result is converted to a serializable array using its **toArray()** method, all errors are +converted to arrays as well using default error formatting (see below). + +Alternatively, you can apply [custom error filtering and formatting](#custom-error-handling-and-formatting) +for your specific requirements. + +# Default Error formatting +By default, each error entry is converted to an associative array with following structure: + +```php + 'Error message', + 'category' => 'graphql', + 'locations' => [ + ['line' => 1, 'column' => 2] + ], + 'path' => [ + 'listField', + 0, + 'fieldWithException' + ] +]; +``` +Entry at key **locations** points to a character in query string which caused the error. +In some cases (like deep fragment fields) locations will include several entries to track down +the path to field with the error in query. + +Entry at key **path** exists only for errors caused by exceptions thrown in resolvers. +It contains a path from the very root field to actual field value producing an error +(including indexes for list types and field names for composite types). + +**Internal errors** + +As of version **0.10.0**, all exceptions thrown in resolvers are reported with generic message **"Internal server error"**. +This is done to avoid information leak in production environments (e.g. database connection errors, file access errors, etc). + +Only exceptions implementing interface [`GraphQL\Error\ClientAware`](reference.md#graphqlerrorclientaware) and claiming themselves as **safe** will +be reported with a full error message. + +For example: +```php + 'My reported error', + 'category' => 'businessLogic', + 'locations' => [ + ['line' => 10, 'column' => 2] + ], + 'path' => [ + 'path', + 'to', + 'fieldWithException' + ] +]; +``` + +To change default **"Internal server error"** message to something else, use: +``` +GraphQL\Error\FormattedError::setInternalErrorMessage("Unexpected error"); +``` + +# Debugging tools + +During development or debugging use `$result->toArray(true)` to add **debugMessage** key to +each formatted error entry. If you also want to add exception trace - pass flags instead: + +``` +use GraphQL\Error\Debug; +$debug = Debug::INCLUDE_DEBUG_MESSAGE | Debug::INCLUDE_TRACE; +$result = GraphQL::executeQuery(/*args*/)->toArray($debug); +``` + +This will make each error entry to look like this: +```php + 'Actual exception message', + 'message' => 'Internal server error', + 'category' => 'internal', + 'locations' => [ + ['line' => 10, 'column' => 2] + ], + 'path' => [ + 'listField', + 0, + 'fieldWithException' + ], + 'trace' => [ + /* Formatted original exception trace */ + ] +]; +``` + +If you prefer the first resolver exception to be re-thrown, use following flags: +```php +toArray($debug); +``` + +If you only want to re-throw Exceptions that are not marked as safe through the `ClientAware` interface, use +the flag `Debug::RETHROW_UNSAFE_EXCEPTIONS`. + +# Custom Error Handling and Formatting +It is possible to define custom **formatter** and **handler** for result errors. + +**Formatter** is responsible for converting instances of [`GraphQL\Error\Error`](reference.md#graphqlerrorerror) +to an array. **Handler** is useful for error filtering and logging. + +For example, these are default formatter and handler: + +```php +setErrorFormatter($myErrorFormatter) + ->setErrorsHandler($myErrorHandler) + ->toArray(); +``` + +Note that when you pass [debug flags](#debugging-tools) to **toArray()** your custom formatter will still be +decorated with same debugging information mentioned above. + +# Schema Errors +So far we only covered errors which occur during query execution process. But schema definition can +also throw `GraphQL\Error\InvariantViolation` if there is an error in one of type definitions. + +Usually such errors mean that there is some logical error in your schema and it is the only case +when it makes sense to return `500` error code for GraphQL endpoint: + +```php + [FormattedError::createFromException($e)] + ]; + $status = 500; +} + +header('Content-Type: application/json', true, $status); +echo json_encode($body); +``` diff --git a/vendor/webonyx/graphql-php/docs/executing-queries.md b/vendor/webonyx/graphql-php/docs/executing-queries.md new file mode 100644 index 0000000..29388a2 --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/executing-queries.md @@ -0,0 +1,208 @@ +# Using Facade Method +Query execution is a complex process involving multiple steps, including query **parsing**, +**validating** and finally **executing** against your [schema](type-system/schema.md). + +**graphql-php** provides a convenient facade for this process in class +[`GraphQL\GraphQL`](reference.md#graphqlgraphql): + +```php +toArray(); +``` + +Returned array contains **data** and **errors** keys, as described by the +[GraphQL spec](http://facebook.github.io/graphql/#sec-Response-Format). +This array is suitable for further serialization (e.g. using **json_encode**). +See also the section on [error handling and formatting](error-handling.md). + +Description of **executeQuery** method arguments: + +Argument | Type | Notes +------------ | -------- | ----- +schema | [`GraphQL\Type\Schema`](#) | **Required.** Instance of your application [Schema](type-system/schema.md) +queryString | `string` or `GraphQL\Language\AST\DocumentNode` | **Required.** Actual GraphQL query string to be parsed, validated and executed. If you parse query elsewhere before executing - pass corresponding AST document here to avoid new parsing. +rootValue | `mixed` | Any value that represents a root of your data graph. It is passed as the 1st argument to field resolvers of [Query type](type-system/schema.md#query-and-mutation-types). Can be omitted or set to null if actual root values are fetched by Query type itself. +context | `mixed` | Any value that holds information shared between all field resolvers. Most often they use it to pass currently logged in user, locale details, etc.

It will be available as the 3rd argument in all field resolvers. (see section on [Field Definitions](type-system/object-types.md#field-configuration-options) for reference) **graphql-php** never modifies this value and passes it *as is* to all underlying resolvers. +variableValues | `array` | Map of variable values passed along with query string. See section on [query variables on official GraphQL website](http://graphql.org/learn/queries/#variables). Note that while variableValues must be an associative array, the values inside it can be nested using \stdClass if desired. +operationName | `string` | Allows the caller to specify which operation in queryString will be run, in cases where queryString contains multiple top-level operations. +fieldResolver | `callable` | A resolver function to use when one is not provided by the schema. If not provided, the [default field resolver is used](data-fetching.md#default-field-resolver). +validationRules | `array` | A set of rules for query validation step. The default value is all available rules. Empty array would allow skipping query validation (may be convenient for persisted queries which are validated before persisting and assumed valid during execution) + +# Using Server +If you are building HTTP GraphQL API, you may prefer our Standard Server +(compatible with [express-graphql](https://github.com/graphql/express-graphql)). +It supports more features out of the box, including parsing HTTP requests, producing a spec-compliant response; [batched queries](#query-batching); persisted queries. + +Usage example (with plain PHP): + +```php +handleRequest(); // parses PHP globals and emits response +``` + +Server also supports [PSR-7 request/response interfaces](http://www.php-fig.org/psr/psr-7/): +```php +processPsrRequest($psrRequest, $psrResponse, $psrBodyStream); + + +// Alternatively create PSR-7 response yourself: + +/** @var ExecutionResult|ExecutionResult[] $result */ +$result = $server->executePsrRequest($psrRequest); +$psrResponse = new SomePsr7ResponseImplementation(json_encode($result)); +``` + +PSR-7 is useful when you want to integrate the server into existing framework: + +- [PSR-7 for Laravel](https://laravel.com/docs/5.1/requests#psr7-requests) +- [Symfony PSR-7 Bridge](https://symfony.com/doc/current/components/psr7.html) +- [Slim](https://www.slimframework.com/docs/concepts/value-objects.html) +- [Zend Expressive](http://zendframework.github.io/zend-expressive/) + +## Server configuration options + +Argument | Type | Notes +------------ | -------- | ----- +schema | [`Schema`](reference.md#graphqltypeschema) | **Required.** Instance of your application [Schema](type-system/schema/) +rootValue | `mixed` | Any value that represents a root of your data graph. It is passed as the 1st argument to field resolvers of [Query type](type-system/schema.md#query-and-mutation-types). Can be omitted or set to null if actual root values are fetched by Query type itself. +context | `mixed` | Any value that holds information shared between all field resolvers. Most often they use it to pass currently logged in user, locale details, etc.

It will be available as the 3rd argument in all field resolvers. (see section on [Field Definitions](type-system/object-types.md#field-configuration-options) for reference) **graphql-php** never modifies this value and passes it *as is* to all underlying resolvers. +fieldResolver | `callable` | A resolver function to use when one is not provided by the schema. If not provided, the [default field resolver is used](data-fetching.md#default-field-resolver). +validationRules | `array` or `callable` | A set of rules for query validation step. The default value is all available rules. The empty array would allow skipping query validation (may be convenient for persisted queries which are validated before persisting and assumed valid during execution).

Pass `callable` to return different validation rules for different queries (e.g. empty array for persisted query and a full list of rules for regular queries). When passed, it is expected to have the following signature:

**function ([OperationParams](reference.md#graphqlserveroperationparams) $params, DocumentNode $node, $operationType): array** +queryBatching | `bool` | Flag indicating whether this server supports query batching ([apollo-style](https://dev-blog.apollodata.com/query-batching-in-apollo-63acfd859862)).

Defaults to **false** +debug | `int` | Debug flags. See [docs on error debugging](error-handling.md#debugging-tools) (flag values are the same). +persistentQueryLoader | `callable` | A function which is called to fetch actual query when server encounters **queryId** in request vs **query**.

The server does not implement persistence part (which you will have to build on your own), but it allows you to execute queries which were persisted previously.

Expected function signature:
**function ($queryId, [OperationParams](reference.md#graphqlserveroperationparams) $params)**

Function is expected to return query **string** or parsed **DocumentNode**

[Read more about persisted queries](https://dev-blog.apollodata.com/persisted-graphql-queries-with-apollo-client-119fd7e6bba5). +errorFormatter | `callable` | Custom error formatter. See [error handling docs](error-handling.md#custom-error-handling-and-formatting). +errorsHandler | `callable` | Custom errors handler. See [error handling docs](error-handling.md#custom-error-handling-and-formatting). +promiseAdapter | [`PromiseAdapter`](reference.md#graphqlexecutorpromisepromiseadapter) | Required for [Async PHP](data-fetching/#async-php) only. + +**Server config instance** + +If you prefer fluid interface for config with autocomplete in IDE and static time validation, +use [`GraphQL\Server\ServerConfig`](reference.md#graphqlserverserverconfig) instead of an array: + +```php +setSchema($schema) + ->setErrorFormatter($myFormatter) + ->setDebug($debug) +; + +$server = new StandardServer($config); +``` + +## Query batching +Standard Server supports query batching ([apollo-style](https://dev-blog.apollodata.com/query-batching-in-apollo-63acfd859862)). + +One of the major benefits of Server over a sequence of **executeQuery()** calls is that +[Deferred resolvers](data-fetching.md#solving-n1-problem) won't be isolated in queries. +So for example following batch will require single DB request (if user field is deferred): + +```json +[ + { + "query": "{user(id: 1) { id }}" + }, + { + "query": "{user(id: 2) { id }}" + }, + { + "query": "{user(id: 3) { id }}" + } +] +``` + +To enable query batching, pass **queryBatching** option in server config: +```php + true +]); +``` + +# Custom Validation Rules +Before execution, a query is validated using a set of standard rules defined by the GraphQL spec. +It is possible to override standard set of rules globally or per execution. + +Add rules globally: +```php + $myValiationRules +]); +``` diff --git a/vendor/webonyx/graphql-php/docs/getting-started.md b/vendor/webonyx/graphql-php/docs/getting-started.md new file mode 100644 index 0000000..4477cda --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/getting-started.md @@ -0,0 +1,125 @@ +# Prerequisites +This documentation assumes your familiarity with GraphQL concepts. If it is not the case - +first learn about GraphQL on [the official website](http://graphql.org/learn/). + +# Installation + +Using [composer](https://getcomposer.org/doc/00-intro.md), run: + +```sh +composer require webonyx/graphql-php +``` + +# Upgrading +We try to keep library releases backwards compatible. But when breaking changes are inevitable +they are explained in [upgrade instructions](https://github.com/webonyx/graphql-php/blob/master/UPGRADE.md). + +# Install Tools (optional) +While it is possible to communicate with GraphQL API using regular HTTP tools it is way +more convenient for humans to use [GraphiQL](https://github.com/graphql/graphiql) - an in-browser +IDE for exploring GraphQL APIs. + +It provides syntax-highlighting, auto-completion and auto-generated documentation for +GraphQL API. + +The easiest way to use it is to install one of the existing Google Chrome extensions: + + - [ChromeiQL](https://chrome.google.com/webstore/detail/chromeiql/fkkiamalmpiidkljmicmjfbieiclmeij) + - [GraphiQL Feen](https://chrome.google.com/webstore/detail/graphiql-feen/mcbfdonlkfpbfdpimkjilhdneikhfklp) + +Alternatively, you can follow instructions on [the GraphiQL](https://github.com/graphql/graphiql) +page and install it locally. + + +# Hello World +Let's create a type system that will be capable to process following simple query: +``` +query { + echo(message: "Hello World") +} +``` + +To do so we need an object type with field `echo`: + +```php + 'Query', + 'fields' => [ + 'echo' => [ + 'type' => Type::string(), + 'args' => [ + 'message' => Type::nonNull(Type::string()), + ], + 'resolve' => function ($root, $args) { + return $root['prefix'] . $args['message']; + } + ], + ], +]); + +``` + +(Note: type definition can be expressed in [different styles](type-system/index.md#type-definition-styles), +but this example uses **inline** style for simplicity) + +The interesting piece here is **resolve** option of field definition. It is responsible for returning +a value of our field. Values of **scalar** fields will be directly included in response while values of +**composite** fields (objects, interfaces, unions) will be passed down to nested field resolvers +(not in this example though). + +Now when our type is ready, let's create GraphQL endpoint file for it **graphql.php**: + +```php + $queryType +]); + +$rawInput = file_get_contents('php://input'); +$input = json_decode($rawInput, true); +$query = $input['query']; +$variableValues = isset($input['variables']) ? $input['variables'] : null; + +try { + $rootValue = ['prefix' => 'You said: ']; + $result = GraphQL::executeQuery($schema, $query, $rootValue, null, $variableValues); + $output = $result->toArray(); +} catch (\Exception $e) { + $output = [ + 'errors' => [ + [ + 'message' => $e->getMessage() + ] + ] + ]; +} +header('Content-Type: application/json'); +echo json_encode($output); +``` + +Our example is finished. Try it by running: +```sh +php -S localhost:8080 graphql.php +curl http://localhost:8080 -d '{"query": "query { echo(message: \"Hello World\") }" }' +``` + +Check out the full [source code](https://github.com/webonyx/graphql-php/blob/master/examples/00-hello-world) of this example +which also includes simple mutation. + +Obviously hello world only scratches the surface of what is possible. +So check out next example, which is closer to real-world apps. +Or keep reading about [schema definition](type-system/index.md). + +# Blog example +It is often easier to start with a full-featured example and then get back to documentation +for your own work. + +Check out [Blog example of GraphQL API](https://github.com/webonyx/graphql-php/tree/master/examples/01-blog). +It is quite close to real-world GraphQL hierarchies. Follow instructions and try it yourself in ~10 minutes. diff --git a/vendor/webonyx/graphql-php/docs/how-it-works.md b/vendor/webonyx/graphql-php/docs/how-it-works.md new file mode 100644 index 0000000..fd57e2b --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/how-it-works.md @@ -0,0 +1,35 @@ +# Overview +Following reading describes implementation details of query execution process. It may clarify some +internals of GraphQL runtime but is not required to use it. + +# Parsing + +TODOC + +# Validating +TODOC + +# Executing +TODOC + +# Errors explained +There are 3 types of errors in GraphQL: + +- **Syntax**: query has invalid syntax and could not be parsed; +- **Validation**: query is incompatible with type system (e.g. unknown field is requested); +- **Execution**: occurs when some field resolver throws (or returns unexpected value). + +Obviously, when **Syntax** or **Validation** error is detected - the process is interrupted and +the query is not executed. + +Execution process never throws exceptions. Instead, all errors are caught and collected in +execution result. + +GraphQL is forgiving to **Execution** errors which occur in resolvers of nullable fields. +If such field throws or returns unexpected value the value of the field in response will be simply +replaced with **null** and error entry will be registered. + +If an exception is thrown in the non-null field - error bubbles up to the first nullable field. +This nullable field is replaced with **null** and error entry is added to the result. +If all fields up to the root are non-null - **data** entry will be removed from the result +and only **errors** key will be presented. diff --git a/vendor/webonyx/graphql-php/docs/index.md b/vendor/webonyx/graphql-php/docs/index.md new file mode 100644 index 0000000..a031a42 --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/index.md @@ -0,0 +1,55 @@ +[![GitHub stars](https://img.shields.io/github/stars/webonyx/graphql-php.svg?style=social&label=Star)](https://github.com/webonyx/graphql-php) +[![Build Status](https://travis-ci.org/webonyx/graphql-php.svg?branch=master)](https://travis-ci.org/webonyx/graphql-php) +[![Coverage Status](https://coveralls.io/repos/github/webonyx/graphql-php/badge.svg)](https://coveralls.io/github/webonyx/graphql-php) +[![Latest Stable Version](https://poser.pugx.org/webonyx/graphql-php/version)](https://packagist.org/packages/webonyx/graphql-php) +[![License](https://poser.pugx.org/webonyx/graphql-php/license)](https://packagist.org/packages/webonyx/graphql-php) + +# About GraphQL + +GraphQL is a modern way to build HTTP APIs consumed by the web and mobile clients. +It is intended to be an alternative to REST and SOAP APIs (even for **existing applications**). + +GraphQL itself is a [specification](https://github.com/facebook/graphql) designed by Facebook +engineers. Various implementations of this specification were written +[in different languages and environments](http://graphql.org/code/). + +Great overview of GraphQL features and benefits is presented on [the official website](http://graphql.org/). +All of them equally apply to this PHP implementation. + + +# About graphql-php + +**graphql-php** is a feature-complete implementation of GraphQL specification in PHP (5.5+, 7.0+). +It was originally inspired by [reference JavaScript implementation](https://github.com/graphql/graphql-js) +published by Facebook. + +This library is a thin wrapper around your existing data layer and business logic. +It doesn't dictate how these layers are implemented or which storage engines +are used. Instead, it provides tools for creating rich API for your existing app. + +Library features include: + + - Primitives to express your app as a [Type System](type-system/index.md) + - Validation and introspection of this Type System (for compatibility with tools like [GraphiQL](complementary-tools.md#tools)) + - Parsing, validating and [executing GraphQL queries](executing-queries.md) against this Type System + - Rich [error reporting](error-handling.md), including query validation and execution errors + - Optional tools for [parsing GraphQL Type language](type-system/type-language.md) + - Tools for [batching requests](data-fetching.md#solving-n1-problem) to backend storage + - [Async PHP platforms support](data-fetching.md#async-php) via promises + - [Standard HTTP server](executing-queries.md#using-server) + +Also, several [complementary tools](complementary-tools.md) are available which provide integrations with +existing PHP frameworks, add support for Relay, etc. + +## Current Status +The first version of this library (v0.1) was released on August 10th 2015. + +The current version supports all features described by GraphQL specification +as well as some experimental features like +[Schema Language parser](type-system/type-language.md) and +[Schema printer](reference.md#graphqlutilsschemaprinter). + +Ready for real-world usage. + +## GitHub +Project source code is [hosted on GitHub](https://github.com/webonyx/graphql-php). diff --git a/vendor/webonyx/graphql-php/docs/reference.md b/vendor/webonyx/graphql-php/docs/reference.md new file mode 100644 index 0000000..e36e2cd --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/reference.md @@ -0,0 +1,2336 @@ +# GraphQL\GraphQL +This is the primary facade for fulfilling GraphQL operations. +See [related documentation](executing-queries.md). + +**Class Methods:** +```php +/** + * Executes graphql query. + * + * More sophisticated GraphQL servers, such as those which persist queries, + * may wish to separate the validation and execution phases to a static time + * tooling step, and a server runtime step. + * + * Available options: + * + * schema: + * The GraphQL type system to use when validating and executing a query. + * source: + * A GraphQL language formatted string representing the requested operation. + * rootValue: + * The value provided as the first argument to resolver functions on the top + * level type (e.g. the query object type). + * context: + * The value provided as the third argument to all resolvers. + * Use this to pass current session, user data, etc + * variableValues: + * A mapping of variable name to runtime value to use for all variables + * defined in the requestString. + * operationName: + * The name of the operation to use if requestString contains multiple + * possible operations. Can be omitted if requestString contains only + * one operation. + * fieldResolver: + * A resolver function to use when one is not provided by the schema. + * If not provided, the default field resolver is used (which looks for a + * value on the source value with the field's name). + * validationRules: + * A set of rules for query validation step. Default value is all available rules. + * Empty array would allow to skip query validation (may be convenient for persisted + * queries which are validated before persisting and assumed valid during execution) + * + * @param string|DocumentNode $source + * @param mixed $rootValue + * @param mixed $context + * @param mixed[]|null $variableValues + * @param ValidationRule[] $validationRules + * + * @api + */ +static function executeQuery( + GraphQL\Type\Schema $schema, + $source, + $rootValue = null, + $context = null, + $variableValues = null, + string $operationName = null, + callable $fieldResolver = null, + array $validationRules = null +) +``` + +```php +/** + * Same as executeQuery(), but requires PromiseAdapter and always returns a Promise. + * Useful for Async PHP platforms. + * + * @param string|DocumentNode $source + * @param mixed $rootValue + * @param mixed $context + * @param mixed[]|null $variableValues + * @param ValidationRule[]|null $validationRules + * + * @api + */ +static function promiseToExecute( + GraphQL\Executor\Promise\PromiseAdapter $promiseAdapter, + GraphQL\Type\Schema $schema, + $source, + $rootValue = null, + $context = null, + $variableValues = null, + string $operationName = null, + callable $fieldResolver = null, + array $validationRules = null +) +``` + +```php +/** + * Returns directives defined in GraphQL spec + * + * @return Directive[] + * + * @api + */ +static function getStandardDirectives() +``` + +```php +/** + * Returns types defined in GraphQL spec + * + * @return Type[] + * + * @api + */ +static function getStandardTypes() +``` + +```php +/** + * Replaces standard types with types from this list (matching by name) + * Standard types not listed here remain untouched. + * + * @param Type[] $types + * + * @api + */ +static function overrideStandardTypes(array $types) +``` + +```php +/** + * Returns standard validation rules implementing GraphQL spec + * + * @return ValidationRule[] + * + * @api + */ +static function getStandardValidationRules() +``` + +```php +/** + * Set default resolver implementation + * + * @api + */ +static function setDefaultFieldResolver(callable $fn) +``` +# GraphQL\Type\Definition\Type +Registry of standard GraphQL types +and a base class for all other types. + +**Class Methods:** +```php +/** + * @return IDType + * + * @api + */ +static function id() +``` + +```php +/** + * @return StringType + * + * @api + */ +static function string() +``` + +```php +/** + * @return BooleanType + * + * @api + */ +static function boolean() +``` + +```php +/** + * @return IntType + * + * @api + */ +static function int() +``` + +```php +/** + * @return FloatType + * + * @api + */ +static function float() +``` + +```php +/** + * @param Type|ObjectType|InterfaceType|UnionType|ScalarType|InputObjectType|EnumType|ListOfType|NonNull $wrappedType + * + * @return ListOfType + * + * @api + */ +static function listOf($wrappedType) +``` + +```php +/** + * @param NullableType $wrappedType + * + * @return NonNull + * + * @api + */ +static function nonNull($wrappedType) +``` + +```php +/** + * @param Type $type + * + * @return bool + * + * @api + */ +static function isInputType($type) +``` + +```php +/** + * @param Type $type + * + * @return ObjectType|InterfaceType|UnionType|ScalarType|InputObjectType|EnumType + * + * @api + */ +static function getNamedType($type) +``` + +```php +/** + * @param Type $type + * + * @return bool + * + * @api + */ +static function isOutputType($type) +``` + +```php +/** + * @param Type $type + * + * @return bool + * + * @api + */ +static function isLeafType($type) +``` + +```php +/** + * @param Type $type + * + * @return bool + * + * @api + */ +static function isCompositeType($type) +``` + +```php +/** + * @param Type $type + * + * @return bool + * + * @api + */ +static function isAbstractType($type) +``` + +```php +/** + * @param Type $type + * + * @return bool + * + * @api + */ +static function isType($type) +``` + +```php +/** + * @param Type $type + * + * @return NullableType + * + * @api + */ +static function getNullableType($type) +``` +# GraphQL\Type\Definition\ResolveInfo +Structure containing information useful for field resolution process. + +Passed as 4th argument to every field resolver. See [docs on field resolving (data fetching)](data-fetching.md). + +**Class Props:** +```php +/** + * The name of the field being resolved. + * + * @api + * @var string + */ +public $fieldName; + +/** + * AST of all nodes referencing this field in the query. + * + * @api + * @var FieldNode[] + */ +public $fieldNodes; + +/** + * Expected return type of the field being resolved. + * + * @api + * @var ScalarType|ObjectType|InterfaceType|UnionType|EnumType|ListOfType|NonNull + */ +public $returnType; + +/** + * Parent type of the field being resolved. + * + * @api + * @var ObjectType + */ +public $parentType; + +/** + * Path to this field from the very root value. + * + * @api + * @var string[][] + */ +public $path; + +/** + * Instance of a schema used for execution. + * + * @api + * @var Schema + */ +public $schema; + +/** + * AST of all fragments defined in query. + * + * @api + * @var FragmentDefinitionNode[] + */ +public $fragments; + +/** + * Root value passed to query execution. + * + * @api + * @var mixed + */ +public $rootValue; + +/** + * AST of operation definition node (query, mutation). + * + * @api + * @var OperationDefinitionNode|null + */ +public $operation; + +/** + * Array of variables passed to query execution. + * + * @api + * @var mixed[] + */ +public $variableValues; +``` + +**Class Methods:** +```php +/** + * Helper method that returns names of all fields selected in query for + * $this->fieldName up to $depth levels. + * + * Example: + * query MyQuery{ + * { + * root { + * id, + * nested { + * nested1 + * nested2 { + * nested3 + * } + * } + * } + * } + * + * Given this ResolveInfo instance is a part of "root" field resolution, and $depth === 1, + * method will return: + * [ + * 'id' => true, + * 'nested' => [ + * nested1 => true, + * nested2 => true + * ] + * ] + * + * Warning: this method it is a naive implementation which does not take into account + * conditional typed fragments. So use it with care for fields of interface and union types. + * + * @param int $depth How many levels to include in output + * + * @return bool[] + * + * @api + */ +function getFieldSelection($depth = 0) +``` +# GraphQL\Language\DirectiveLocation +List of available directive locations + +**Class Constants:** +```php +const QUERY = "QUERY"; +const MUTATION = "MUTATION"; +const SUBSCRIPTION = "SUBSCRIPTION"; +const FIELD = "FIELD"; +const FRAGMENT_DEFINITION = "FRAGMENT_DEFINITION"; +const FRAGMENT_SPREAD = "FRAGMENT_SPREAD"; +const INLINE_FRAGMENT = "INLINE_FRAGMENT"; +const SCHEMA = "SCHEMA"; +const SCALAR = "SCALAR"; +const OBJECT = "OBJECT"; +const FIELD_DEFINITION = "FIELD_DEFINITION"; +const ARGUMENT_DEFINITION = "ARGUMENT_DEFINITION"; +const IFACE = "INTERFACE"; +const UNION = "UNION"; +const ENUM = "ENUM"; +const ENUM_VALUE = "ENUM_VALUE"; +const INPUT_OBJECT = "INPUT_OBJECT"; +const INPUT_FIELD_DEFINITION = "INPUT_FIELD_DEFINITION"; +``` + +# GraphQL\Type\SchemaConfig +Schema configuration class. +Could be passed directly to schema constructor. List of options accepted by **create** method is +[described in docs](type-system/schema.md#configuration-options). + +Usage example: + + $config = SchemaConfig::create() + ->setQuery($myQueryType) + ->setTypeLoader($myTypeLoader); + + $schema = new Schema($config); + +**Class Methods:** +```php +/** + * Converts an array of options to instance of SchemaConfig + * (or just returns empty config when array is not passed). + * + * @param mixed[] $options + * + * @return SchemaConfig + * + * @api + */ +static function create(array $options = []) +``` + +```php +/** + * @return ObjectType + * + * @api + */ +function getQuery() +``` + +```php +/** + * @param ObjectType $query + * + * @return SchemaConfig + * + * @api + */ +function setQuery($query) +``` + +```php +/** + * @return ObjectType + * + * @api + */ +function getMutation() +``` + +```php +/** + * @param ObjectType $mutation + * + * @return SchemaConfig + * + * @api + */ +function setMutation($mutation) +``` + +```php +/** + * @return ObjectType + * + * @api + */ +function getSubscription() +``` + +```php +/** + * @param ObjectType $subscription + * + * @return SchemaConfig + * + * @api + */ +function setSubscription($subscription) +``` + +```php +/** + * @return Type[] + * + * @api + */ +function getTypes() +``` + +```php +/** + * @param Type[]|callable $types + * + * @return SchemaConfig + * + * @api + */ +function setTypes($types) +``` + +```php +/** + * @return Directive[] + * + * @api + */ +function getDirectives() +``` + +```php +/** + * @param Directive[] $directives + * + * @return SchemaConfig + * + * @api + */ +function setDirectives(array $directives) +``` + +```php +/** + * @return callable + * + * @api + */ +function getTypeLoader() +``` + +```php +/** + * @return SchemaConfig + * + * @api + */ +function setTypeLoader(callable $typeLoader) +``` +# GraphQL\Type\Schema +Schema Definition (see [related docs](type-system/schema.md)) + +A Schema is created by supplying the root types of each type of operation: +query, mutation (optional) and subscription (optional). A schema definition is +then supplied to the validator and executor. Usage Example: + + $schema = new GraphQL\Type\Schema([ + 'query' => $MyAppQueryRootType, + 'mutation' => $MyAppMutationRootType, + ]); + +Or using Schema Config instance: + + $config = GraphQL\Type\SchemaConfig::create() + ->setQuery($MyAppQueryRootType) + ->setMutation($MyAppMutationRootType); + + $schema = new GraphQL\Type\Schema($config); + +**Class Methods:** +```php +/** + * @param mixed[]|SchemaConfig $config + * + * @api + */ +function __construct($config) +``` + +```php +/** + * Returns array of all types in this schema. Keys of this array represent type names, values are instances + * of corresponding type definitions + * + * This operation requires full schema scan. Do not use in production environment. + * + * @return Type[] + * + * @api + */ +function getTypeMap() +``` + +```php +/** + * Returns a list of directives supported by this schema + * + * @return Directive[] + * + * @api + */ +function getDirectives() +``` + +```php +/** + * Returns schema query type + * + * @return ObjectType + * + * @api + */ +function getQueryType() +``` + +```php +/** + * Returns schema mutation type + * + * @return ObjectType|null + * + * @api + */ +function getMutationType() +``` + +```php +/** + * Returns schema subscription + * + * @return ObjectType|null + * + * @api + */ +function getSubscriptionType() +``` + +```php +/** + * @return SchemaConfig + * + * @api + */ +function getConfig() +``` + +```php +/** + * Returns type by it's name + * + * @param string $name + * + * @return Type|null + * + * @api + */ +function getType($name) +``` + +```php +/** + * Returns all possible concrete types for given abstract type + * (implementations for interfaces and members of union type for unions) + * + * This operation requires full schema scan. Do not use in production environment. + * + * @return ObjectType[] + * + * @api + */ +function getPossibleTypes(GraphQL\Type\Definition\AbstractType $abstractType) +``` + +```php +/** + * Returns true if object type is concrete type of given abstract type + * (implementation for interfaces and members of union type for unions) + * + * @return bool + * + * @api + */ +function isPossibleType( + GraphQL\Type\Definition\AbstractType $abstractType, + GraphQL\Type\Definition\ObjectType $possibleType +) +``` + +```php +/** + * Returns instance of directive by name + * + * @param string $name + * + * @return Directive + * + * @api + */ +function getDirective($name) +``` + +```php +/** + * Validates schema. + * + * This operation requires full schema scan. Do not use in production environment. + * + * @throws InvariantViolation + * + * @api + */ +function assertValid() +``` + +```php +/** + * Validates schema. + * + * This operation requires full schema scan. Do not use in production environment. + * + * @return InvariantViolation[]|Error[] + * + * @api + */ +function validate() +``` +# GraphQL\Language\Parser +Parses string containing GraphQL query or [type definition](type-system/type-language.md) to Abstract Syntax Tree. + +**Class Methods:** +```php +/** + * Given a GraphQL source, parses it into a `GraphQL\Language\AST\DocumentNode`. + * Throws `GraphQL\Error\SyntaxError` if a syntax error is encountered. + * + * Available options: + * + * noLocation: boolean, + * (By default, the parser creates AST nodes that know the location + * in the source that they correspond to. This configuration flag + * disables that behavior for performance or testing.) + * + * allowLegacySDLEmptyFields: boolean + * If enabled, the parser will parse empty fields sets in the Schema + * Definition Language. Otherwise, the parser will follow the current + * specification. + * + * This option is provided to ease adoption of the final SDL specification + * and will be removed in a future major release. + * + * allowLegacySDLImplementsInterfaces: boolean + * If enabled, the parser will parse implemented interfaces with no `&` + * character between each interface. Otherwise, the parser will follow the + * current specification. + * + * This option is provided to ease adoption of the final SDL specification + * and will be removed in a future major release. + * + * experimentalFragmentVariables: boolean, + * (If enabled, the parser will understand and parse variable definitions + * contained in a fragment definition. They'll be represented in the + * `variableDefinitions` field of the FragmentDefinitionNode. + * + * The syntax is identical to normal, query-defined variables. For example: + * + * fragment A($var: Boolean = false) on T { + * ... + * } + * + * Note: this feature is experimental and may change or be removed in the + * future.) + * + * @param Source|string $source + * @param bool[] $options + * + * @return DocumentNode + * + * @throws SyntaxError + * + * @api + */ +static function parse($source, array $options = []) +``` + +```php +/** + * Given a string containing a GraphQL value (ex. `[42]`), parse the AST for + * that value. + * Throws `GraphQL\Error\SyntaxError` if a syntax error is encountered. + * + * This is useful within tools that operate upon GraphQL Values directly and + * in isolation of complete GraphQL documents. + * + * Consider providing the results to the utility function: `GraphQL\Utils\AST::valueFromAST()`. + * + * @param Source|string $source + * @param bool[] $options + * + * @return BooleanValueNode|EnumValueNode|FloatValueNode|IntValueNode|ListValueNode|ObjectValueNode|StringValueNode|VariableNode + * + * @api + */ +static function parseValue($source, array $options = []) +``` + +```php +/** + * Given a string containing a GraphQL Type (ex. `[Int!]`), parse the AST for + * that type. + * Throws `GraphQL\Error\SyntaxError` if a syntax error is encountered. + * + * This is useful within tools that operate upon GraphQL Types directly and + * in isolation of complete GraphQL documents. + * + * Consider providing the results to the utility function: `GraphQL\Utils\AST::typeFromAST()`. + * + * @param Source|string $source + * @param bool[] $options + * + * @return ListTypeNode|NameNode|NonNullTypeNode + * + * @api + */ +static function parseType($source, array $options = []) +``` +# GraphQL\Language\Printer +Prints AST to string. Capable of printing GraphQL queries and Type definition language. +Useful for pretty-printing queries or printing back AST for logging, documentation, etc. + +Usage example: + +```php +$query = 'query myQuery {someField}'; +$ast = GraphQL\Language\Parser::parse($query); +$printed = GraphQL\Language\Printer::doPrint($ast); +``` + +**Class Methods:** +```php +/** + * Prints AST to string. Capable of printing GraphQL queries and Type definition language. + * + * @param Node $ast + * + * @return string + * + * @api + */ +static function doPrint($ast) +``` +# GraphQL\Language\Visitor +Utility for efficient AST traversal and modification. + +`visit()` will walk through an AST using a depth first traversal, calling +the visitor's enter function at each node in the traversal, and calling the +leave function after visiting that node and all of it's child nodes. + +By returning different values from the enter and leave functions, the +behavior of the visitor can be altered, including skipping over a sub-tree of +the AST (by returning false), editing the AST by returning a value or null +to remove the value, or to stop the whole traversal by returning BREAK. + +When using `visit()` to edit an AST, the original AST will not be modified, and +a new version of the AST with the changes applied will be returned from the +visit function. + + $editedAST = Visitor::visit($ast, [ + 'enter' => function ($node, $key, $parent, $path, $ancestors) { + // return + // null: no action + // Visitor::skipNode(): skip visiting this node + // Visitor::stop(): stop visiting altogether + // Visitor::removeNode(): delete this node + // any value: replace this node with the returned value + }, + 'leave' => function ($node, $key, $parent, $path, $ancestors) { + // return + // null: no action + // Visitor::stop(): stop visiting altogether + // Visitor::removeNode(): delete this node + // any value: replace this node with the returned value + } + ]); + +Alternatively to providing enter() and leave() functions, a visitor can +instead provide functions named the same as the [kinds of AST nodes](reference.md#graphqllanguageastnodekind), +or enter/leave visitors at a named key, leading to four permutations of +visitor API: + +1) Named visitors triggered when entering a node a specific kind. + + Visitor::visit($ast, [ + 'Kind' => function ($node) { + // enter the "Kind" node + } + ]); + +2) Named visitors that trigger upon entering and leaving a node of + a specific kind. + + Visitor::visit($ast, [ + 'Kind' => [ + 'enter' => function ($node) { + // enter the "Kind" node + } + 'leave' => function ($node) { + // leave the "Kind" node + } + ] + ]); + +3) Generic visitors that trigger upon entering and leaving any node. + + Visitor::visit($ast, [ + 'enter' => function ($node) { + // enter any node + }, + 'leave' => function ($node) { + // leave any node + } + ]); + +4) Parallel visitors for entering and leaving nodes of a specific kind. + + Visitor::visit($ast, [ + 'enter' => [ + 'Kind' => function($node) { + // enter the "Kind" node + } + }, + 'leave' => [ + 'Kind' => function ($node) { + // leave the "Kind" node + } + ] + ]); + +**Class Methods:** +```php +/** + * Visit the AST (see class description for details) + * + * @param Node|ArrayObject|stdClass $root + * @param callable[] $visitor + * @param mixed[]|null $keyMap + * + * @return Node|mixed + * + * @throws Exception + * + * @api + */ +static function visit($root, $visitor, $keyMap = null) +``` + +```php +/** + * Returns marker for visitor break + * + * @return VisitorOperation + * + * @api + */ +static function stop() +``` + +```php +/** + * Returns marker for skipping current node + * + * @return VisitorOperation + * + * @api + */ +static function skipNode() +``` + +```php +/** + * Returns marker for removing a node + * + * @return VisitorOperation + * + * @api + */ +static function removeNode() +``` +# GraphQL\Language\AST\NodeKind + + +**Class Constants:** +```php +const NAME = "Name"; +const DOCUMENT = "Document"; +const OPERATION_DEFINITION = "OperationDefinition"; +const VARIABLE_DEFINITION = "VariableDefinition"; +const VARIABLE = "Variable"; +const SELECTION_SET = "SelectionSet"; +const FIELD = "Field"; +const ARGUMENT = "Argument"; +const FRAGMENT_SPREAD = "FragmentSpread"; +const INLINE_FRAGMENT = "InlineFragment"; +const FRAGMENT_DEFINITION = "FragmentDefinition"; +const INT = "IntValue"; +const FLOAT = "FloatValue"; +const STRING = "StringValue"; +const BOOLEAN = "BooleanValue"; +const ENUM = "EnumValue"; +const NULL = "NullValue"; +const LST = "ListValue"; +const OBJECT = "ObjectValue"; +const OBJECT_FIELD = "ObjectField"; +const DIRECTIVE = "Directive"; +const NAMED_TYPE = "NamedType"; +const LIST_TYPE = "ListType"; +const NON_NULL_TYPE = "NonNullType"; +const SCHEMA_DEFINITION = "SchemaDefinition"; +const OPERATION_TYPE_DEFINITION = "OperationTypeDefinition"; +const SCALAR_TYPE_DEFINITION = "ScalarTypeDefinition"; +const OBJECT_TYPE_DEFINITION = "ObjectTypeDefinition"; +const FIELD_DEFINITION = "FieldDefinition"; +const INPUT_VALUE_DEFINITION = "InputValueDefinition"; +const INTERFACE_TYPE_DEFINITION = "InterfaceTypeDefinition"; +const UNION_TYPE_DEFINITION = "UnionTypeDefinition"; +const ENUM_TYPE_DEFINITION = "EnumTypeDefinition"; +const ENUM_VALUE_DEFINITION = "EnumValueDefinition"; +const INPUT_OBJECT_TYPE_DEFINITION = "InputObjectTypeDefinition"; +const SCALAR_TYPE_EXTENSION = "ScalarTypeExtension"; +const OBJECT_TYPE_EXTENSION = "ObjectTypeExtension"; +const INTERFACE_TYPE_EXTENSION = "InterfaceTypeExtension"; +const UNION_TYPE_EXTENSION = "UnionTypeExtension"; +const ENUM_TYPE_EXTENSION = "EnumTypeExtension"; +const INPUT_OBJECT_TYPE_EXTENSION = "InputObjectTypeExtension"; +const DIRECTIVE_DEFINITION = "DirectiveDefinition"; +const SCHEMA_EXTENSION = "SchemaExtension"; +``` + +# GraphQL\Executor\Executor +Implements the "Evaluating requests" section of the GraphQL specification. + +**Class Methods:** +```php +/** + * Executes DocumentNode against given $schema. + * + * Always returns ExecutionResult and never throws. All errors which occur during operation + * execution are collected in `$result->errors`. + * + * @param mixed|null $rootValue + * @param mixed|null $contextValue + * @param mixed[]|ArrayAccess|null $variableValues + * @param string|null $operationName + * + * @return ExecutionResult|Promise + * + * @api + */ +static function execute( + GraphQL\Type\Schema $schema, + GraphQL\Language\AST\DocumentNode $documentNode, + $rootValue = null, + $contextValue = null, + $variableValues = null, + $operationName = null, + callable $fieldResolver = null +) +``` + +```php +/** + * Same as execute(), but requires promise adapter and returns a promise which is always + * fulfilled with an instance of ExecutionResult and never rejected. + * + * Useful for async PHP platforms. + * + * @param mixed|null $rootValue + * @param mixed|null $contextValue + * @param mixed[]|null $variableValues + * @param string|null $operationName + * + * @return Promise + * + * @api + */ +static function promiseToExecute( + GraphQL\Executor\Promise\PromiseAdapter $promiseAdapter, + GraphQL\Type\Schema $schema, + GraphQL\Language\AST\DocumentNode $documentNode, + $rootValue = null, + $contextValue = null, + $variableValues = null, + $operationName = null, + callable $fieldResolver = null +) +``` +# GraphQL\Executor\ExecutionResult +Returned after [query execution](executing-queries.md). +Represents both - result of successful execution and of a failed one +(with errors collected in `errors` prop) + +Could be converted to [spec-compliant](https://facebook.github.io/graphql/#sec-Response-Format) +serializable array using `toArray()` + +**Class Props:** +```php +/** + * Data collected from resolvers during query execution + * + * @api + * @var mixed[] + */ +public $data; + +/** + * Errors registered during query execution. + * + * If an error was caused by exception thrown in resolver, $error->getPrevious() would + * contain original exception. + * + * @api + * @var Error[] + */ +public $errors; + +/** + * User-defined serializable array of extensions included in serialized result. + * Conforms to + * + * @api + * @var mixed[] + */ +public $extensions; +``` + +**Class Methods:** +```php +/** + * Define custom error formatting (must conform to http://facebook.github.io/graphql/#sec-Errors) + * + * Expected signature is: function (GraphQL\Error\Error $error): array + * + * Default formatter is "GraphQL\Error\FormattedError::createFromException" + * + * Expected returned value must be an array: + * array( + * 'message' => 'errorMessage', + * // ... other keys + * ); + * + * @return self + * + * @api + */ +function setErrorFormatter(callable $errorFormatter) +``` + +```php +/** + * Define custom logic for error handling (filtering, logging, etc). + * + * Expected handler signature is: function (array $errors, callable $formatter): array + * + * Default handler is: + * function (array $errors, callable $formatter) { + * return array_map($formatter, $errors); + * } + * + * @return self + * + * @api + */ +function setErrorsHandler(callable $handler) +``` + +```php +/** + * Converts GraphQL query result to spec-compliant serializable array using provided + * errors handler and formatter. + * + * If debug argument is passed, output of error formatter is enriched which debugging information + * ("debugMessage", "trace" keys depending on flags). + * + * $debug argument must be either bool (only adds "debugMessage" to result) or sum of flags from + * GraphQL\Error\Debug + * + * @param bool|int $debug + * + * @return mixed[] + * + * @api + */ +function toArray($debug = false) +``` +# GraphQL\Executor\Promise\PromiseAdapter +Provides a means for integration of async PHP platforms ([related docs](data-fetching.md#async-php)) + +**Interface Methods:** +```php +/** + * Return true if the value is a promise or a deferred of the underlying platform + * + * @param mixed $value + * + * @return bool + * + * @api + */ +function isThenable($value) +``` + +```php +/** + * Converts thenable of the underlying platform into GraphQL\Executor\Promise\Promise instance + * + * @param object $thenable + * + * @return Promise + * + * @api + */ +function convertThenable($thenable) +``` + +```php +/** + * Accepts our Promise wrapper, extracts adopted promise out of it and executes actual `then` logic described + * in Promises/A+ specs. Then returns new wrapped instance of GraphQL\Executor\Promise\Promise. + * + * @return Promise + * + * @api + */ +function then( + GraphQL\Executor\Promise\Promise $promise, + callable $onFulfilled = null, + callable $onRejected = null +) +``` + +```php +/** + * Creates a Promise + * + * Expected resolver signature: + * function(callable $resolve, callable $reject) + * + * @return Promise + * + * @api + */ +function create(callable $resolver) +``` + +```php +/** + * Creates a fulfilled Promise for a value if the value is not a promise. + * + * @param mixed $value + * + * @return Promise + * + * @api + */ +function createFulfilled($value = null) +``` + +```php +/** + * Creates a rejected promise for a reason if the reason is not a promise. If + * the provided reason is a promise, then it is returned as-is. + * + * @param Throwable $reason + * + * @return Promise + * + * @api + */ +function createRejected($reason) +``` + +```php +/** + * Given an array of promises (or values), returns a promise that is fulfilled when all the + * items in the array are fulfilled. + * + * @param Promise[]|mixed[] $promisesOrValues Promises or values. + * + * @return Promise + * + * @api + */ +function all(array $promisesOrValues) +``` +# GraphQL\Validator\DocumentValidator +Implements the "Validation" section of the spec. + +Validation runs synchronously, returning an array of encountered errors, or +an empty array if no errors were encountered and the document is valid. + +A list of specific validation rules may be provided. If not provided, the +default list of rules defined by the GraphQL specification will be used. + +Each validation rule is an instance of GraphQL\Validator\Rules\ValidationRule +which returns a visitor (see the [GraphQL\Language\Visitor API](reference.md#graphqllanguagevisitor)). + +Visitor methods are expected to return an instance of [GraphQL\Error\Error](reference.md#graphqlerrorerror), +or array of such instances when invalid. + +Optionally a custom TypeInfo instance may be provided. If not provided, one +will be created from the provided schema. + +**Class Methods:** +```php +/** + * Primary method for query validation. See class description for details. + * + * @param ValidationRule[]|null $rules + * + * @return Error[] + * + * @api + */ +static function validate( + GraphQL\Type\Schema $schema, + GraphQL\Language\AST\DocumentNode $ast, + array $rules = null, + GraphQL\Utils\TypeInfo $typeInfo = null +) +``` + +```php +/** + * Returns all global validation rules. + * + * @return ValidationRule[] + * + * @api + */ +static function allRules() +``` + +```php +/** + * Returns global validation rule by name. Standard rules are named by class name, so + * example usage for such rules: + * + * $rule = DocumentValidator::getRule(GraphQL\Validator\Rules\QueryComplexity::class); + * + * @param string $name + * + * @return ValidationRule + * + * @api + */ +static function getRule($name) +``` + +```php +/** + * Add rule to list of global validation rules + * + * @api + */ +static function addRule(GraphQL\Validator\Rules\ValidationRule $rule) +``` +# GraphQL\Error\Error +Describes an Error found during the parse, validate, or +execute phases of performing a GraphQL operation. In addition to a message +and stack trace, it also includes information about the locations in a +GraphQL document and/or execution result that correspond to the Error. + +When the error was caused by an exception thrown in resolver, original exception +is available via `getPrevious()`. + +Also read related docs on [error handling](error-handling.md) + +Class extends standard PHP `\Exception`, so all standard methods of base `\Exception` class +are available in addition to those listed below. + +**Class Constants:** +```php +const CATEGORY_GRAPHQL = "graphql"; +const CATEGORY_INTERNAL = "internal"; +``` + +**Class Methods:** +```php +/** + * An array of locations within the source GraphQL document which correspond to this error. + * + * Each entry has information about `line` and `column` within source GraphQL document: + * $location->line; + * $location->column; + * + * Errors during validation often contain multiple locations, for example to + * point out to field mentioned in multiple fragments. Errors during execution include a + * single location, the field which produced the error. + * + * @return SourceLocation[] + * + * @api + */ +function getLocations() +``` + +```php +/** + * Returns an array describing the path from the root value to the field which produced this error. + * Only included for execution errors. + * + * @return mixed[]|null + * + * @api + */ +function getPath() +``` +# GraphQL\Error\Warning +Encapsulates warnings produced by the library. + +Warnings can be suppressed (individually or all) if required. +Also it is possible to override warning handler (which is **trigger_error()** by default) + +**Class Constants:** +```php +const WARNING_ASSIGN = 2; +const WARNING_CONFIG = 4; +const WARNING_FULL_SCHEMA_SCAN = 8; +const WARNING_CONFIG_DEPRECATION = 16; +const WARNING_NOT_A_TYPE = 32; +const ALL = 63; +``` + +**Class Methods:** +```php +/** + * Sets warning handler which can intercept all system warnings. + * When not set, trigger_error() is used to notify about warnings. + * + * @api + */ +static function setWarningHandler(callable $warningHandler = null) +``` + +```php +/** + * Suppress warning by id (has no effect when custom warning handler is set) + * + * Usage example: + * Warning::suppress(Warning::WARNING_NOT_A_TYPE) + * + * When passing true - suppresses all warnings. + * + * @param bool|int $suppress + * + * @api + */ +static function suppress($suppress = true) +``` + +```php +/** + * Re-enable previously suppressed warning by id + * + * Usage example: + * Warning::suppress(Warning::WARNING_NOT_A_TYPE) + * + * When passing true - re-enables all warnings. + * + * @param bool|int $enable + * + * @api + */ +static function enable($enable = true) +``` +# GraphQL\Error\ClientAware +This interface is used for [default error formatting](error-handling.md). + +Only errors implementing this interface (and returning true from `isClientSafe()`) +will be formatted with original error message. + +All other errors will be formatted with generic "Internal server error". + +**Interface Methods:** +```php +/** + * Returns true when exception message is safe to be displayed to a client. + * + * @return bool + * + * @api + */ +function isClientSafe() +``` + +```php +/** + * Returns string describing a category of the error. + * + * Value "graphql" is reserved for errors produced by query parsing or validation, do not use it. + * + * @return string + * + * @api + */ +function getCategory() +``` +# GraphQL\Error\Debug +Collection of flags for [error debugging](error-handling.md#debugging-tools). + +**Class Constants:** +```php +const INCLUDE_DEBUG_MESSAGE = 1; +const INCLUDE_TRACE = 2; +const RETHROW_INTERNAL_EXCEPTIONS = 4; +const RETHROW_UNSAFE_EXCEPTIONS = 8; +``` + +# GraphQL\Error\FormattedError +This class is used for [default error formatting](error-handling.md). +It converts PHP exceptions to [spec-compliant errors](https://facebook.github.io/graphql/#sec-Errors) +and provides tools for error debugging. + +**Class Methods:** +```php +/** + * Set default error message for internal errors formatted using createFormattedError(). + * This value can be overridden by passing 3rd argument to `createFormattedError()`. + * + * @param string $msg + * + * @api + */ +static function setInternalErrorMessage($msg) +``` + +```php +/** + * Standard GraphQL error formatter. Converts any exception to array + * conforming to GraphQL spec. + * + * This method only exposes exception message when exception implements ClientAware interface + * (or when debug flags are passed). + * + * For a list of available debug flags see GraphQL\Error\Debug constants. + * + * @param Throwable $e + * @param bool|int $debug + * @param string $internalErrorMessage + * + * @return mixed[] + * + * @throws Throwable + * + * @api + */ +static function createFromException($e, $debug = false, $internalErrorMessage = null) +``` + +```php +/** + * Returns error trace as serializable array + * + * @param Throwable $error + * + * @return mixed[] + * + * @api + */ +static function toSafeTrace($error) +``` +# GraphQL\Server\StandardServer +GraphQL server compatible with both: [express-graphql](https://github.com/graphql/express-graphql) +and [Apollo Server](https://github.com/apollographql/graphql-server). +Usage Example: + + $server = new StandardServer([ + 'schema' => $mySchema + ]); + $server->handleRequest(); + +Or using [ServerConfig](reference.md#graphqlserverserverconfig) instance: + + $config = GraphQL\Server\ServerConfig::create() + ->setSchema($mySchema) + ->setContext($myContext); + + $server = new GraphQL\Server\StandardServer($config); + $server->handleRequest(); + +See [dedicated section in docs](executing-queries.md#using-server) for details. + +**Class Methods:** +```php +/** + * Converts and exception to error and sends spec-compliant HTTP 500 error. + * Useful when an exception is thrown somewhere outside of server execution context + * (e.g. during schema instantiation). + * + * @param Throwable $error + * @param bool $debug + * @param bool $exitWhenDone + * + * @api + */ +static function send500Error($error, $debug = false, $exitWhenDone = false) +``` + +```php +/** + * Creates new instance of a standard GraphQL HTTP server + * + * @param ServerConfig|mixed[] $config + * + * @api + */ +function __construct($config) +``` + +```php +/** + * Parses HTTP request, executes and emits response (using standard PHP `header` function and `echo`) + * + * By default (when $parsedBody is not set) it uses PHP globals to parse a request. + * It is possible to implement request parsing elsewhere (e.g. using framework Request instance) + * and then pass it to the server. + * + * See `executeRequest()` if you prefer to emit response yourself + * (e.g. using Response object of some framework) + * + * @param OperationParams|OperationParams[] $parsedBody + * @param bool $exitWhenDone + * + * @api + */ +function handleRequest($parsedBody = null, $exitWhenDone = false) +``` + +```php +/** + * Executes GraphQL operation and returns execution result + * (or promise when promise adapter is different from SyncPromiseAdapter). + * + * By default (when $parsedBody is not set) it uses PHP globals to parse a request. + * It is possible to implement request parsing elsewhere (e.g. using framework Request instance) + * and then pass it to the server. + * + * PSR-7 compatible method executePsrRequest() does exactly this. + * + * @param OperationParams|OperationParams[] $parsedBody + * + * @return ExecutionResult|ExecutionResult[]|Promise + * + * @throws InvariantViolation + * + * @api + */ +function executeRequest($parsedBody = null) +``` + +```php +/** + * Executes PSR-7 request and fulfills PSR-7 response. + * + * See `executePsrRequest()` if you prefer to create response yourself + * (e.g. using specific JsonResponse instance of some framework). + * + * @return ResponseInterface|Promise + * + * @api + */ +function processPsrRequest( + Psr\Http\Message\ServerRequestInterface $request, + Psr\Http\Message\ResponseInterface $response, + Psr\Http\Message\StreamInterface $writableBodyStream +) +``` + +```php +/** + * Executes GraphQL operation and returns execution result + * (or promise when promise adapter is different from SyncPromiseAdapter) + * + * @return ExecutionResult|ExecutionResult[]|Promise + * + * @api + */ +function executePsrRequest(Psr\Http\Message\ServerRequestInterface $request) +``` + +```php +/** + * Returns an instance of Server helper, which contains most of the actual logic for + * parsing / validating / executing request (which could be re-used by other server implementations) + * + * @return Helper + * + * @api + */ +function getHelper() +``` +# GraphQL\Server\ServerConfig +Server configuration class. +Could be passed directly to server constructor. List of options accepted by **create** method is +[described in docs](executing-queries.md#server-configuration-options). + +Usage example: + + $config = GraphQL\Server\ServerConfig::create() + ->setSchema($mySchema) + ->setContext($myContext); + + $server = new GraphQL\Server\StandardServer($config); + +**Class Methods:** +```php +/** + * Converts an array of options to instance of ServerConfig + * (or just returns empty config when array is not passed). + * + * @param mixed[] $config + * + * @return ServerConfig + * + * @api + */ +static function create(array $config = []) +``` + +```php +/** + * @return self + * + * @api + */ +function setSchema(GraphQL\Type\Schema $schema) +``` + +```php +/** + * @param mixed|callable $context + * + * @return self + * + * @api + */ +function setContext($context) +``` + +```php +/** + * @param mixed|callable $rootValue + * + * @return self + * + * @api + */ +function setRootValue($rootValue) +``` + +```php +/** + * Expects function(Throwable $e) : array + * + * @return self + * + * @api + */ +function setErrorFormatter(callable $errorFormatter) +``` + +```php +/** + * Expects function(array $errors, callable $formatter) : array + * + * @return self + * + * @api + */ +function setErrorsHandler(callable $handler) +``` + +```php +/** + * Set validation rules for this server. + * + * @param ValidationRule[]|callable $validationRules + * + * @return self + * + * @api + */ +function setValidationRules($validationRules) +``` + +```php +/** + * @return self + * + * @api + */ +function setFieldResolver(callable $fieldResolver) +``` + +```php +/** + * Expects function($queryId, OperationParams $params) : string|DocumentNode + * + * This function must return query string or valid DocumentNode. + * + * @return self + * + * @api + */ +function setPersistentQueryLoader(callable $persistentQueryLoader) +``` + +```php +/** + * Set response debug flags. See GraphQL\Error\Debug class for a list of all available flags + * + * @param bool|int $set + * + * @return self + * + * @api + */ +function setDebug($set = true) +``` + +```php +/** + * Allow batching queries (disabled by default) + * + * @api + */ +function setQueryBatching(bool $enableBatching) +``` + +```php +/** + * @return self + * + * @api + */ +function setPromiseAdapter(GraphQL\Executor\Promise\PromiseAdapter $promiseAdapter) +``` +# GraphQL\Server\Helper +Contains functionality that could be re-used by various server implementations + +**Class Methods:** +```php +/** + * Parses HTTP request using PHP globals and returns GraphQL OperationParams + * contained in this request. For batched requests it returns an array of OperationParams. + * + * This function does not check validity of these params + * (validation is performed separately in validateOperationParams() method). + * + * If $readRawBodyFn argument is not provided - will attempt to read raw request body + * from `php://input` stream. + * + * Internally it normalizes input to $method, $bodyParams and $queryParams and + * calls `parseRequestParams()` to produce actual return value. + * + * For PSR-7 request parsing use `parsePsrRequest()` instead. + * + * @return OperationParams|OperationParams[] + * + * @throws RequestError + * + * @api + */ +function parseHttpRequest(callable $readRawBodyFn = null) +``` + +```php +/** + * Parses normalized request params and returns instance of OperationParams + * or array of OperationParams in case of batch operation. + * + * Returned value is a suitable input for `executeOperation` or `executeBatch` (if array) + * + * @param string $method + * @param mixed[] $bodyParams + * @param mixed[] $queryParams + * + * @return OperationParams|OperationParams[] + * + * @throws RequestError + * + * @api + */ +function parseRequestParams($method, array $bodyParams, array $queryParams) +``` + +```php +/** + * Checks validity of OperationParams extracted from HTTP request and returns an array of errors + * if params are invalid (or empty array when params are valid) + * + * @return Error[] + * + * @api + */ +function validateOperationParams(GraphQL\Server\OperationParams $params) +``` + +```php +/** + * Executes GraphQL operation with given server configuration and returns execution result + * (or promise when promise adapter is different from SyncPromiseAdapter) + * + * @return ExecutionResult|Promise + * + * @api + */ +function executeOperation(GraphQL\Server\ServerConfig $config, GraphQL\Server\OperationParams $op) +``` + +```php +/** + * Executes batched GraphQL operations with shared promise queue + * (thus, effectively batching deferreds|promises of all queries at once) + * + * @param OperationParams[] $operations + * + * @return ExecutionResult|ExecutionResult[]|Promise + * + * @api + */ +function executeBatch(GraphQL\Server\ServerConfig $config, array $operations) +``` + +```php +/** + * Send response using standard PHP `header()` and `echo`. + * + * @param Promise|ExecutionResult|ExecutionResult[] $result + * @param bool $exitWhenDone + * + * @api + */ +function sendResponse($result, $exitWhenDone = false) +``` + +```php +/** + * Converts PSR-7 request to OperationParams[] + * + * @return OperationParams[]|OperationParams + * + * @throws RequestError + * + * @api + */ +function parsePsrRequest(Psr\Http\Message\ServerRequestInterface $request) +``` + +```php +/** + * Converts query execution result to PSR-7 response + * + * @param Promise|ExecutionResult|ExecutionResult[] $result + * + * @return Promise|ResponseInterface + * + * @api + */ +function toPsrResponse( + $result, + Psr\Http\Message\ResponseInterface $response, + Psr\Http\Message\StreamInterface $writableBodyStream +) +``` +# GraphQL\Server\OperationParams +Structure representing parsed HTTP parameters for GraphQL operation + +**Class Props:** +```php +/** + * Id of the query (when using persistent queries). + * + * Valid aliases (case-insensitive): + * - id + * - queryId + * - documentId + * + * @api + * @var string + */ +public $queryId; + +/** + * @api + * @var string + */ +public $query; + +/** + * @api + * @var string + */ +public $operation; + +/** + * @api + * @var mixed[]|null + */ +public $variables; + +/** + * @api + * @var mixed[]|null + */ +public $extensions; +``` + +**Class Methods:** +```php +/** + * Creates an instance from given array + * + * @param mixed[] $params + * + * @api + */ +static function create(array $params, bool $readonly = false) +``` + +```php +/** + * @param string $key + * + * @return mixed + * + * @api + */ +function getOriginalInput($key) +``` + +```php +/** + * Indicates that operation is executed in read-only context + * (e.g. via HTTP GET request) + * + * @return bool + * + * @api + */ +function isReadOnly() +``` +# GraphQL\Utils\BuildSchema +Build instance of `GraphQL\Type\Schema` out of type language definition (string or parsed AST) +See [section in docs](type-system/type-language.md) for details. + +**Class Methods:** +```php +/** + * A helper function to build a GraphQLSchema directly from a source + * document. + * + * @param DocumentNode|Source|string $source + * @param bool[] $options + * + * @return Schema + * + * @api + */ +static function build($source, callable $typeConfigDecorator = null, array $options = []) +``` + +```php +/** + * This takes the ast of a schema document produced by the parse function in + * GraphQL\Language\Parser. + * + * If no schema definition is provided, then it will look for types named Query + * and Mutation. + * + * Given that AST it constructs a GraphQL\Type\Schema. The resulting schema + * has no resolve methods, so execution will use default resolvers. + * + * Accepts options as a third argument: + * + * - commentDescriptions: + * Provide true to use preceding comments as the description. + * + * @param bool[] $options + * + * @return Schema + * + * @throws Error + * + * @api + */ +static function buildAST( + GraphQL\Language\AST\DocumentNode $ast, + callable $typeConfigDecorator = null, + array $options = [] +) +``` +# GraphQL\Utils\AST +Various utilities dealing with AST + +**Class Methods:** +```php +/** + * Convert representation of AST as an associative array to instance of GraphQL\Language\AST\Node. + * + * For example: + * + * ```php + * AST::fromArray([ + * 'kind' => 'ListValue', + * 'values' => [ + * ['kind' => 'StringValue', 'value' => 'my str'], + * ['kind' => 'StringValue', 'value' => 'my other str'] + * ], + * 'loc' => ['start' => 21, 'end' => 25] + * ]); + * ``` + * + * Will produce instance of `ListValueNode` where `values` prop is a lazily-evaluated `NodeList` + * returning instances of `StringValueNode` on access. + * + * This is a reverse operation for AST::toArray($node) + * + * @param mixed[] $node + * + * @api + */ +static function fromArray(array $node) +``` + +```php +/** + * Convert AST node to serializable array + * + * @return mixed[] + * + * @api + */ +static function toArray(GraphQL\Language\AST\Node $node) +``` + +```php +/** + * Produces a GraphQL Value AST given a PHP value. + * + * Optionally, a GraphQL type may be provided, which will be used to + * disambiguate between value primitives. + * + * | PHP Value | GraphQL Value | + * | ------------- | -------------------- | + * | Object | Input Object | + * | Assoc Array | Input Object | + * | Array | List | + * | Boolean | Boolean | + * | String | String / Enum Value | + * | Int | Int | + * | Float | Int / Float | + * | Mixed | Enum Value | + * | null | NullValue | + * + * @param Type|mixed|null $value + * + * @return ObjectValueNode|ListValueNode|BooleanValueNode|IntValueNode|FloatValueNode|EnumValueNode|StringValueNode|NullValueNode + * + * @api + */ +static function astFromValue($value, GraphQL\Type\Definition\InputType $type) +``` + +```php +/** + * Produces a PHP value given a GraphQL Value AST. + * + * A GraphQL type must be provided, which will be used to interpret different + * GraphQL Value literals. + * + * Returns `null` when the value could not be validly coerced according to + * the provided type. + * + * | GraphQL Value | PHP Value | + * | -------------------- | ------------- | + * | Input Object | Assoc Array | + * | List | Array | + * | Boolean | Boolean | + * | String | String | + * | Int / Float | Int / Float | + * | Enum Value | Mixed | + * | Null Value | null | + * + * @param ValueNode|null $valueNode + * @param mixed[]|null $variables + * + * @return mixed[]|stdClass|null + * + * @throws Exception + * + * @api + */ +static function valueFromAST($valueNode, GraphQL\Type\Definition\InputType $type, array $variables = null) +``` + +```php +/** + * Produces a PHP value given a GraphQL Value AST. + * + * Unlike `valueFromAST()`, no type is provided. The resulting PHP value + * will reflect the provided GraphQL value AST. + * + * | GraphQL Value | PHP Value | + * | -------------------- | ------------- | + * | Input Object | Assoc Array | + * | List | Array | + * | Boolean | Boolean | + * | String | String | + * | Int / Float | Int / Float | + * | Enum | Mixed | + * | Null | null | + * + * @param Node $valueNode + * @param mixed[]|null $variables + * + * @return mixed + * + * @throws Exception + * + * @api + */ +static function valueFromASTUntyped($valueNode, array $variables = null) +``` + +```php +/** + * Returns type definition for given AST Type node + * + * @param NamedTypeNode|ListTypeNode|NonNullTypeNode $inputTypeNode + * + * @return Type|null + * + * @throws Exception + * + * @api + */ +static function typeFromAST(GraphQL\Type\Schema $schema, $inputTypeNode) +``` + +```php +/** + * Returns operation type ("query", "mutation" or "subscription") given a document and operation name + * + * @param string $operationName + * + * @return bool + * + * @api + */ +static function getOperation(GraphQL\Language\AST\DocumentNode $document, $operationName = null) +``` +# GraphQL\Utils\SchemaPrinter +Given an instance of Schema, prints it in GraphQL type language. + +**Class Methods:** +```php +/** + * Accepts options as a second argument: + * + * - commentDescriptions: + * Provide true to use preceding comments as the description. + * + * @param bool[] $options + * + * @api + */ +static function doPrint(GraphQL\Type\Schema $schema, array $options = []) +``` + +```php +/** + * @param bool[] $options + * + * @api + */ +static function printIntrospectionSchema(GraphQL\Type\Schema $schema, array $options = []) +``` diff --git a/vendor/webonyx/graphql-php/docs/security.md b/vendor/webonyx/graphql-php/docs/security.md new file mode 100644 index 0000000..5f1cc61 --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/security.md @@ -0,0 +1,94 @@ +# Query Complexity Analysis + +This is a PHP port of [Query Complexity Analysis](http://sangria-graphql.org/learn/#query-complexity-analysis) in Sangria implementation. + +Complexity analysis is a separate validation rule which calculates query complexity score before execution. +Every field in the query gets a default score 1 (including ObjectType nodes). Total complexity of the +query is the sum of all field scores. For example, the complexity of introspection query is **109**. + +If this score exceeds a threshold, a query is not executed and an error is returned instead. + +Complexity analysis is disabled by default. To enabled it, add validation rule: + +```php + 'MyType', + 'fields' => [ + 'someList' => [ + 'type' => Type::listOf(Type::string()), + 'args' => [ + 'limit' => [ + 'type' => Type::int(), + 'defaultValue' => 10 + ] + ], + 'complexity' => function($childrenComplexity, $args) { + return $childrenComplexity * $args['limit']; + } + ] + ] +]); +``` + +# Limiting Query Depth + +This is a PHP port of [Limiting Query Depth](http://sangria-graphql.org/learn/#limiting-query-depth) in Sangria implementation. +For example, max depth of the introspection query is **7**. + +It is disabled by default. To enable it, add following validation rule: + +```php + 'track', + 'description' => 'Instruction to record usage of the field by client', + 'locations' => [ + DirectiveLocation::FIELD, + ], + 'args' => [ + new FieldArgument([ + 'name' => 'details', + 'type' => Type::string(), + 'description' => 'String with additional details of field usage scenario', + 'defaultValue' => '' + ]) + ] +]); +``` + +See possible directive locations in +[`GraphQL\Language\DirectiveLocation`](../reference.md#graphqllanguagedirectivelocation). diff --git a/vendor/webonyx/graphql-php/docs/type-system/enum-types.md b/vendor/webonyx/graphql-php/docs/type-system/enum-types.md new file mode 100644 index 0000000..4cebdec --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/type-system/enum-types.md @@ -0,0 +1,182 @@ +# Enum Type Definition +Enumeration types are a special kind of scalar that is restricted to a particular set +of allowed values. + +In **graphql-php** enum type is an instance of `GraphQL\Type\Definition\EnumType` +which accepts configuration array in constructor: + +```php + 'Episode', + 'description' => 'One of the films in the Star Wars Trilogy', + 'values' => [ + 'NEWHOPE' => [ + 'value' => 4, + 'description' => 'Released in 1977.' + ], + 'EMPIRE' => [ + 'value' => 5, + 'description' => 'Released in 1980.' + ], + 'JEDI' => [ + 'value' => 6, + 'description' => 'Released in 1983.' + ], + ] +]); +``` + +This example uses an **inline** style for Enum Type definition, but you can also use +[inheritance or type language](index.md#type-definition-styles). + +# Configuration options +Enum Type constructor accepts an array with following options: + +Option | Type | Notes +------ | ---- | ----- +name | `string` | **Required.** Name of the type. When not set - inferred from array key (read about [shorthand field definition](#shorthand-definitions) below) +description | `string` | Plain-text description of the type for clients (e.g. used by [GraphiQL](https://github.com/graphql/graphiql) for auto-generated documentation) +values | `array` | List of enumerated items, see below for expected structure of each entry + +Each entry of **values** array in turn accepts following options: + +Option | Type | Notes +------ | ---- | ----- +name | `string` | **Required.** Name of the item. When not set - inferred from array key (read about [shorthand field definition](#shorthand-definitions) below) +value | `mixed` | Internal representation of enum item in your application (could be any value, including complex objects or callbacks) +description | `string` | Plain-text description of enum value for clients (e.g. used by [GraphiQL](https://github.com/graphql/graphiql) for auto-generated documentation) +deprecationReason | `string` | Text describing why this enum value is deprecated. When not empty - item will not be returned by introspection queries (unless forced) + + +# Shorthand definitions +If internal representation of enumerated item is the same as item name, then you can use +following shorthand for definition: + +```php + 'Episode', + 'description' => 'One of the films in the Star Wars Trilogy', + 'values' => ['NEWHOPE', 'EMPIRE', 'JEDI'] +]); +``` + +which is equivalent of: +```php + 'Episode', + 'description' => 'One of the films in the Star Wars Trilogy', + 'values' => [ + 'NEWHOPE' => ['value' => 'NEWHOPE'], + 'EMPIRE' => ['value' => 'EMPIRE'], + 'JEDI' => ['value' => 'JEDI'] + ] +]); +``` + +which is in turn equivalent of the full form: + +```php + 'Episode', + 'description' => 'One of the films in the Star Wars Trilogy', + 'values' => [ + ['name' => 'NEWHOPE', 'value' => 'NEWHOPE'], + ['name' => 'EMPIRE', 'value' => 'EMPIRE'], + ['name' => 'JEDI', 'value' => 'JEDI'] + ] +]); +``` + +# Field Resolution +When object field is of Enum Type, field resolver is expected to return an internal +representation of corresponding Enum item (**value** in config). **graphql-php** will +then serialize this **value** to **name** to include in response: + +```php + 'Episode', + 'description' => 'One of the films in the Star Wars Trilogy', + 'values' => [ + 'NEWHOPE' => [ + 'value' => 4, + 'description' => 'Released in 1977.' + ], + 'EMPIRE' => [ + 'value' => 5, + 'description' => 'Released in 1980.' + ], + 'JEDI' => [ + 'value' => 6, + 'description' => 'Released in 1983.' + ], + ] +]); + +$heroType = new ObjectType([ + 'name' => 'Hero', + 'fields' => [ + 'appearsIn' => [ + 'type' => $episodeEnum, + 'resolve' => function() { + return 5; // Actual entry in response will be 'appearsIn' => 'EMPIRE' + } + ] + ] +]); +``` + +The Reverse is true when the enum is used as input type (e.g. as field argument). +GraphQL will treat enum input as **name** and convert it into **value** before passing to your app. + +For example, given object type definition: +```php + 'Hero', + 'fields' => [ + 'appearsIn' => [ + 'type' => Type::boolean(), + 'args' => [ + 'episode' => Type::nonNull($enumType) + ], + 'resolve' => function($_value, $args) { + return $args['episode'] === 5 ? true : false; + } + ] + ] +]); +``` + +Then following query: +```graphql +fragment on Hero { + appearsInNewHope: appearsIn(NEWHOPE) + appearsInEmpire: appearsIn(EMPIRE) +} +``` +will return: +```php +[ + 'appearsInNewHope' => false, + 'appearsInEmpire' => true +] +``` diff --git a/vendor/webonyx/graphql-php/docs/type-system/index.md b/vendor/webonyx/graphql-php/docs/type-system/index.md new file mode 100644 index 0000000..5aea26c --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/type-system/index.md @@ -0,0 +1,127 @@ +# Type System +To start using GraphQL you are expected to implement a type hierarchy and expose it as [Schema](schema.md). + +In graphql-php **type** is an instance of internal class from +`GraphQL\Type\Definition` namespace: [`ObjectType`](object-types.md), +[`InterfaceType`](interfaces.md), [`UnionType`](unions.md), [`InputObjectType`](input-types.md), +[`ScalarType`](scalar-types.md), [`EnumType`](enum-types.md) (or one of subclasses). + +But most of the types in your schema will be [object types](object-types.md). + +# Type Definition Styles +Several styles of type definitions are supported depending on your preferences. + +Inline definitions: +```php + 'MyType', + 'fields' => [ + 'id' => Type::id() + ] +]); +``` + +Class per type: +```php + [ + 'id' => Type::id() + ] + ]; + parent::__construct($config); + } +} +``` + +Using [GraphQL Type language](http://graphql.org/learn/schema/#type-language): + +```graphql +schema { + query: Query + mutation: Mutation +} + +type Query { + greetings(input: HelloInput!): String! +} + +input HelloInput { + firstName: String! + lastName: String +} +``` + +Read more about type language definitions in a [dedicated docs section](type-language.md). + +# Type Registry +Every type must be presented in Schema by a single instance (**graphql-php** +throws when it discovers several instances with the same **name** in the schema). + +Therefore if you define your type as separate PHP class you must ensure that only one +instance of that class is added to the schema. + +The typical way to do this is to create a registry of your types: + +```php +myAType ?: ($this->myAType = new MyAType($this)); + } + + public function myBType() + { + return $this->myBType ?: ($this->myBType = new MyBType($this)); + } +} +``` +And use this registry in type definition: + +```php + [ + 'b' => $types->myBType() + ] + ]); + } +} +``` +Obviously, you can automate this registry as you wish to reduce boilerplate or even +introduce Dependency Injection Container if your types have other dependencies. + +Alternatively, all methods of the registry could be static - then there is no need +to pass it in constructor - instead just use use **TypeRegistry::myAType()** in your +type definitions. diff --git a/vendor/webonyx/graphql-php/docs/type-system/input-types.md b/vendor/webonyx/graphql-php/docs/type-system/input-types.md new file mode 100644 index 0000000..1b7ffc8 --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/type-system/input-types.md @@ -0,0 +1,172 @@ +# Mutations +Mutation is just a field of a regular [Object Type](object-types.md) with arguments. +For GraphQL PHP runtime there is no difference between query fields with arguments and mutations. +They are executed [almost](http://facebook.github.io/graphql/#sec-Mutation) identically. +To some extent, Mutation is just a convention described in the GraphQL spec. + +Here is an example of a mutation operation: +```graphql +mutation CreateReviewForEpisode($ep: EpisodeInput!, $review: ReviewInput!) { + createReview(episode: $ep, review: $review) { + stars + commentary + } +} +``` + +To execute such a mutation, you need **Mutation** type [at the root of your schema](schema.md): + +```php + 'Mutation', + 'fields' => [ + // List of mutations: + 'createReview' => [ + 'args' => [ + 'episode' => Type::nonNull($episodeInputType), + 'review' => Type::nonNull($reviewInputType) + ], + 'type' => new ObjectType([ + 'name' => 'CreateReviewOutput', + 'fields' => [ + 'stars' => ['type' => Type::int()], + 'commentary' => ['type' => Type::string()] + ] + ]), + ], + // ... other mutations + ] +]); +``` +As you can see, the only difference from regular object type is the semantics of field names +(verbs vs nouns). + +Also as we see arguments can be of complex types. To leverage the full power of mutations +(and field arguments in general) you must learn how to create complex input types. + + +# About Input and Output Types +All types in GraphQL are of two categories: **input** and **output**. + +* **Output** types (or field types) are: [Scalar](scalar-types.md), [Enum](enum-types.md), [Object](object-types.md), +[Interface](interfaces.md), [Union](unions.md) + +* **Input** types (or argument types) are: [Scalar](scalar-types.md), [Enum](enum-types.md), InputObject + +Obviously, [NonNull and List](lists-and-nonnulls.md) types belong to both categories depending on their +inner type. + +Until now all examples of field **arguments** in this documentation were of [Scalar](scalar-types.md) or +[Enum](enum-types.md) types. But you can also pass complex objects. + +This is particularly valuable in case of mutations, where input data might be rather complex. + +# Input Object Type +GraphQL specification defines Input Object Type for complex inputs. It is similar to ObjectType +except that it's fields have no **args** or **resolve** options and their **type** must be input type. + +In graphql-php **Input Object Type** is an instance of `GraphQL\Type\Definition\InputObjectType` +(or one of it subclasses) which accepts configuration array in constructor: + +```php + 'StoryFiltersInput', + 'fields' => [ + 'author' => [ + 'type' => Type::id(), + 'description' => 'Only show stories with this author id' + ], + 'popular' => [ + 'type' => Type::boolean(), + 'description' => 'Only show popular stories (liked by several people)' + ], + 'tags' => [ + 'type' => Type::listOf(Type::string()), + 'description' => 'Only show stories which contain all of those tags' + ] + ] +]); +``` + +Every field may be of other InputObjectType (thus complex hierarchies of inputs are possible) + +# Configuration options +The constructor of InputObjectType accepts array with only 3 options: + +Option | Type | Notes +------------ | -------- | ----- +name | `string` | **Required.** Unique name of this object type within Schema +fields | `array` or `callable` | **Required**. An array describing object fields or callable returning such an array (see below). +description | `string` | Plain-text description of this type for clients (e.g. used by [GraphiQL](https://github.com/graphql/graphiql) for auto-generated documentation) + +Every field is an array with following entries: + +Option | Type | Notes +------ | ---- | ----- +name | `string` | **Required.** Name of the input field. When not set - inferred from **fields** array key +type | `Type` | **Required.** Instance of one of [Input Types](input-types.md) (**Scalar**, **Enum**, **InputObjectType** + any combination of those with **nonNull** and **listOf** modifiers) +description | `string` | Plain-text description of this input field for clients (e.g. used by [GraphiQL](https://github.com/graphql/graphiql) for auto-generated documentation) +defaultValue | `scalar` | Default value of this input field. Use the internal value if specifying a default for an **enum** type + +# Using Input Object Type +In the example above we defined our InputObjectType. Now let's use it in one of field arguments: + +```php + 'Query', + 'fields' => [ + 'stories' => [ + 'type' => Type::listOf($storyType), + 'args' => [ + 'filters' => [ + 'type' => Type::nonNull($filters), + 'defaultValue' => [ + 'popular' => true + ] + ] + ], + 'resolve' => function($rootValue, $args) { + return DataSource::filterStories($args['filters']); + } + ] + ] +]); +``` +(note that you can define **defaultValue** for fields with complex inputs as associative array). + +Then GraphQL query could include filters as literal value: +```graphql +{ + stories(filters: {author: "1", popular: false}) +} +``` + +Or as query variable: +```graphql +query($filters: StoryFiltersInput!) { + stories(filters: $filters) +} +``` +```php +$variables = [ + 'filters' => [ + "author" => "1", + "popular" => false + ] +]; +``` + +**graphql-php** will validate the input against your InputObjectType definition and pass it to your +resolver as `$args['filters']` diff --git a/vendor/webonyx/graphql-php/docs/type-system/interfaces.md b/vendor/webonyx/graphql-php/docs/type-system/interfaces.md new file mode 100644 index 0000000..5335d6d --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/type-system/interfaces.md @@ -0,0 +1,136 @@ +# Interface Type Definition +An Interface is an abstract type that includes a certain set of fields that a +type must include to implement the interface. + +In **graphql-php** interface type is an instance of `GraphQL\Type\Definition\InterfaceType` +(or one of its subclasses) which accepts configuration array in a constructor: + +```php + 'Character', + 'description' => 'A character in the Star Wars Trilogy', + 'fields' => [ + 'id' => [ + 'type' => Type::nonNull(Type::string()), + 'description' => 'The id of the character.', + ], + 'name' => [ + 'type' => Type::string(), + 'description' => 'The name of the character.' + ] + ], + 'resolveType' => function ($value) { + if ($value->type === 'human') { + return MyTypes::human(); + } else { + return MyTypes::droid(); + } + } +]); +``` +This example uses **inline** style for Interface definition, but you can also use +[inheritance or type language](index.md#type-definition-styles). + +# Configuration options +The constructor of InterfaceType accepts an array. Below is a full list of allowed options: + +Option | Type | Notes +------ | ---- | ----- +name | `string` | **Required.** Unique name of this interface type within Schema +fields | `array` | **Required.** List of fields required to be defined by interface implementors. Same as [Fields for Object Type](object-types.md#field-configuration-options) +description | `string` | Plain-text description of this type for clients (e.g. used by [GraphiQL](https://github.com/graphql/graphiql) for auto-generated documentation) +resolveType | `callback` | **function($value, $context, [ResolveInfo](../reference.md#graphqltypedefinitionresolveinfo) $info)**
Receives **$value** from resolver of the parent field and returns concrete interface implementor for this **$value**. + +# Implementing interface +To implement the Interface simply add it to **interfaces** array of Object Type definition: +```php + 'Human', + 'fields' => [ + 'id' => [ + 'type' => Type::nonNull(Type::string()), + 'description' => 'The id of the character.', + ], + 'name' => [ + 'type' => Type::string(), + 'description' => 'The name of the character.' + ] + ], + 'interfaces' => [ + $character + ] +]); +``` +Note that Object Type must include all fields of interface with exact same types +(including **nonNull** specification) and arguments. + +The only exception is when object's field type is more specific than the type of this field defined in interface +(see [Covariant return types for interface fields](#covariant-return-types-for-interface-fields) below) + +# Covariant return types for interface fields +Object types implementing interface may change the field type to more specific. +Example: + +``` +interface A { + field1: A +} + +type B implements A { + field1: B +} +``` + +# Sharing Interface fields +Since every Object Type implementing an Interface must have the same set of fields - it often makes +sense to reuse field definitions of Interface in Object Types: + +```php + 'Human', + 'interfaces' => [ + $character + ], + 'fields' => [ + 'height' => Type::float(), + $character->getField('id'), + $character->getField('name') + ] +]); +``` + +In this case, field definitions are created only once (as a part of Interface Type) and then +reused by all interface implementors. It can save several microseconds and kilobytes + ensures that +field definitions of Interface and implementors are always in sync. + +Yet it creates a problem with the resolution of such fields. There are two ways how shared fields could +be resolved: + +1. If field resolution algorithm is the same for all Interface implementors - you can simply add +**resolve** option to field definition in Interface itself. + +2. If field resolution varies for different implementations - you can specify **resolveField** +option in [Object Type config](object-types.md#configuration-options) and handle field +resolutions there +(Note: **resolve** option in field definition has precedence over **resolveField** option in object type definition) + +# Interface role in data fetching +The only responsibility of interface in Data Fetching process is to return concrete Object Type +for given **$value** in **resolveType**. Then resolution of fields is delegated to resolvers of this +concrete Object Type. + +If a **resolveType** option is omitted, graphql-php will loop through all interface implementors and +use their **isTypeOf** callback to pick the first suitable one. This is obviously less efficient +than single **resolveType** call. So it is recommended to define **resolveType** whenever possible. diff --git a/vendor/webonyx/graphql-php/docs/type-system/lists-and-nonnulls.md b/vendor/webonyx/graphql-php/docs/type-system/lists-and-nonnulls.md new file mode 100644 index 0000000..8f3743d --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/type-system/lists-and-nonnulls.md @@ -0,0 +1,62 @@ +# Lists +**graphql-php** provides built-in support for lists. In order to create list type - wrap +existing type with `GraphQL\Type\Definition\Type::listOf()` modifier: +```php + 'User', + 'fields' => [ + 'emails' => [ + 'type' => Type::listOf(Type::string()), + 'resolve' => function() { + return ['jon@example.com', 'jonny@example.com']; + } + ] + ] +]); +``` + +Resolvers for such fields are expected to return **array** or instance of PHP's built-in **Traversable** +interface (**null** is allowed by default too). + +If returned value is not of one of these types - **graphql-php** will add an error to result +and set the field value to **null** (only if the field is nullable, see below for non-null fields). + +# Non-Null fields +By default in GraphQL, every field can have a **null** value. To indicate that some field always +returns **non-null** value - use `GraphQL\Type\Definition\Type::nonNull()` modifier: + +```php + 'User', + 'fields' => [ + 'id' => [ + 'type' => Type::nonNull(Type::id()), + 'resolve' => function() { + return uniqid(); + } + ], + 'emails' => [ + 'type' => Type::nonNull(Type::listOf(Type::string())), + 'resolve' => function() { + return ['jon@example.com', 'jonny@example.com']; + } + ] + ] +]); +``` + +If resolver of non-null field returns **null**, graphql-php will add an error to +result and exclude the whole object from the output (an error will bubble to first +nullable parent field which will be set to **null**). + +Read the section on [Data Fetching](../data-fetching.md) for details. diff --git a/vendor/webonyx/graphql-php/docs/type-system/object-types.md b/vendor/webonyx/graphql-php/docs/type-system/object-types.md new file mode 100644 index 0000000..9c1f2fb --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/type-system/object-types.md @@ -0,0 +1,210 @@ +# Object Type Definition +Object Type is the most frequently used primitive in a typical GraphQL application. + +Conceptually Object Type is a collection of Fields. Each field, in turn, +has its own type which allows building complex hierarchies. + +In **graphql-php** object type is an instance of `GraphQL\Type\Definition\ObjectType` +(or one of it subclasses) which accepts configuration array in constructor: + +```php + 'User', + 'description' => 'Our blog visitor', + 'fields' => [ + 'firstName' => [ + 'type' => Type::string(), + 'description' => 'User first name' + ], + 'email' => Type::string() + ] +]); + +$blogStory = new ObjectType([ + 'name' => 'Story', + 'fields' => [ + 'body' => Type::string(), + 'author' => [ + 'type' => $userType, + 'description' => 'Story author', + 'resolve' => function(Story $blogStory) { + return DataSource::findUser($blogStory->authorId); + } + ], + 'likes' => [ + 'type' => Type::listOf($userType), + 'description' => 'List of users who liked the story', + 'args' => [ + 'limit' => [ + 'type' => Type::int(), + 'description' => 'Limit the number of recent likes returned', + 'defaultValue' => 10 + ] + ], + 'resolve' => function(Story $blogStory, $args) { + return DataSource::findLikes($blogStory->id, $args['limit']); + } + ] + ] +]); +``` +This example uses **inline** style for Object Type definitions, but you can also use +[inheritance or type language](index.md#type-definition-styles). + + +# Configuration options +Object type constructor expects configuration array. Below is a full list of available options: + +Option | Type | Notes +------------ | -------- | ----- +name | `string` | **Required.** Unique name of this object type within Schema +fields | `array` or `callable` | **Required**. An array describing object fields or callable returning such an array. See [Fields](#field-definitions) section below for expected structure of each array entry. See also the section on [Circular types](#recurring-and-circular-types) for an explanation of when to use callable for this option. +description | `string` | Plain-text description of this type for clients (e.g. used by [GraphiQL](https://github.com/graphql/graphiql) for auto-generated documentation) +interfaces | `array` or `callable` | List of interfaces implemented by this type or callable returning such a list. See [Interface Types](interfaces.md) for details. See also the section on [Circular types](#recurring-and-circular-types) for an explanation of when to use callable for this option. +isTypeOf | `callable` | **function($value, $context, [ResolveInfo](../reference.md#graphqltypedefinitionresolveinfo) $info)**
Expected to return **true** if **$value** qualifies for this type (see section about [Abstract Type Resolution](interfaces.md#interface-role-in-data-fetching) for explanation). +resolveField | `callable` | **function($value, $args, $context, [ResolveInfo](../reference.md#graphqltypedefinitionresolveinfo) $info)**
Given the **$value** of this type, it is expected to return value for a field defined in **$info->fieldName**. A good place to define a type-specific strategy for field resolution. See section on [Data Fetching](../data-fetching.md) for details. + +# Field configuration options +Below is a full list of available field configuration options: + +Option | Type | Notes +------ | ---- | ----- +name | `string` | **Required.** Name of the field. When not set - inferred from **fields** array key (read about [shorthand field definition](#shorthand-field-definitions) below) +type | `Type` | **Required.** An instance of internal or custom type. Note: type must be represented by a single instance within one schema (see also [Type Registry](index.md#type-registry)) +args | `array` | An array of possible type arguments. Each entry is expected to be an array with keys: **name**, **type**, **description**, **defaultValue**. See [Field Arguments](#field-arguments) section below. +resolve | `callable` | **function($value, $args, $context, [ResolveInfo](../reference.md#graphqltypedefinitionresolveinfo) $info)**
Given the **$value** of this type, it is expected to return actual value of the current field. See section on [Data Fetching](../data-fetching.md) for details +complexity | `callable` | **function($childrenComplexity, $args)**
Used to restrict query complexity. The feature is disabled by default, read about [Security](../security.md#query-complexity-analysis) to use it. +description | `string` | Plain-text description of this field for clients (e.g. used by [GraphiQL](https://github.com/graphql/graphiql) for auto-generated documentation) +deprecationReason | `string` | Text describing why this field is deprecated. When not empty - field will not be returned by introspection queries (unless forced) + +# Field arguments +Every field on a GraphQL object type can have zero or more arguments, defined in **args** option of field definition. +Each argument is an array with following options: + +Option | Type | Notes +------ | ---- | ----- +name | `string` | **Required.** Name of the argument. When not set - inferred from **args** array key +type | `Type` | **Required.** Instance of one of [Input Types](input-types.md) (**scalar**, **enum**, **InputObjectType** + any combination of those with **nonNull** and **listOf** modifiers) +description | `string` | Plain-text description of this argument for clients (e.g. used by [GraphiQL](https://github.com/graphql/graphiql) for auto-generated documentation) +defaultValue | `scalar` | Default value for this argument. Use the internal value if specifying a default for an **enum** type + +# Shorthand field definitions +Fields can be also defined in **shorthand** notation (with only **name** and **type** options): +```php +'fields' => [ + 'id' => Type::id(), + 'fieldName' => $fieldType +] +``` +which is equivalent of: +```php +'fields' => [ + 'id' => ['type' => Type::id()], + 'fieldName' => ['type' => $fieldName] +] +``` +which is in turn equivalent of the full form: +```php +'fields' => [ + ['name' => 'id', 'type' => Type::id()], + ['name' => 'fieldName', 'type' => $fieldName] +] +``` +Same shorthand notation applies to field arguments as well. + +# Recurring and circular types +Almost all real-world applications contain recurring or circular types. +Think user friends or nested comments for example. + +**graphql-php** allows such types, but you have to use `callable` in +option **fields** (and/or **interfaces**). + +For example: +```php + 'User', + 'fields' => function() use (&$userType) { + return [ + 'email' => [ + 'type' => Type::string() + ], + 'friends' => [ + 'type' => Type::listOf($userType) + ] + ]; + } +]); +``` + +Same example for [inheritance style of type definitions](index.md#type-definition-styles) using [TypeRegistry](index.md#type-registry): +```php + function() { + return [ + 'email' => MyTypes::string(), + 'friends' => MyTypes::listOf(MyTypes::user()) + ]; + } + ]; + parent::__construct($config); + } +} + +class MyTypes +{ + private static $user; + + public static function user() + { + return self::$user ?: (self::$user = new UserType()); + } + + public static function string() + { + return Type::string(); + } + + public static function listOf($type) + { + return Type::listOf($type); + } +} +``` + +# Field Resolution +Field resolution is the primary mechanism in **graphql-php** for returning actual data for your fields. +It is implemented using **resolveField** callable in type definition or **resolve** +callable in field definition (which has precedence). + +Read the section on [Data Fetching](../data-fetching.md) for a complete description of this process. + +# Custom Metadata +All types in **graphql-php** accept configuration array. In some cases, you may be interested in +passing your own metadata for type or field definition. + +**graphql-php** preserves original configuration array in every type or field instance in +public property **$config**. Use it to implement app-level mappings and definitions. diff --git a/vendor/webonyx/graphql-php/docs/type-system/scalar-types.md b/vendor/webonyx/graphql-php/docs/type-system/scalar-types.md new file mode 100644 index 0000000..3029238 --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/type-system/scalar-types.md @@ -0,0 +1,130 @@ +# Built-in Scalar Types +GraphQL specification describes several built-in scalar types. In **graphql-php** they are +exposed as static methods of [`GraphQL\Type\Definition\Type`](../reference.md#graphqltypedefinitiontype) class: + +```php +parseValue($value); + } + + /** + * Parses an externally provided value (query variable) to use as an input + * + * @param mixed $value + * @return mixed + */ + public function parseValue($value) + { + if (!filter_var($value, FILTER_VALIDATE_EMAIL)) { + throw new Error("Cannot represent following value as email: " . Utils::printSafeJson($value)); + } + return $value; + } + + /** + * Parses an externally provided literal value (hardcoded in GraphQL query) to use as an input. + * + * E.g. + * { + * user(email: "user@example.com") + * } + * + * @param \GraphQL\Language\AST\Node $valueNode + * @param array|null $variables + * @return string + * @throws Error + */ + public function parseLiteral($valueNode, array $variables = null) + { + // Note: throwing GraphQL\Error\Error vs \UnexpectedValueException to benefit from GraphQL + // error location in query: + if (!$valueNode instanceof StringValueNode) { + throw new Error('Query error: Can only parse strings got: ' . $valueNode->kind, [$valueNode]); + } + if (!filter_var($valueNode->value, FILTER_VALIDATE_EMAIL)) { + throw new Error("Not a valid email", [$valueNode]); + } + return $valueNode->value; + } +} +``` + +Or with inline style: + +```php + 'Email', + 'serialize' => function($value) {/* See function body above */}, + 'parseValue' => function($value) {/* See function body above */}, + 'parseLiteral' => function($valueNode, array $variables = null) {/* See function body above */}, +]); +``` diff --git a/vendor/webonyx/graphql-php/docs/type-system/schema.md b/vendor/webonyx/graphql-php/docs/type-system/schema.md new file mode 100644 index 0000000..08ee12f --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/type-system/schema.md @@ -0,0 +1,194 @@ +# Schema Definition +The schema is a container of your type hierarchy, which accepts root types in a constructor and provides +methods for receiving information about your types to internal GrahpQL tools. + +In **graphql-php** schema is an instance of [`GraphQL\Type\Schema`](../reference.md#graphqltypeschema) +which accepts configuration array in a constructor: + +```php + $queryType, + 'mutation' => $mutationType, +]); +``` +See possible constructor options [below](#configuration-options). + +# Query and Mutation types +The schema consists of two root types: + +* **Query** type is a surface of your read API +* **Mutation** type (optional) exposes write API by declaring all possible mutations in your app. + +Query and Mutation types are regular [object types](object-types.md) containing root-level fields +of your API: + +```php + 'Query', + 'fields' => [ + 'hello' => [ + 'type' => Type::string(), + 'resolve' => function() { + return 'Hello World!'; + } + ], + 'hero' => [ + 'type' => $characterInterface, + 'args' => [ + 'episode' => [ + 'type' => $episodeEnum + ] + ], + 'resolve' => function ($rootValue, $args) { + return StarWarsData::getHero(isset($args['episode']) ? $args['episode'] : null); + }, + ] + ] +]); + +$mutationType = new ObjectType([ + 'name' => 'Mutation', + 'fields' => [ + 'createReview' => [ + 'type' => $createReviewOutput, + 'args' => [ + 'episode' => $episodeEnum, + 'review' => $reviewInputObject + ], + 'resolve' => function($val, $args) { + // TODOC + } + ] + ] +]); +``` + +Keep in mind that other than the special meaning of declaring a surface area of your API, +those types are the same as any other [object type](object-types.md), and their fields work +exactly the same way. + +**Mutation** type is also just a regular object type. The difference is in semantics. +Field names of Mutation type are usually verbs and they almost always have arguments - quite often +with complex input values (see [Mutations and Input Types](input-types.md) for details). + +# Configuration Options +Schema constructor expects an instance of [`GraphQL\Type\SchemaConfig`](../reference.md#graphqltypeschemaconfig) +or an array with following options: + +Option | Type | Notes +------------ | -------- | ----- +query | `ObjectType` | **Required.** Object type (usually named "Query") containing root-level fields of your read API +mutation | `ObjectType` | Object type (usually named "Mutation") containing root-level fields of your write API +subscription | `ObjectType` | Reserved for future subscriptions implementation. Currently presented for compatibility with introspection query of **graphql-js**, used by various clients (like Relay or GraphiQL) +directives | `Directive[]` | A full list of [directives](directives.md) supported by your schema. By default, contains built-in **@skip** and **@include** directives.

If you pass your own directives and still want to use built-in directives - add them explicitly. For example:

*array_merge(GraphQL::getStandardDirectives(), [$myCustomDirective]);* +types | `ObjectType[]` | List of object types which cannot be detected by **graphql-php** during static schema analysis.

Most often it happens when the object type is never referenced in fields directly but is still a part of a schema because it implements an interface which resolves to this object type in its **resolveType** callable.

Note that you are not required to pass all of your types here - it is simply a workaround for concrete use-case. +typeLoader | `callable` | **function($name)** Expected to return type instance given the name. Must always return the same instance if called multiple times. See section below on lazy type loading. + +# Using config class +If you prefer fluid interface for config with auto-completion in IDE and static time validation, +use [`GraphQL\Type\SchemaConfig`](../reference.md#graphqltypeschemaconfig) instead of an array: + +```php +setQuery($myQueryType) + ->setTypeLoader($myTypeLoader); + +$schema = new Schema($config); +``` + + +# Lazy loading of types +By default, the schema will scan all of your type, field and argument definitions to serve GraphQL queries. +It may cause performance overhead when there are many types in the schema. + +In this case, it is recommended to pass **typeLoader** option to schema constructor and define all +of your object **fields** as callbacks. + +Type loading concept is very similar to PHP class loading, but keep in mind that **typeLoader** must +always return the same instance of a type. + +Usage example: +```php +types[$name])) { + $this->types[$name] = $this->{$name}(); + } + return $this->types[$name]; + } + + private function MyTypeA() + { + return new ObjectType([ + 'name' => 'MyTypeA', + 'fields' => function() { + return [ + 'b' => ['type' => $this->get('MyTypeB')] + ]; + } + ]); + } + + private function MyTypeB() + { + // ... + } +} + +$registry = new Types(); + +$schema = new Schema([ + 'query' => $registry->get('Query'), + 'typeLoader' => function($name) use ($registry) { + return $registry->get($name); + } +]); +``` + + +# Schema Validation +By default, the schema is created with only shallow validation of type and field definitions +(because validation requires full schema scan and is very costly on bigger schemas). + +But there is a special method **assertValid()** on schema instance which throws +`GraphQL\Error\InvariantViolation` exception when it encounters any error, like: + +- Invalid types used for fields/arguments +- Missing interface implementations +- Invalid interface implementations +- Other schema errors... + +Schema validation is supposed to be used in CLI commands or during build step of your app. +Don't call it in web requests in production. + +Usage example: +```php + $myQueryType + ]); + $schema->assertValid(); +} catch (GraphQL\Error\InvariantViolation $e) { + echo $e->getMessage(); +} +``` diff --git a/vendor/webonyx/graphql-php/docs/type-system/type-language.md b/vendor/webonyx/graphql-php/docs/type-system/type-language.md new file mode 100644 index 0000000..2961551 --- /dev/null +++ b/vendor/webonyx/graphql-php/docs/type-system/type-language.md @@ -0,0 +1,91 @@ +# Defining your schema +Since 0.9.0 + +[Type language](http://graphql.org/learn/schema/#type-language) is a convenient way to define your schema, +especially with IDE autocompletion and syntax validation. + +Here is a simple schema defined in GraphQL type language (e.g. in a separate **schema.graphql** file): + +```graphql +schema { + query: Query + mutation: Mutation +} + +type Query { + greetings(input: HelloInput!): String! +} + +input HelloInput { + firstName: String! + lastName: String +} +``` + +In order to create schema instance out of this file, use +[`GraphQL\Utils\BuildSchema`](../reference.md#graphqlutilsbuildschema): + +```php + 'SearchResult', + 'types' => [ + MyTypes::story(), + MyTypes::user() + ], + 'resolveType' => function($value) { + if ($value->type === 'story') { + return MyTypes::story(); + } else { + return MyTypes::user(); + } + } +]); +``` + +This example uses **inline** style for Union definition, but you can also use +[inheritance or type language](index.md#type-definition-styles). + +# Configuration options +The constructor of UnionType accepts an array. Below is a full list of allowed options: + +Option | Type | Notes +------ | ---- | ----- +name | `string` | **Required.** Unique name of this interface type within Schema +types | `array` | **Required.** List of Object Types included in this Union. Note that you can't create a Union type out of Interfaces or other Unions. +description | `string` | Plain-text description of this type for clients (e.g. used by [GraphiQL](https://github.com/graphql/graphiql) for auto-generated documentation) +resolveType | `callback` | **function($value, $context, [ResolveInfo](../reference.md#graphqltypedefinitionresolveinfo) $info)**
Receives **$value** from resolver of the parent field and returns concrete Object Type for this **$value**. diff --git a/vendor/webonyx/graphql-php/examples/00-hello-world/README.md b/vendor/webonyx/graphql-php/examples/00-hello-world/README.md new file mode 100644 index 0000000..98a7393 --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/00-hello-world/README.md @@ -0,0 +1,18 @@ +# Hello world +Clean and simple single-file example of main GraphQL concepts originally proposed and +implemented by [Leo Cavalcante](https://github.com/leocavalcante) + +### Run locally +``` +php -S localhost:8080 ./graphql.php +``` + +### Try query +``` +curl http://localhost:8080 -d '{"query": "query { echo(message: \"Hello World\") }" }' +``` + +### Try mutation +``` +curl http://localhost:8080 -d '{"query": "mutation { sum(x: 2, y: 2) }" }' +``` diff --git a/vendor/webonyx/graphql-php/examples/00-hello-world/graphql.php b/vendor/webonyx/graphql-php/examples/00-hello-world/graphql.php new file mode 100644 index 0000000..30b1f9c --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/00-hello-world/graphql.php @@ -0,0 +1,69 @@ + 'Query', + 'fields' => [ + 'echo' => [ + 'type' => Type::string(), + 'args' => [ + 'message' => ['type' => Type::string()], + ], + 'resolve' => function ($root, $args) { + return $root['prefix'] . $args['message']; + } + ], + ], + ]); + + $mutationType = new ObjectType([ + 'name' => 'Calc', + 'fields' => [ + 'sum' => [ + 'type' => Type::int(), + 'args' => [ + 'x' => ['type' => Type::int()], + 'y' => ['type' => Type::int()], + ], + 'resolve' => function ($root, $args) { + return $args['x'] + $args['y']; + }, + ], + ], + ]); + + // See docs on schema options: + // http://webonyx.github.io/graphql-php/type-system/schema/#configuration-options + $schema = new Schema([ + 'query' => $queryType, + 'mutation' => $mutationType, + ]); + + $rawInput = file_get_contents('php://input'); + $input = json_decode($rawInput, true); + $query = $input['query']; + $variableValues = isset($input['variables']) ? $input['variables'] : null; + + $rootValue = ['prefix' => 'You said: ']; + $result = GraphQL::executeQuery($schema, $query, $rootValue, null, $variableValues); + $output = $result->toArray(); +} catch (\Exception $e) { + $output = [ + 'error' => [ + 'message' => $e->getMessage() + ] + ]; +} +header('Content-Type: application/json; charset=UTF-8'); +echo json_encode($output); + diff --git a/vendor/webonyx/graphql-php/examples/01-blog/Blog/AppContext.php b/vendor/webonyx/graphql-php/examples/01-blog/Blog/AppContext.php new file mode 100644 index 0000000..f6c16cf --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/01-blog/Blog/AppContext.php @@ -0,0 +1,28 @@ + new User([ + 'id' => '1', + 'email' => 'john@example.com', + 'firstName' => 'John', + 'lastName' => 'Doe' + ]), + '2' => new User([ + 'id' => '2', + 'email' => 'jane@example.com', + 'firstName' => 'Jane', + 'lastName' => 'Doe' + ]), + '3' => new User([ + 'id' => '3', + 'email' => 'john@example.com', + 'firstName' => 'John', + 'lastName' => 'Doe' + ]), + ]; + + self::$stories = [ + '1' => new Story(['id' => '1', 'authorId' => '1', 'body' => '

GraphQL is awesome!

']), + '2' => new Story(['id' => '2', 'authorId' => '1', 'body' => 'Test this']), + '3' => new Story(['id' => '3', 'authorId' => '3', 'body' => "This\n
story\n
spans\n
newlines"]), + ]; + + self::$storyLikes = [ + '1' => ['1', '2', '3'], + '2' => [], + '3' => ['1'] + ]; + + self::$comments = [ + // thread #1: + '100' => new Comment(['id' => '100', 'authorId' => '3', 'storyId' => '1', 'body' => 'Likes']), + '110' => new Comment(['id' =>'110', 'authorId' =>'2', 'storyId' => '1', 'body' => 'Reply #1', 'parentId' => '100']), + '111' => new Comment(['id' => '111', 'authorId' => '1', 'storyId' => '1', 'body' => 'Reply #1-1', 'parentId' => '110']), + '112' => new Comment(['id' => '112', 'authorId' => '3', 'storyId' => '1', 'body' => 'Reply #1-2', 'parentId' => '110']), + '113' => new Comment(['id' => '113', 'authorId' => '2', 'storyId' => '1', 'body' => 'Reply #1-3', 'parentId' => '110']), + '114' => new Comment(['id' => '114', 'authorId' => '1', 'storyId' => '1', 'body' => 'Reply #1-4', 'parentId' => '110']), + '115' => new Comment(['id' => '115', 'authorId' => '3', 'storyId' => '1', 'body' => 'Reply #1-5', 'parentId' => '110']), + '116' => new Comment(['id' => '116', 'authorId' => '1', 'storyId' => '1', 'body' => 'Reply #1-6', 'parentId' => '110']), + '117' => new Comment(['id' => '117', 'authorId' => '2', 'storyId' => '1', 'body' => 'Reply #1-7', 'parentId' => '110']), + '120' => new Comment(['id' => '120', 'authorId' => '3', 'storyId' => '1', 'body' => 'Reply #2', 'parentId' => '100']), + '130' => new Comment(['id' => '130', 'authorId' => '3', 'storyId' => '1', 'body' => 'Reply #3', 'parentId' => '100']), + '200' => new Comment(['id' => '200', 'authorId' => '2', 'storyId' => '1', 'body' => 'Me2']), + '300' => new Comment(['id' => '300', 'authorId' => '3', 'storyId' => '1', 'body' => 'U2']), + + # thread #2: + '400' => new Comment(['id' => '400', 'authorId' => '2', 'storyId' => '2', 'body' => 'Me too']), + '500' => new Comment(['id' => '500', 'authorId' => '2', 'storyId' => '2', 'body' => 'Nice!']), + ]; + + self::$storyComments = [ + '1' => ['100', '200', '300'], + '2' => ['400', '500'] + ]; + + self::$commentReplies = [ + '100' => ['110', '120', '130'], + '110' => ['111', '112', '113', '114', '115', '116', '117'], + ]; + + self::$storyMentions = [ + '1' => [ + self::$users['2'] + ], + '2' => [ + self::$stories['1'], + self::$users['3'] + ] + ]; + } + + public static function findUser($id) + { + return isset(self::$users[$id]) ? self::$users[$id] : null; + } + + public static function findStory($id) + { + return isset(self::$stories[$id]) ? self::$stories[$id] : null; + } + + public static function findComment($id) + { + return isset(self::$comments[$id]) ? self::$comments[$id] : null; + } + + public static function findLastStoryFor($authorId) + { + $storiesFound = array_filter(self::$stories, function(Story $story) use ($authorId) { + return $story->authorId == $authorId; + }); + return !empty($storiesFound) ? $storiesFound[count($storiesFound) - 1] : null; + } + + public static function findLikes($storyId, $limit) + { + $likes = isset(self::$storyLikes[$storyId]) ? self::$storyLikes[$storyId] : []; + $result = array_map( + function($userId) { + return self::$users[$userId]; + }, + $likes + ); + return array_slice($result, 0, $limit); + } + + public static function isLikedBy($storyId, $userId) + { + $subscribers = isset(self::$storyLikes[$storyId]) ? self::$storyLikes[$storyId] : []; + return in_array($userId, $subscribers); + } + + public static function getUserPhoto($userId, $size) + { + return new Image([ + 'id' => $userId, + 'type' => Image::TYPE_USERPIC, + 'size' => $size, + 'width' => rand(100, 200), + 'height' => rand(100, 200) + ]); + } + + public static function findLatestStory() + { + return array_pop(self::$stories); + } + + public static function findStories($limit, $afterId = null) + { + $start = $afterId ? (int) array_search($afterId, array_keys(self::$stories)) + 1 : 0; + return array_slice(array_values(self::$stories), $start, $limit); + } + + public static function findComments($storyId, $limit = 5, $afterId = null) + { + $storyComments = isset(self::$storyComments[$storyId]) ? self::$storyComments[$storyId] : []; + + $start = isset($after) ? (int) array_search($afterId, $storyComments) + 1 : 0; + $storyComments = array_slice($storyComments, $start, $limit); + + return array_map( + function($commentId) { + return self::$comments[$commentId]; + }, + $storyComments + ); + } + + public static function findReplies($commentId, $limit = 5, $afterId = null) + { + $commentReplies = isset(self::$commentReplies[$commentId]) ? self::$commentReplies[$commentId] : []; + + $start = isset($after) ? (int) array_search($afterId, $commentReplies) + 1: 0; + $commentReplies = array_slice($commentReplies, $start, $limit); + + return array_map( + function($replyId) { + return self::$comments[$replyId]; + }, + $commentReplies + ); + } + + public static function countComments($storyId) + { + return isset(self::$storyComments[$storyId]) ? count(self::$storyComments[$storyId]) : 0; + } + + public static function countReplies($commentId) + { + return isset(self::$commentReplies[$commentId]) ? count(self::$commentReplies[$commentId]) : 0; + } + + public static function findStoryMentions($storyId) + { + return isset(self::$storyMentions[$storyId]) ? self::$storyMentions[$storyId] :[]; + } +} diff --git a/vendor/webonyx/graphql-php/examples/01-blog/Blog/Data/Image.php b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Data/Image.php new file mode 100644 index 0000000..68a81ba --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Data/Image.php @@ -0,0 +1,29 @@ + 'Comment', + 'fields' => function() { + return [ + 'id' => Types::id(), + 'author' => Types::user(), + 'parent' => Types::comment(), + 'isAnonymous' => Types::boolean(), + 'replies' => [ + 'type' => Types::listOf(Types::comment()), + 'args' => [ + 'after' => Types::int(), + 'limit' => [ + 'type' => Types::int(), + 'defaultValue' => 5 + ] + ] + ], + 'totalReplyCount' => Types::int(), + + Types::htmlField('body') + ]; + }, + 'resolveField' => function($value, $args, $context, ResolveInfo $info) { + $method = 'resolve' . ucfirst($info->fieldName); + if (method_exists($this, $method)) { + return $this->{$method}($value, $args, $context, $info); + } else { + return $value->{$info->fieldName}; + } + } + ]; + parent::__construct($config); + } + + public function resolveAuthor(Comment $comment) + { + if ($comment->isAnonymous) { + return null; + } + return DataSource::findUser($comment->authorId); + } + + public function resolveParent(Comment $comment) + { + if ($comment->parentId) { + return DataSource::findComment($comment->parentId); + } + return null; + } + + public function resolveReplies(Comment $comment, $args) + { + $args += ['after' => null]; + return DataSource::findReplies($comment->id, $args['limit'], $args['after']); + } + + public function resolveTotalReplyCount(Comment $comment) + { + return DataSource::countReplies($comment->id); + } +} diff --git a/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Enum/ContentFormatEnum.php b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Enum/ContentFormatEnum.php new file mode 100644 index 0000000..8825247 --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Enum/ContentFormatEnum.php @@ -0,0 +1,19 @@ + 'ContentFormatEnum', + 'values' => [self::FORMAT_TEXT, self::FORMAT_HTML] + ]; + parent::__construct($config); + } +} diff --git a/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Enum/ImageSizeEnumType.php b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Enum/ImageSizeEnumType.php new file mode 100644 index 0000000..5e744a6 --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Enum/ImageSizeEnumType.php @@ -0,0 +1,23 @@ + [ + 'ICON' => Image::SIZE_ICON, + 'SMALL' => Image::SIZE_SMALL, + 'MEDIUM' => Image::SIZE_MEDIUM, + 'ORIGINAL' => Image::SIZE_ORIGINAL + ] + ]; + + parent::__construct($config); + } +} diff --git a/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Field/HtmlField.php b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Field/HtmlField.php new file mode 100644 index 0000000..f15ba6b --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Field/HtmlField.php @@ -0,0 +1,52 @@ + $name, + 'type' => Types::string(), + 'args' => [ + 'format' => [ + 'type' => Types::contentFormatEnum(), + 'defaultValue' => ContentFormatEnum::FORMAT_HTML + ], + 'maxLength' => Types::int() + ], + 'resolve' => function($object, $args) use ($objectKey) { + $html = $object->{$objectKey}; + $text = strip_tags($html); + + if (!empty($args['maxLength'])) { + $safeText = mb_substr($text, 0, $args['maxLength']); + } else { + $safeText = $text; + } + + switch ($args['format']) { + case ContentFormatEnum::FORMAT_HTML: + if ($safeText !== $text) { + // Text was truncated, so just show what's safe: + return nl2br($safeText); + } else { + return $html; + } + + case ContentFormatEnum::FORMAT_TEXT: + default: + return $safeText; + } + } + ]; + } +} diff --git a/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/ImageType.php b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/ImageType.php new file mode 100644 index 0000000..aef9bff --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/ImageType.php @@ -0,0 +1,62 @@ + 'ImageType', + 'fields' => [ + 'id' => Types::id(), + 'type' => new EnumType([ + 'name' => 'ImageTypeEnum', + 'values' => [ + 'USERPIC' => Image::TYPE_USERPIC + ] + ]), + 'size' => Types::imageSizeEnum(), + 'width' => Types::int(), + 'height' => Types::int(), + 'url' => [ + 'type' => Types::url(), + 'resolve' => [$this, 'resolveUrl'] + ], + + // Just for the sake of example + 'fieldWithError' => [ + 'type' => Types::string(), + 'resolve' => function() { + throw new \Exception("Field with exception"); + } + ], + 'nonNullFieldWithError' => [ + 'type' => Types::nonNull(Types::string()), + 'resolve' => function() { + throw new \Exception("Non-null field with exception"); + } + ] + ] + ]; + + parent::__construct($config); + } + + public function resolveUrl(Image $value, $args, AppContext $context) + { + switch ($value->type) { + case Image::TYPE_USERPIC: + $path = "/images/user/{$value->id}-{$value->size}.jpg"; + break; + default: + throw new \UnexpectedValueException("Unexpected image type: " . $value->type); + } + return $context->rootUrl . $path; + } +} diff --git a/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/NodeType.php b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/NodeType.php new file mode 100644 index 0000000..d3be9ed --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/NodeType.php @@ -0,0 +1,34 @@ + 'Node', + 'fields' => [ + 'id' => Types::id() + ], + 'resolveType' => [$this, 'resolveNodeType'] + ]; + parent::__construct($config); + } + + public function resolveNodeType($object) + { + if ($object instanceof User) { + return Types::user(); + } else if ($object instanceof Image) { + return Types::image(); + } else if ($object instanceof Story) { + return Types::story(); + } + } +} diff --git a/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/QueryType.php b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/QueryType.php new file mode 100644 index 0000000..ff85577 --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/QueryType.php @@ -0,0 +1,97 @@ + 'Query', + 'fields' => [ + 'user' => [ + 'type' => Types::user(), + 'description' => 'Returns user by id (in range of 1-5)', + 'args' => [ + 'id' => Types::nonNull(Types::id()) + ] + ], + 'viewer' => [ + 'type' => Types::user(), + 'description' => 'Represents currently logged-in user (for the sake of example - simply returns user with id == 1)' + ], + 'stories' => [ + 'type' => Types::listOf(Types::story()), + 'description' => 'Returns subset of stories posted for this blog', + 'args' => [ + 'after' => [ + 'type' => Types::id(), + 'description' => 'Fetch stories listed after the story with this ID' + ], + 'limit' => [ + 'type' => Types::int(), + 'description' => 'Number of stories to be returned', + 'defaultValue' => 10 + ] + ] + ], + 'lastStoryPosted' => [ + 'type' => Types::story(), + 'description' => 'Returns last story posted for this blog' + ], + 'deprecatedField' => [ + 'type' => Types::string(), + 'deprecationReason' => 'This field is deprecated!' + ], + 'fieldWithException' => [ + 'type' => Types::string(), + 'resolve' => function() { + throw new \Exception("Exception message thrown in field resolver"); + } + ], + 'hello' => Type::string() + ], + 'resolveField' => function($val, $args, $context, ResolveInfo $info) { + return $this->{$info->fieldName}($val, $args, $context, $info); + } + ]; + parent::__construct($config); + } + + public function user($rootValue, $args) + { + return DataSource::findUser($args['id']); + } + + public function viewer($rootValue, $args, AppContext $context) + { + return $context->viewer; + } + + public function stories($rootValue, $args) + { + $args += ['after' => null]; + return DataSource::findStories($args['limit'], $args['after']); + } + + public function lastStoryPosted() + { + return DataSource::findLatestStory(); + } + + public function hello() + { + return 'Your graphql-php endpoint is ready! Use GraphiQL to browse API'; + } + + public function deprecatedField() + { + return 'You can request deprecated field, but it is not displayed in auto-generated documentation by default.'; + } +} diff --git a/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Scalar/EmailType.php b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Scalar/EmailType.php new file mode 100644 index 0000000..fd78ea7 --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Scalar/EmailType.php @@ -0,0 +1,70 @@ + 'Email', + 'serialize' => [__CLASS__, 'serialize'], + 'parseValue' => [__CLASS__, 'parseValue'], + 'parseLiteral' => [__CLASS__, 'parseLiteral'], + ]); + } + + /** + * Serializes an internal value to include in a response. + * + * @param string $value + * @return string + */ + public static function serialize($value) + { + // Assuming internal representation of email is always correct: + return $value; + + // If it might be incorrect and you want to make sure that only correct values are included in response - + // use following line instead: + // return $this->parseValue($value); + } + + /** + * Parses an externally provided value (query variable) to use as an input + * + * @param mixed $value + * @return mixed + */ + public static function parseValue($value) + { + if (!filter_var($value, FILTER_VALIDATE_EMAIL)) { + throw new \UnexpectedValueException("Cannot represent value as email: " . Utils::printSafe($value)); + } + return $value; + } + + /** + * Parses an externally provided literal value (hardcoded in GraphQL query) to use as an input + * + * @param \GraphQL\Language\AST\Node $valueNode + * @return string + * @throws Error + */ + public static function parseLiteral($valueNode) + { + // Note: throwing GraphQL\Error\Error vs \UnexpectedValueException to benefit from GraphQL + // error location in query: + if (!$valueNode instanceof StringValueNode) { + throw new Error('Query error: Can only parse strings got: ' . $valueNode->kind, [$valueNode]); + } + if (!filter_var($valueNode->value, FILTER_VALIDATE_EMAIL)) { + throw new Error("Not a valid email", [$valueNode]); + } + return $valueNode->value; + } +} diff --git a/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Scalar/UrlType.php b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Scalar/UrlType.php new file mode 100644 index 0000000..0590546 --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/Scalar/UrlType.php @@ -0,0 +1,63 @@ +parseValue($value); + } + + /** + * Parses an externally provided value (query variable) to use as an input + * + * @param mixed $value + * @return mixed + * @throws Error + */ + public function parseValue($value) + { + if (!is_string($value) || !filter_var($value, FILTER_VALIDATE_URL)) { // quite naive, but after all this is example + throw new Error("Cannot represent value as URL: " . Utils::printSafe($value)); + } + return $value; + } + + /** + * Parses an externally provided literal value to use as an input (e.g. in Query AST) + * + * @param Node $valueNode + * @param array|null $variables + * @return null|string + * @throws Error + */ + public function parseLiteral($valueNode, array $variables = null) + { + // Note: throwing GraphQL\Error\Error vs \UnexpectedValueException to benefit from GraphQL + // error location in query: + if (!($valueNode instanceof StringValueNode)) { + throw new Error('Query error: Can only parse strings got: ' . $valueNode->kind, [$valueNode]); + } + if (!is_string($valueNode->value) || !filter_var($valueNode->value, FILTER_VALIDATE_URL)) { + throw new Error('Query error: Not a valid URL', [$valueNode]); + } + return $valueNode->value; + } +} diff --git a/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/SearchResultType.php b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/SearchResultType.php new file mode 100644 index 0000000..d832a26 --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/SearchResultType.php @@ -0,0 +1,31 @@ + 'SearchResultType', + 'types' => function() { + return [ + Types::story(), + Types::user() + ]; + }, + 'resolveType' => function($value) { + if ($value instanceof Story) { + return Types::story(); + } else if ($value instanceof User) { + return Types::user(); + } + } + ]; + parent::__construct($config); + } +} diff --git a/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/StoryType.php b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/StoryType.php new file mode 100644 index 0000000..32cea4e --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/StoryType.php @@ -0,0 +1,127 @@ + 'Story', + 'fields' => function() { + return [ + 'id' => Types::id(), + 'author' => Types::user(), + 'mentions' => Types::listOf(Types::mention()), + 'totalCommentCount' => Types::int(), + 'comments' => [ + 'type' => Types::listOf(Types::comment()), + 'args' => [ + 'after' => [ + 'type' => Types::id(), + 'description' => 'Load all comments listed after given comment ID' + ], + 'limit' => [ + 'type' => Types::int(), + 'defaultValue' => 5 + ] + ] + ], + 'likes' => [ + 'type' => Types::listOf(Types::user()), + 'args' => [ + 'limit' => [ + 'type' => Types::int(), + 'description' => 'Limit the number of recent likes returned', + 'defaultValue' => 5 + ] + ] + ], + 'likedBy' => [ + 'type' => Types::listOf(Types::user()), + ], + 'affordances' => Types::listOf(new EnumType([ + 'name' => 'StoryAffordancesEnum', + 'values' => [ + self::EDIT, + self::DELETE, + self::LIKE, + self::UNLIKE, + self::REPLY + ] + ])), + 'hasViewerLiked' => Types::boolean(), + + Types::htmlField('body'), + ]; + }, + 'interfaces' => [ + Types::node() + ], + 'resolveField' => function($value, $args, $context, ResolveInfo $info) { + $method = 'resolve' . ucfirst($info->fieldName); + if (method_exists($this, $method)) { + return $this->{$method}($value, $args, $context, $info); + } else { + return $value->{$info->fieldName}; + } + } + ]; + parent::__construct($config); + } + + public function resolveAuthor(Story $story) + { + return DataSource::findUser($story->authorId); + } + + public function resolveAffordances(Story $story, $args, AppContext $context) + { + $isViewer = $context->viewer === DataSource::findUser($story->authorId); + $isLiked = DataSource::isLikedBy($story->id, $context->viewer->id); + + if ($isViewer) { + $affordances[] = self::EDIT; + $affordances[] = self::DELETE; + } + if ($isLiked) { + $affordances[] = self::UNLIKE; + } else { + $affordances[] = self::LIKE; + } + return $affordances; + } + + public function resolveHasViewerLiked(Story $story, $args, AppContext $context) + { + return DataSource::isLikedBy($story->id, $context->viewer->id); + } + + public function resolveTotalCommentCount(Story $story) + { + return DataSource::countComments($story->id); + } + + public function resolveComments(Story $story, $args) + { + $args += ['after' => null]; + return DataSource::findComments($story->id, $args['limit'], $args['after']); + } +} diff --git a/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/UserType.php b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/UserType.php new file mode 100644 index 0000000..9960b62 --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Type/UserType.php @@ -0,0 +1,68 @@ + 'User', + 'description' => 'Our blog authors', + 'fields' => function() { + return [ + 'id' => Types::id(), + 'email' => Types::email(), + 'photo' => [ + 'type' => Types::image(), + 'description' => 'User photo URL', + 'args' => [ + 'size' => Types::nonNull(Types::imageSizeEnum()), + ] + ], + 'firstName' => [ + 'type' => Types::string(), + ], + 'lastName' => [ + 'type' => Types::string(), + ], + 'lastStoryPosted' => Types::story(), + 'fieldWithError' => [ + 'type' => Types::string(), + 'resolve' => function() { + throw new \Exception("This is error field"); + } + ] + ]; + }, + 'interfaces' => [ + Types::node() + ], + 'resolveField' => function($value, $args, $context, ResolveInfo $info) { + $method = 'resolve' . ucfirst($info->fieldName); + if (method_exists($this, $method)) { + return $this->{$method}($value, $args, $context, $info); + } else { + return $value->{$info->fieldName}; + } + } + ]; + parent::__construct($config); + } + + public function resolvePhoto(User $user, $args) + { + return DataSource::getUserPhoto($user->id, $args['size']); + } + + public function resolveLastStoryPosted(User $user) + { + return DataSource::findLastStoryFor($user->id); + } +} diff --git a/vendor/webonyx/graphql-php/examples/01-blog/Blog/Types.php b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Types.php new file mode 100644 index 0000000..7ffc657 --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/01-blog/Blog/Types.php @@ -0,0 +1,209 @@ +viewer = DataSource::findUser('1'); // simulated "currently logged-in user" + $appContext->rootUrl = 'http://localhost:8080'; + $appContext->request = $_REQUEST; + + // Parse incoming query and variables + if (isset($_SERVER['CONTENT_TYPE']) && strpos($_SERVER['CONTENT_TYPE'], 'application/json') !== false) { + $raw = file_get_contents('php://input') ?: ''; + $data = json_decode($raw, true) ?: []; + } else { + $data = $_REQUEST; + } + + $data += ['query' => null, 'variables' => null]; + + if (null === $data['query']) { + $data['query'] = '{hello}'; + } + + // GraphQL schema to be passed to query executor: + $schema = new Schema([ + 'query' => Types::query() + ]); + + $result = GraphQL::executeQuery( + $schema, + $data['query'], + null, + $appContext, + (array) $data['variables'] + ); + $output = $result->toArray($debug); + $httpStatus = 200; +} catch (\Exception $error) { + $httpStatus = 500; + $output['errors'] = [ + FormattedError::createFromException($error, $debug) + ]; +} + +header('Content-Type: application/json', true, $httpStatus); +echo json_encode($output); diff --git a/vendor/webonyx/graphql-php/examples/02-shorthand/README.md b/vendor/webonyx/graphql-php/examples/02-shorthand/README.md new file mode 100644 index 0000000..dd7cfca --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/02-shorthand/README.md @@ -0,0 +1,19 @@ +# Parsing GraphQL IDL shorthand + +Same as the Hello world example but shows how to build GraphQL schema from shorthand +and wire up some resolvers + +### Run locally +``` +php -S localhost:8080 ./graphql.php +``` + +### Try query +``` +curl http://localhost:8080 -d '{"query": "query { echo(message: \"Hello World\") }" }' +``` + +### Try mutation +``` +curl http://localhost:8080 -d '{"query": "mutation { sum(x: 2, y: 2) }" }' +``` diff --git a/vendor/webonyx/graphql-php/examples/02-shorthand/graphql.php b/vendor/webonyx/graphql-php/examples/02-shorthand/graphql.php new file mode 100644 index 0000000..e958955 --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/02-shorthand/graphql.php @@ -0,0 +1,31 @@ + [ + 'message' => $e->getMessage() + ] + ]; +} +header('Content-Type: application/json; charset=UTF-8'); +echo json_encode($result); + diff --git a/vendor/webonyx/graphql-php/examples/02-shorthand/rootvalue.php b/vendor/webonyx/graphql-php/examples/02-shorthand/rootvalue.php new file mode 100644 index 0000000..97e0a82 --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/02-shorthand/rootvalue.php @@ -0,0 +1,35 @@ + function($root, $args, $context) { + $sum = new Addition(); + + return $sum->resolve($root, $args, $context); + }, + 'echo' => function($root, $args, $context) { + $echo = new Echoer(); + + return $echo->resolve($root, $args, $context); + }, + 'prefix' => 'You said: ', +]; diff --git a/vendor/webonyx/graphql-php/examples/02-shorthand/schema.graphqls b/vendor/webonyx/graphql-php/examples/02-shorthand/schema.graphqls new file mode 100644 index 0000000..a8f11d2 --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/02-shorthand/schema.graphqls @@ -0,0 +1,13 @@ +schema { + query: Query + mutation: Calc +} + +type Calc { + sum(x: Int, y: Int): Int +} + +type Query { + echo(message: String): String +} + diff --git a/vendor/webonyx/graphql-php/examples/03-server/README.md b/vendor/webonyx/graphql-php/examples/03-server/README.md new file mode 100644 index 0000000..4737d6e --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/03-server/README.md @@ -0,0 +1,19 @@ +# Hello world +Same example as 01-hello-world, but uses +[Standard Http Server](http://webonyx.github.io/graphql-php/executing-queries/#using-server) +instead of manual parsing of incoming data. + +### Run locally +``` +php -S localhost:8080 ./graphql.php +``` + +### Try query +``` +curl -d '{"query": "query { echo(message: \"Hello World\") }" }' -H "Content-Type: application/json" http://localhost:8080 +``` + +### Try mutation +``` +curl -d '{"query": "mutation { sum(x: 2, y: 2) }" }' -H "Content-Type: application/json" http://localhost:8080 +``` diff --git a/vendor/webonyx/graphql-php/examples/03-server/graphql.php b/vendor/webonyx/graphql-php/examples/03-server/graphql.php new file mode 100644 index 0000000..0c01195 --- /dev/null +++ b/vendor/webonyx/graphql-php/examples/03-server/graphql.php @@ -0,0 +1,61 @@ + 'Query', + 'fields' => [ + 'echo' => [ + 'type' => Type::string(), + 'args' => [ + 'message' => ['type' => Type::string()], + ], + 'resolve' => function ($root, $args) { + return $root['prefix'] . $args['message']; + } + ], + ], + ]); + + $mutationType = new ObjectType([ + 'name' => 'Calc', + 'fields' => [ + 'sum' => [ + 'type' => Type::int(), + 'args' => [ + 'x' => ['type' => Type::int()], + 'y' => ['type' => Type::int()], + ], + 'resolve' => function ($root, $args) { + return $args['x'] + $args['y']; + }, + ], + ], + ]); + + // See docs on schema options: + // http://webonyx.github.io/graphql-php/type-system/schema/#configuration-options + $schema = new Schema([ + 'query' => $queryType, + 'mutation' => $mutationType, + ]); + + // See docs on server options: + // http://webonyx.github.io/graphql-php/executing-queries/#server-configuration-options + $server = new StandardServer([ + 'schema' => $schema + ]); + + $server->handleRequest(); +} catch (\Exception $e) { + StandardServer::send500Error($e); +} diff --git a/vendor/webonyx/graphql-php/phpcs.xml.dist b/vendor/webonyx/graphql-php/phpcs.xml.dist new file mode 100644 index 0000000..803dd12 --- /dev/null +++ b/vendor/webonyx/graphql-php/phpcs.xml.dist @@ -0,0 +1,102 @@ + + + + + + + + + + + + src + tests + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/webonyx/graphql-php/phpstan.neon.dist b/vendor/webonyx/graphql-php/phpstan.neon.dist new file mode 100644 index 0000000..02a7a9a --- /dev/null +++ b/vendor/webonyx/graphql-php/phpstan.neon.dist @@ -0,0 +1,17 @@ +parameters: + level: 1 + + paths: + - %currentWorkingDirectory%/src + - %currentWorkingDirectory%/tests + + ignoreErrors: + - "~Construct empty\\(\\) is not allowed\\. Use more strict comparison~" + - "~(Method|Property) .+::.+(\\(\\))? (has parameter \\$\\w+ with no|has no return|has no) typehint specified~" + - "~Variable property access on .+~" + - "~Variable method call on static\\(GraphQL\\\\Server\\\\ServerConfig\\)~" # TODO get rid of + +includes: + - vendor/phpstan/phpstan-phpunit/extension.neon + - vendor/phpstan/phpstan-phpunit/rules.neon + - vendor/phpstan/phpstan-strict-rules/rules.neon diff --git a/vendor/webonyx/graphql-php/src/Deferred.php b/vendor/webonyx/graphql-php/src/Deferred.php new file mode 100644 index 0000000..6b7bd78 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Deferred.php @@ -0,0 +1,65 @@ +callback = $callback; + $this->promise = new SyncPromise(); + self::getQueue()->enqueue($this); + } + + public static function getQueue() : SplQueue + { + if (self::$queue === null) { + self::$queue = new SplQueue(); + } + + return self::$queue; + } + + public static function runQueue() : void + { + $queue = self::getQueue(); + while (! $queue->isEmpty()) { + /** @var self $dequeuedNodeValue */ + $dequeuedNodeValue = $queue->dequeue(); + $dequeuedNodeValue->run(); + } + } + + public function then($onFulfilled = null, $onRejected = null) + { + return $this->promise->then($onFulfilled, $onRejected); + } + + public function run() : void + { + try { + $cb = $this->callback; + $this->promise->resolve($cb()); + } catch (Exception $e) { + $this->promise->reject($e); + } catch (Throwable $e) { + $this->promise->reject($e); + } + } +} diff --git a/vendor/webonyx/graphql-php/src/Error/ClientAware.php b/vendor/webonyx/graphql-php/src/Error/ClientAware.php new file mode 100644 index 0000000..adccb0c --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Error/ClientAware.php @@ -0,0 +1,36 @@ +nodes = $nodes; + $this->source = $source; + $this->positions = $positions; + $this->path = $path; + $this->extensions = $extensions ?: ( + $previous && $previous instanceof self + ? $previous->extensions + : [] + ); + + if ($previous instanceof ClientAware) { + $this->isClientSafe = $previous->isClientSafe(); + $this->category = $previous->getCategory() ?: self::CATEGORY_INTERNAL; + } elseif ($previous) { + $this->isClientSafe = false; + $this->category = self::CATEGORY_INTERNAL; + } else { + $this->isClientSafe = true; + $this->category = self::CATEGORY_GRAPHQL; + } + } + + /** + * Given an arbitrary Error, presumably thrown while attempting to execute a + * GraphQL operation, produce a new GraphQLError aware of the location in the + * document responsible for the original Error. + * + * @param mixed $error + * @param Node[]|null $nodes + * @param mixed[]|null $path + * + * @return Error + */ + public static function createLocatedError($error, $nodes = null, $path = null) + { + if ($error instanceof self) { + if ($error->path && $error->nodes) { + return $error; + } + + $nodes = $nodes ?: $error->nodes; + $path = $path ?: $error->path; + } + + $source = $positions = $originalError = null; + $extensions = []; + + if ($error instanceof self) { + $message = $error->getMessage(); + $originalError = $error; + $nodes = $error->nodes ?: $nodes; + $source = $error->source; + $positions = $error->positions; + $extensions = $error->extensions; + } elseif ($error instanceof Exception || $error instanceof Throwable) { + $message = $error->getMessage(); + $originalError = $error; + } else { + $message = (string) $error; + } + + return new static( + $message ?: 'An unknown error occurred.', + $nodes, + $source, + $positions, + $path, + $originalError, + $extensions + ); + } + + /** + * @return mixed[] + */ + public static function formatError(Error $error) + { + return $error->toSerializableArray(); + } + + /** + * @inheritdoc + */ + public function isClientSafe() + { + return $this->isClientSafe; + } + + /** + * @inheritdoc + */ + public function getCategory() + { + return $this->category; + } + + /** + * @return Source|null + */ + public function getSource() + { + if ($this->source === null) { + if (! empty($this->nodes[0]) && ! empty($this->nodes[0]->loc)) { + $this->source = $this->nodes[0]->loc->source; + } + } + + return $this->source; + } + + /** + * @return int[] + */ + public function getPositions() + { + if ($this->positions === null && ! empty($this->nodes)) { + $positions = array_map( + static function ($node) { + return isset($node->loc) ? $node->loc->start : null; + }, + $this->nodes + ); + + $positions = array_filter( + $positions, + static function ($p) { + return $p !== null; + } + ); + + $this->positions = array_values($positions); + } + + return $this->positions; + } + + /** + * An array of locations within the source GraphQL document which correspond to this error. + * + * Each entry has information about `line` and `column` within source GraphQL document: + * $location->line; + * $location->column; + * + * Errors during validation often contain multiple locations, for example to + * point out to field mentioned in multiple fragments. Errors during execution include a + * single location, the field which produced the error. + * + * @return SourceLocation[] + * + * @api + */ + public function getLocations() + { + if ($this->locations === null) { + $positions = $this->getPositions(); + $source = $this->getSource(); + $nodes = $this->nodes; + + if ($positions && $source) { + $this->locations = array_map( + static function ($pos) use ($source) { + return $source->getLocation($pos); + }, + $positions + ); + } elseif ($nodes) { + $locations = array_filter( + array_map( + static function ($node) { + if ($node->loc && $node->loc->source) { + return $node->loc->source->getLocation($node->loc->start); + } + }, + $nodes + ) + ); + $this->locations = array_values($locations); + } else { + $this->locations = []; + } + } + + return $this->locations; + } + + /** + * @return Node[]|null + */ + public function getNodes() + { + return $this->nodes; + } + + /** + * Returns an array describing the path from the root value to the field which produced this error. + * Only included for execution errors. + * + * @return mixed[]|null + * + * @api + */ + public function getPath() + { + return $this->path; + } + + /** + * @return mixed[] + */ + public function getExtensions() + { + return $this->extensions; + } + + /** + * Returns array representation of error suitable for serialization + * + * @deprecated Use FormattedError::createFromException() instead + * + * @return mixed[] + */ + public function toSerializableArray() + { + $arr = [ + 'message' => $this->getMessage(), + ]; + + $locations = Utils::map( + $this->getLocations(), + static function (SourceLocation $loc) { + return $loc->toSerializableArray(); + } + ); + + if (! empty($locations)) { + $arr['locations'] = $locations; + } + if (! empty($this->path)) { + $arr['path'] = $this->path; + } + if (! empty($this->extensions)) { + $arr['extensions'] = $this->extensions; + } + + return $arr; + } + + /** + * Specify data which should be serialized to JSON + * + * @link http://php.net/manual/en/jsonserializable.jsonserialize.php + * + * @return mixed data which can be serialized by json_encode, + * which is a value of any type other than a resource. + */ + public function jsonSerialize() + { + return $this->toSerializableArray(); + } + + /** + * @return string + */ + public function __toString() + { + return FormattedError::printError($this); + } +} diff --git a/vendor/webonyx/graphql-php/src/Error/FormattedError.php b/vendor/webonyx/graphql-php/src/Error/FormattedError.php new file mode 100644 index 0000000..799ee74 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Error/FormattedError.php @@ -0,0 +1,440 @@ +nodes) { + /** @var Node $node */ + foreach ($error->nodes as $node) { + if (! $node->loc) { + continue; + } + + if ($node->loc->source === null) { + continue; + } + + $printedLocations[] = self::highlightSourceAtLocation( + $node->loc->source, + $node->loc->source->getLocation($node->loc->start) + ); + } + } elseif ($error->getSource() && $error->getLocations()) { + $source = $error->getSource(); + foreach ($error->getLocations() as $location) { + $printedLocations[] = self::highlightSourceAtLocation($source, $location); + } + } + + return ! $printedLocations + ? $error->getMessage() + : implode("\n\n", array_merge([$error->getMessage()], $printedLocations)) . "\n"; + } + + /** + * Render a helpful description of the location of the error in the GraphQL + * Source document. + * + * @return string + */ + private static function highlightSourceAtLocation(Source $source, SourceLocation $location) + { + $line = $location->line; + $lineOffset = $source->locationOffset->line - 1; + $columnOffset = self::getColumnOffset($source, $location); + $contextLine = $line + $lineOffset; + $contextColumn = $location->column + $columnOffset; + $prevLineNum = (string) ($contextLine - 1); + $lineNum = (string) $contextLine; + $nextLineNum = (string) ($contextLine + 1); + $padLen = strlen($nextLineNum); + $lines = preg_split('/\r\n|[\n\r]/', $source->body); + + $lines[0] = self::whitespace($source->locationOffset->column - 1) . $lines[0]; + + $outputLines = [ + sprintf('%s (%s:%s)', $source->name, $contextLine, $contextColumn), + $line >= 2 ? (self::lpad($padLen, $prevLineNum) . ': ' . $lines[$line - 2]) : null, + self::lpad($padLen, $lineNum) . ': ' . $lines[$line - 1], + self::whitespace(2 + $padLen + $contextColumn - 1) . '^', + $line < count($lines) ? self::lpad($padLen, $nextLineNum) . ': ' . $lines[$line] : null, + ]; + + return implode("\n", array_filter($outputLines)); + } + + /** + * @return int + */ + private static function getColumnOffset(Source $source, SourceLocation $location) + { + return $location->line === 1 ? $source->locationOffset->column - 1 : 0; + } + + /** + * @param int $len + * + * @return string + */ + private static function whitespace($len) + { + return str_repeat(' ', $len); + } + + /** + * @param int $len + * + * @return string + */ + private static function lpad($len, $str) + { + return self::whitespace($len - mb_strlen($str)) . $str; + } + + /** + * Standard GraphQL error formatter. Converts any exception to array + * conforming to GraphQL spec. + * + * This method only exposes exception message when exception implements ClientAware interface + * (or when debug flags are passed). + * + * For a list of available debug flags see GraphQL\Error\Debug constants. + * + * @param Throwable $e + * @param bool|int $debug + * @param string $internalErrorMessage + * + * @return mixed[] + * + * @throws Throwable + * + * @api + */ + public static function createFromException($e, $debug = false, $internalErrorMessage = null) + { + Utils::invariant( + $e instanceof Exception || $e instanceof Throwable, + 'Expected exception, got %s', + Utils::getVariableType($e) + ); + + $internalErrorMessage = $internalErrorMessage ?: self::$internalErrorMessage; + + if ($e instanceof ClientAware) { + $formattedError = [ + 'message' => $e->isClientSafe() ? $e->getMessage() : $internalErrorMessage, + 'extensions' => [ + 'category' => $e->getCategory(), + ], + ]; + } else { + $formattedError = [ + 'message' => $internalErrorMessage, + 'extensions' => [ + 'category' => Error::CATEGORY_INTERNAL, + ], + ]; + } + + if ($e instanceof Error) { + $locations = Utils::map( + $e->getLocations(), + static function (SourceLocation $loc) { + return $loc->toSerializableArray(); + } + ); + if (! empty($locations)) { + $formattedError['locations'] = $locations; + } + if (! empty($e->path)) { + $formattedError['path'] = $e->path; + } + if (! empty($e->getExtensions())) { + $formattedError['extensions'] = $e->getExtensions() + $formattedError['extensions']; + } + } + + if ($debug) { + $formattedError = self::addDebugEntries($formattedError, $e, $debug); + } + + return $formattedError; + } + + /** + * Decorates spec-compliant $formattedError with debug entries according to $debug flags + * (see GraphQL\Error\Debug for available flags) + * + * @param mixed[] $formattedError + * @param Throwable $e + * @param bool|int $debug + * + * @return mixed[] + * + * @throws Throwable + */ + public static function addDebugEntries(array $formattedError, $e, $debug) + { + if (! $debug) { + return $formattedError; + } + + Utils::invariant( + $e instanceof Exception || $e instanceof Throwable, + 'Expected exception, got %s', + Utils::getVariableType($e) + ); + + $debug = (int) $debug; + + if ($debug & Debug::RETHROW_INTERNAL_EXCEPTIONS) { + if (! $e instanceof Error) { + throw $e; + } + + if ($e->getPrevious()) { + throw $e->getPrevious(); + } + } + + $isUnsafe = ! $e instanceof ClientAware || ! $e->isClientSafe(); + + if (($debug & Debug::RETHROW_UNSAFE_EXCEPTIONS) && $isUnsafe) { + if ($e->getPrevious()) { + throw $e->getPrevious(); + } + } + + if (($debug & Debug::INCLUDE_DEBUG_MESSAGE) && $isUnsafe) { + // Displaying debugMessage as a first entry: + $formattedError = ['debugMessage' => $e->getMessage()] + $formattedError; + } + + if ($debug & Debug::INCLUDE_TRACE) { + if ($e instanceof ErrorException || $e instanceof \Error) { + $formattedError += [ + 'file' => $e->getFile(), + 'line' => $e->getLine(), + ]; + } + + $isTrivial = $e instanceof Error && ! $e->getPrevious(); + + if (! $isTrivial) { + $debugging = $e->getPrevious() ?: $e; + $formattedError['trace'] = static::toSafeTrace($debugging); + } + } + + return $formattedError; + } + + /** + * Prepares final error formatter taking in account $debug flags. + * If initial formatter is not set, FormattedError::createFromException is used + * + * @param bool|int $debug + * + * @return callable|callable + */ + public static function prepareFormatter(?callable $formatter = null, $debug) + { + $formatter = $formatter ?: static function ($e) { + return FormattedError::createFromException($e); + }; + if ($debug) { + $formatter = static function ($e) use ($formatter, $debug) { + return FormattedError::addDebugEntries($formatter($e), $e, $debug); + }; + } + + return $formatter; + } + + /** + * Returns error trace as serializable array + * + * @param Throwable $error + * + * @return mixed[] + * + * @api + */ + public static function toSafeTrace($error) + { + $trace = $error->getTrace(); + + if (isset($trace[0]['function']) && isset($trace[0]['class']) && + // Remove invariant entries as they don't provide much value: + ($trace[0]['class'] . '::' . $trace[0]['function'] === 'GraphQL\Utils\Utils::invariant')) { + array_shift($trace); + } elseif (! isset($trace[0]['file'])) { + // Remove root call as it's likely error handler trace: + array_shift($trace); + } + + return array_map( + static function ($err) { + $safeErr = array_intersect_key($err, ['file' => true, 'line' => true]); + + if (isset($err['function'])) { + $func = $err['function']; + $args = ! empty($err['args']) ? array_map([self::class, 'printVar'], $err['args']) : []; + $funcStr = $func . '(' . implode(', ', $args) . ')'; + + if (isset($err['class'])) { + $safeErr['call'] = $err['class'] . '::' . $funcStr; + } else { + $safeErr['function'] = $funcStr; + } + } + + return $safeErr; + }, + $trace + ); + } + + /** + * @param mixed $var + * + * @return string + */ + public static function printVar($var) + { + if ($var instanceof Type) { + // FIXME: Replace with schema printer call + if ($var instanceof WrappingType) { + $var = $var->getWrappedType(true); + } + + return 'GraphQLType: ' . $var->name; + } + + if (is_object($var)) { + return 'instance of ' . get_class($var) . ($var instanceof Countable ? '(' . count($var) . ')' : ''); + } + if (is_array($var)) { + return 'array(' . count($var) . ')'; + } + if ($var === '') { + return '(empty string)'; + } + if (is_string($var)) { + return "'" . addcslashes($var, "'") . "'"; + } + if (is_bool($var)) { + return $var ? 'true' : 'false'; + } + if (is_scalar($var)) { + return $var; + } + if ($var === null) { + return 'null'; + } + + return gettype($var); + } + + /** + * @deprecated as of v0.8.0 + * + * @param string $error + * @param SourceLocation[] $locations + * + * @return mixed[] + */ + public static function create($error, array $locations = []) + { + $formatted = ['message' => $error]; + + if (! empty($locations)) { + $formatted['locations'] = array_map( + static function ($loc) { + return $loc->toArray(); + }, + $locations + ); + } + + return $formatted; + } + + /** + * @deprecated as of v0.10.0, use general purpose method createFromException() instead + * + * @return mixed[] + */ + public static function createFromPHPError(ErrorException $e) + { + return [ + 'message' => $e->getMessage(), + 'severity' => $e->getSeverity(), + 'trace' => self::toSafeTrace($e), + ]; + } +} diff --git a/vendor/webonyx/graphql-php/src/Error/InvariantViolation.php b/vendor/webonyx/graphql-php/src/Error/InvariantViolation.php new file mode 100644 index 0000000..24d6dbc --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Error/InvariantViolation.php @@ -0,0 +1,16 @@ + 0 && ! isset(self::$warned[$warningId])) { + self::$warned[$warningId] = true; + trigger_error($errorMessage, $messageLevel ?: E_USER_WARNING); + } + } + + public static function warn($errorMessage, $warningId, $messageLevel = null) + { + if (self::$warningHandler) { + $fn = self::$warningHandler; + $fn($errorMessage, $warningId); + } elseif ((self::$enableWarnings & $warningId) > 0) { + trigger_error($errorMessage, $messageLevel ?: E_USER_WARNING); + } + } +} diff --git a/vendor/webonyx/graphql-php/src/Executor/ExecutionContext.php b/vendor/webonyx/graphql-php/src/Executor/ExecutionContext.php new file mode 100644 index 0000000..3de1a2e --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Executor/ExecutionContext.php @@ -0,0 +1,78 @@ +schema = $schema; + $this->fragments = $fragments; + $this->rootValue = $root; + $this->contextValue = $contextValue; + $this->operation = $operation; + $this->variableValues = $variables; + $this->errors = $errors ?: []; + $this->fieldResolver = $fieldResolver; + $this->promises = $promiseAdapter; + } + + public function addError(Error $error) + { + $this->errors[] = $error; + + return $this; + } +} diff --git a/vendor/webonyx/graphql-php/src/Executor/ExecutionResult.php b/vendor/webonyx/graphql-php/src/Executor/ExecutionResult.php new file mode 100644 index 0000000..db16dd3 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Executor/ExecutionResult.php @@ -0,0 +1,162 @@ +getPrevious() would + * contain original exception. + * + * @api + * @var Error[] + */ + public $errors; + + /** + * User-defined serializable array of extensions included in serialized result. + * Conforms to + * + * @api + * @var mixed[] + */ + public $extensions; + + /** @var callable */ + private $errorFormatter; + + /** @var callable */ + private $errorsHandler; + + /** + * @param mixed[] $data + * @param Error[] $errors + * @param mixed[] $extensions + */ + public function __construct($data = null, array $errors = [], array $extensions = []) + { + $this->data = $data; + $this->errors = $errors; + $this->extensions = $extensions; + } + + /** + * Define custom error formatting (must conform to http://facebook.github.io/graphql/#sec-Errors) + * + * Expected signature is: function (GraphQL\Error\Error $error): array + * + * Default formatter is "GraphQL\Error\FormattedError::createFromException" + * + * Expected returned value must be an array: + * array( + * 'message' => 'errorMessage', + * // ... other keys + * ); + * + * @return self + * + * @api + */ + public function setErrorFormatter(callable $errorFormatter) + { + $this->errorFormatter = $errorFormatter; + + return $this; + } + + /** + * Define custom logic for error handling (filtering, logging, etc). + * + * Expected handler signature is: function (array $errors, callable $formatter): array + * + * Default handler is: + * function (array $errors, callable $formatter) { + * return array_map($formatter, $errors); + * } + * + * @return self + * + * @api + */ + public function setErrorsHandler(callable $handler) + { + $this->errorsHandler = $handler; + + return $this; + } + + /** + * @return mixed[] + */ + public function jsonSerialize() + { + return $this->toArray(); + } + + /** + * Converts GraphQL query result to spec-compliant serializable array using provided + * errors handler and formatter. + * + * If debug argument is passed, output of error formatter is enriched which debugging information + * ("debugMessage", "trace" keys depending on flags). + * + * $debug argument must be either bool (only adds "debugMessage" to result) or sum of flags from + * GraphQL\Error\Debug + * + * @param bool|int $debug + * + * @return mixed[] + * + * @api + */ + public function toArray($debug = false) + { + $result = []; + + if (! empty($this->errors)) { + $errorsHandler = $this->errorsHandler ?: static function (array $errors, callable $formatter) { + return array_map($formatter, $errors); + }; + + $result['errors'] = $errorsHandler( + $this->errors, + FormattedError::prepareFormatter($this->errorFormatter, $debug) + ); + } + + if ($this->data !== null) { + $result['data'] = $this->data; + } + + if (! empty($this->extensions)) { + $result['extensions'] = $this->extensions; + } + + return $result; + } +} diff --git a/vendor/webonyx/graphql-php/src/Executor/Executor.php b/vendor/webonyx/graphql-php/src/Executor/Executor.php new file mode 100644 index 0000000..30ccad4 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Executor/Executor.php @@ -0,0 +1,187 @@ +errors`. + * + * @param mixed|null $rootValue + * @param mixed|null $contextValue + * @param mixed[]|ArrayAccess|null $variableValues + * @param string|null $operationName + * + * @return ExecutionResult|Promise + * + * @api + */ + public static function execute( + Schema $schema, + DocumentNode $documentNode, + $rootValue = null, + $contextValue = null, + $variableValues = null, + $operationName = null, + ?callable $fieldResolver = null + ) { + // TODO: deprecate (just always use SyncAdapter here) and have `promiseToExecute()` for other cases + + $promiseAdapter = static::getPromiseAdapter(); + + $result = static::promiseToExecute( + $promiseAdapter, + $schema, + $documentNode, + $rootValue, + $contextValue, + $variableValues, + $operationName, + $fieldResolver + ); + + if ($promiseAdapter instanceof SyncPromiseAdapter) { + $result = $promiseAdapter->wait($result); + } + + return $result; + } + + /** + * Same as execute(), but requires promise adapter and returns a promise which is always + * fulfilled with an instance of ExecutionResult and never rejected. + * + * Useful for async PHP platforms. + * + * @param mixed|null $rootValue + * @param mixed|null $contextValue + * @param mixed[]|null $variableValues + * @param string|null $operationName + * + * @return Promise + * + * @api + */ + public static function promiseToExecute( + PromiseAdapter $promiseAdapter, + Schema $schema, + DocumentNode $documentNode, + $rootValue = null, + $contextValue = null, + $variableValues = null, + $operationName = null, + ?callable $fieldResolver = null + ) { + $factory = self::$implementationFactory; + + /** @var ExecutorImplementation $executor */ + $executor = $factory( + $promiseAdapter, + $schema, + $documentNode, + $rootValue, + $contextValue, + $variableValues, + $operationName, + $fieldResolver ?: self::$defaultFieldResolver + ); + + return $executor->doExecute(); + } + + /** + * If a resolve function is not given, then a default resolve behavior is used + * which takes the property of the source object of the same name as the field + * and returns it as the result, or if it's a function, returns the result + * of calling that function while passing along args and context. + * + * @param mixed $source + * @param mixed[] $args + * @param mixed|null $context + * + * @return mixed|null + */ + public static function defaultFieldResolver($source, $args, $context, ResolveInfo $info) + { + $fieldName = $info->fieldName; + $property = null; + + if (is_array($source) || $source instanceof ArrayAccess) { + if (isset($source[$fieldName])) { + $property = $source[$fieldName]; + } + } elseif (is_object($source)) { + if (isset($source->{$fieldName})) { + $property = $source->{$fieldName}; + } + } + + return $property instanceof Closure ? $property($source, $args, $context, $info) : $property; + } +} diff --git a/vendor/webonyx/graphql-php/src/Executor/ExecutorImplementation.php b/vendor/webonyx/graphql-php/src/Executor/ExecutorImplementation.php new file mode 100644 index 0000000..46cb2b7 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Executor/ExecutorImplementation.php @@ -0,0 +1,15 @@ +adoptedPromise; + + return new Promise($adoptedPromise->then($onFulfilled, $onRejected), $this); + } + + /** + * @inheritdoc + */ + public function create(callable $resolver) + { + $promise = new ReactPromise($resolver); + + return new Promise($promise, $this); + } + + /** + * @inheritdoc + */ + public function createFulfilled($value = null) + { + $promise = resolve($value); + + return new Promise($promise, $this); + } + + /** + * @inheritdoc + */ + public function createRejected($reason) + { + $promise = reject($reason); + + return new Promise($promise, $this); + } + + /** + * @inheritdoc + */ + public function all(array $promisesOrValues) + { + // TODO: rework with generators when PHP minimum required version is changed to 5.5+ + $promisesOrValues = Utils::map( + $promisesOrValues, + static function ($item) { + return $item instanceof Promise ? $item->adoptedPromise : $item; + } + ); + + $promise = all($promisesOrValues)->then(static function ($values) use ($promisesOrValues) { + $orderedResults = []; + + foreach ($promisesOrValues as $key => $value) { + $orderedResults[$key] = $values[$key]; + } + + return $orderedResults; + }); + + return new Promise($promise, $this); + } +} diff --git a/vendor/webonyx/graphql-php/src/Executor/Promise/Adapter/SyncPromise.php b/vendor/webonyx/graphql-php/src/Executor/Promise/Adapter/SyncPromise.php new file mode 100644 index 0000000..26aecd6 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Executor/Promise/Adapter/SyncPromise.php @@ -0,0 +1,170 @@ +isEmpty()) { + $task = $q->dequeue(); + $task(); + } + } + + public function resolve($value) + { + switch ($this->state) { + case self::PENDING: + if ($value === $this) { + throw new Exception('Cannot resolve promise with self'); + } + if (is_object($value) && method_exists($value, 'then')) { + $value->then( + function ($resolvedValue) { + $this->resolve($resolvedValue); + }, + function ($reason) { + $this->reject($reason); + } + ); + + return $this; + } + + $this->state = self::FULFILLED; + $this->result = $value; + $this->enqueueWaitingPromises(); + break; + case self::FULFILLED: + if ($this->result !== $value) { + throw new Exception('Cannot change value of fulfilled promise'); + } + break; + case self::REJECTED: + throw new Exception('Cannot resolve rejected promise'); + } + + return $this; + } + + public function reject($reason) + { + if (! $reason instanceof Exception && ! $reason instanceof Throwable) { + throw new Exception('SyncPromise::reject() has to be called with an instance of \Throwable'); + } + + switch ($this->state) { + case self::PENDING: + $this->state = self::REJECTED; + $this->result = $reason; + $this->enqueueWaitingPromises(); + break; + case self::REJECTED: + if ($reason !== $this->result) { + throw new Exception('Cannot change rejection reason'); + } + break; + case self::FULFILLED: + throw new Exception('Cannot reject fulfilled promise'); + } + + return $this; + } + + private function enqueueWaitingPromises() + { + Utils::invariant( + $this->state !== self::PENDING, + 'Cannot enqueue derived promises when parent is still pending' + ); + + foreach ($this->waiting as $descriptor) { + self::getQueue()->enqueue(function () use ($descriptor) { + /** @var $promise self */ + [$promise, $onFulfilled, $onRejected] = $descriptor; + + if ($this->state === self::FULFILLED) { + try { + $promise->resolve($onFulfilled === null ? $this->result : $onFulfilled($this->result)); + } catch (Exception $e) { + $promise->reject($e); + } catch (Throwable $e) { + $promise->reject($e); + } + } elseif ($this->state === self::REJECTED) { + try { + if ($onRejected === null) { + $promise->reject($this->result); + } else { + $promise->resolve($onRejected($this->result)); + } + } catch (Exception $e) { + $promise->reject($e); + } catch (Throwable $e) { + $promise->reject($e); + } + } + }); + } + $this->waiting = []; + } + + public static function getQueue() + { + return self::$queue ?: self::$queue = new SplQueue(); + } + + public function then(?callable $onFulfilled = null, ?callable $onRejected = null) + { + if ($this->state === self::REJECTED && ! $onRejected) { + return $this; + } + if ($this->state === self::FULFILLED && ! $onFulfilled) { + return $this; + } + $tmp = new self(); + $this->waiting[] = [$tmp, $onFulfilled, $onRejected]; + + if ($this->state !== self::PENDING) { + $this->enqueueWaitingPromises(); + } + + return $tmp; + } +} diff --git a/vendor/webonyx/graphql-php/src/Executor/Promise/Adapter/SyncPromiseAdapter.php b/vendor/webonyx/graphql-php/src/Executor/Promise/Adapter/SyncPromiseAdapter.php new file mode 100644 index 0000000..e5900a9 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Executor/Promise/Adapter/SyncPromiseAdapter.php @@ -0,0 +1,185 @@ +promise, $this); + } + + /** + * @inheritdoc + */ + public function then(Promise $promise, ?callable $onFulfilled = null, ?callable $onRejected = null) + { + /** @var SyncPromise $adoptedPromise */ + $adoptedPromise = $promise->adoptedPromise; + + return new Promise($adoptedPromise->then($onFulfilled, $onRejected), $this); + } + + /** + * @inheritdoc + */ + public function create(callable $resolver) + { + $promise = new SyncPromise(); + + try { + $resolver( + [ + $promise, + 'resolve', + ], + [ + $promise, + 'reject', + ] + ); + } catch (Exception $e) { + $promise->reject($e); + } catch (Throwable $e) { + $promise->reject($e); + } + + return new Promise($promise, $this); + } + + /** + * @inheritdoc + */ + public function createFulfilled($value = null) + { + $promise = new SyncPromise(); + + return new Promise($promise->resolve($value), $this); + } + + /** + * @inheritdoc + */ + public function createRejected($reason) + { + $promise = new SyncPromise(); + + return new Promise($promise->reject($reason), $this); + } + + /** + * @inheritdoc + */ + public function all(array $promisesOrValues) + { + $all = new SyncPromise(); + + $total = count($promisesOrValues); + $count = 0; + $result = []; + + foreach ($promisesOrValues as $index => $promiseOrValue) { + if ($promiseOrValue instanceof Promise) { + $result[$index] = null; + $promiseOrValue->then( + static function ($value) use ($index, &$count, $total, &$result, $all) { + $result[$index] = $value; + $count++; + if ($count < $total) { + return; + } + + $all->resolve($result); + }, + [$all, 'reject'] + ); + } else { + $result[$index] = $promiseOrValue; + $count++; + } + } + if ($count === $total) { + $all->resolve($result); + } + + return new Promise($all, $this); + } + + /** + * Synchronously wait when promise completes + * + * @return ExecutionResult + */ + public function wait(Promise $promise) + { + $this->beforeWait($promise); + $dfdQueue = Deferred::getQueue(); + $promiseQueue = SyncPromise::getQueue(); + + while ($promise->adoptedPromise->state === SyncPromise::PENDING && + ! ($dfdQueue->isEmpty() && $promiseQueue->isEmpty()) + ) { + Deferred::runQueue(); + SyncPromise::runQueue(); + $this->onWait($promise); + } + + /** @var SyncPromise $syncPromise */ + $syncPromise = $promise->adoptedPromise; + + if ($syncPromise->state === SyncPromise::FULFILLED) { + return $syncPromise->result; + } + + if ($syncPromise->state === SyncPromise::REJECTED) { + throw $syncPromise->result; + } + + throw new InvariantViolation('Could not resolve promise'); + } + + /** + * Execute just before starting to run promise completion + */ + protected function beforeWait(Promise $promise) + { + } + + /** + * Execute while running promise completion + */ + protected function onWait(Promise $promise) + { + } +} diff --git a/vendor/webonyx/graphql-php/src/Executor/Promise/Promise.php b/vendor/webonyx/graphql-php/src/Executor/Promise/Promise.php new file mode 100644 index 0000000..5823d14 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Executor/Promise/Promise.php @@ -0,0 +1,40 @@ +adapter = $adapter; + $this->adoptedPromise = $adoptedPromise; + } + + /** + * @return Promise + */ + public function then(?callable $onFulfilled = null, ?callable $onRejected = null) + { + return $this->adapter->then($this, $onFulfilled, $onRejected); + } +} diff --git a/vendor/webonyx/graphql-php/src/Executor/Promise/PromiseAdapter.php b/vendor/webonyx/graphql-php/src/Executor/Promise/PromiseAdapter.php new file mode 100644 index 0000000..c3d4098 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Executor/Promise/PromiseAdapter.php @@ -0,0 +1,92 @@ +exeContext = $context; + $this->subFieldCache = new SplObjectStorage(); + } + + public static function create( + PromiseAdapter $promiseAdapter, + Schema $schema, + DocumentNode $documentNode, + $rootValue, + $contextValue, + $variableValues, + ?string $operationName, + callable $fieldResolver + ) { + $exeContext = self::buildExecutionContext( + $schema, + $documentNode, + $rootValue, + $contextValue, + $variableValues, + $operationName, + $fieldResolver, + $promiseAdapter + ); + + if (is_array($exeContext)) { + return new class($promiseAdapter->createFulfilled(new ExecutionResult(null, $exeContext))) implements ExecutorImplementation + { + /** @var Promise */ + private $result; + + public function __construct(Promise $result) + { + $this->result = $result; + } + + public function doExecute() : Promise + { + return $this->result; + } + }; + } + + return new self($exeContext); + } + + /** + * Constructs an ExecutionContext object from the arguments passed to + * execute, which we will pass throughout the other execution methods. + * + * @param mixed $rootValue + * @param mixed $contextValue + * @param mixed[]|Traversable $rawVariableValues + * @param string|null $operationName + * + * @return ExecutionContext|Error[] + */ + private static function buildExecutionContext( + Schema $schema, + DocumentNode $documentNode, + $rootValue, + $contextValue, + $rawVariableValues, + $operationName = null, + ?callable $fieldResolver = null, + ?PromiseAdapter $promiseAdapter = null + ) { + $errors = []; + $fragments = []; + /** @var OperationDefinitionNode $operation */ + $operation = null; + $hasMultipleAssumedOperations = false; + foreach ($documentNode->definitions as $definition) { + switch ($definition->kind) { + case NodeKind::OPERATION_DEFINITION: + if (! $operationName && $operation) { + $hasMultipleAssumedOperations = true; + } + if (! $operationName || + (isset($definition->name) && $definition->name->value === $operationName)) { + $operation = $definition; + } + break; + case NodeKind::FRAGMENT_DEFINITION: + $fragments[$definition->name->value] = $definition; + break; + } + } + if ($operation === null) { + if ($operationName) { + $errors[] = new Error(sprintf('Unknown operation named "%s".', $operationName)); + } else { + $errors[] = new Error('Must provide an operation.'); + } + } elseif ($hasMultipleAssumedOperations) { + $errors[] = new Error( + 'Must provide operation name if query contains multiple operations.' + ); + } + $variableValues = null; + if ($operation !== null) { + [$coercionErrors, $coercedVariableValues] = Values::getVariableValues( + $schema, + $operation->variableDefinitions ?: [], + $rawVariableValues ?: [] + ); + if (empty($coercionErrors)) { + $variableValues = $coercedVariableValues; + } else { + $errors = array_merge($errors, $coercionErrors); + } + } + if (! empty($errors)) { + return $errors; + } + Utils::invariant($operation, 'Has operation if no errors.'); + Utils::invariant($variableValues !== null, 'Has variables if no errors.'); + + return new ExecutionContext( + $schema, + $fragments, + $rootValue, + $contextValue, + $operation, + $variableValues, + $errors, + $fieldResolver, + $promiseAdapter + ); + } + + public function doExecute() : Promise + { + // Return a Promise that will eventually resolve to the data described by + // The "Response" section of the GraphQL specification. + // + // If errors are encountered while executing a GraphQL field, only that + // field and its descendants will be omitted, and sibling fields will still + // be executed. An execution which encounters errors will still result in a + // resolved Promise. + $data = $this->executeOperation($this->exeContext->operation, $this->exeContext->rootValue); + $result = $this->buildResponse($data); + + // Note: we deviate here from the reference implementation a bit by always returning promise + // But for the "sync" case it is always fulfilled + return $this->isPromise($result) + ? $result + : $this->exeContext->promises->createFulfilled($result); + } + + /** + * @param mixed|Promise|null $data + * + * @return ExecutionResult|Promise + */ + private function buildResponse($data) + { + if ($this->isPromise($data)) { + return $data->then(function ($resolved) { + return $this->buildResponse($resolved); + }); + } + if ($data !== null) { + $data = (array) $data; + } + + return new ExecutionResult($data, $this->exeContext->errors); + } + + /** + * Implements the "Evaluating operations" section of the spec. + * + * @param mixed[] $rootValue + * + * @return Promise|stdClass|mixed[] + */ + private function executeOperation(OperationDefinitionNode $operation, $rootValue) + { + $type = $this->getOperationRootType($this->exeContext->schema, $operation); + $fields = $this->collectFields($type, $operation->selectionSet, new ArrayObject(), new ArrayObject()); + $path = []; + // Errors from sub-fields of a NonNull type may propagate to the top level, + // at which point we still log the error and null the parent field, which + // in this case is the entire response. + // + // Similar to completeValueCatchingError. + try { + $result = $operation->operation === 'mutation' ? + $this->executeFieldsSerially($type, $rootValue, $path, $fields) : + $this->executeFields($type, $rootValue, $path, $fields); + if ($this->isPromise($result)) { + return $result->then( + null, + function ($error) { + $this->exeContext->addError($error); + + return $this->exeContext->promises->createFulfilled(null); + } + ); + } + + return $result; + } catch (Error $error) { + $this->exeContext->addError($error); + + return null; + } + } + + /** + * Extracts the root type of the operation from the schema. + * + * @return ObjectType + * + * @throws Error + */ + private function getOperationRootType(Schema $schema, OperationDefinitionNode $operation) + { + switch ($operation->operation) { + case 'query': + $queryType = $schema->getQueryType(); + if (! $queryType) { + throw new Error( + 'Schema does not define the required query root type.', + [$operation] + ); + } + + return $queryType; + case 'mutation': + $mutationType = $schema->getMutationType(); + if (! $mutationType) { + throw new Error( + 'Schema is not configured for mutations.', + [$operation] + ); + } + + return $mutationType; + case 'subscription': + $subscriptionType = $schema->getSubscriptionType(); + if (! $subscriptionType) { + throw new Error( + 'Schema is not configured for subscriptions.', + [$operation] + ); + } + + return $subscriptionType; + default: + throw new Error( + 'Can only execute queries, mutations and subscriptions.', + [$operation] + ); + } + } + + /** + * Given a selectionSet, adds all of the fields in that selection to + * the passed in map of fields, and returns it at the end. + * + * CollectFields requires the "runtime type" of an object. For a field which + * returns an Interface or Union type, the "runtime type" will be the actual + * Object type returned by that field. + * + * @param ArrayObject $fields + * @param ArrayObject $visitedFragmentNames + * + * @return ArrayObject + */ + private function collectFields( + ObjectType $runtimeType, + SelectionSetNode $selectionSet, + $fields, + $visitedFragmentNames + ) { + $exeContext = $this->exeContext; + foreach ($selectionSet->selections as $selection) { + switch ($selection->kind) { + case NodeKind::FIELD: + if (! $this->shouldIncludeNode($selection)) { + break; + } + $name = self::getFieldEntryKey($selection); + if (! isset($fields[$name])) { + $fields[$name] = new ArrayObject(); + } + $fields[$name][] = $selection; + break; + case NodeKind::INLINE_FRAGMENT: + if (! $this->shouldIncludeNode($selection) || + ! $this->doesFragmentConditionMatch($selection, $runtimeType) + ) { + break; + } + $this->collectFields( + $runtimeType, + $selection->selectionSet, + $fields, + $visitedFragmentNames + ); + break; + case NodeKind::FRAGMENT_SPREAD: + $fragName = $selection->name->value; + if (! empty($visitedFragmentNames[$fragName]) || ! $this->shouldIncludeNode($selection)) { + break; + } + $visitedFragmentNames[$fragName] = true; + /** @var FragmentDefinitionNode|null $fragment */ + $fragment = $exeContext->fragments[$fragName] ?? null; + if (! $fragment || ! $this->doesFragmentConditionMatch($fragment, $runtimeType)) { + break; + } + $this->collectFields( + $runtimeType, + $fragment->selectionSet, + $fields, + $visitedFragmentNames + ); + break; + } + } + + return $fields; + } + + /** + * Determines if a field should be included based on the @include and @skip + * directives, where @skip has higher precedence than @include. + * + * @param FragmentSpreadNode|FieldNode|InlineFragmentNode $node + * + * @return bool + */ + private function shouldIncludeNode($node) + { + $variableValues = $this->exeContext->variableValues; + $skipDirective = Directive::skipDirective(); + $skip = Values::getDirectiveValues( + $skipDirective, + $node, + $variableValues + ); + if (isset($skip['if']) && $skip['if'] === true) { + return false; + } + $includeDirective = Directive::includeDirective(); + $include = Values::getDirectiveValues( + $includeDirective, + $node, + $variableValues + ); + + return ! isset($include['if']) || $include['if'] !== false; + } + + /** + * Implements the logic to compute the key of a given fields entry + * + * @return string + */ + private static function getFieldEntryKey(FieldNode $node) + { + return $node->alias ? $node->alias->value : $node->name->value; + } + + /** + * Determines if a fragment is applicable to the given type. + * + * @param FragmentDefinitionNode|InlineFragmentNode $fragment + * + * @return bool + */ + private function doesFragmentConditionMatch( + $fragment, + ObjectType $type + ) { + $typeConditionNode = $fragment->typeCondition; + if ($typeConditionNode === null) { + return true; + } + $conditionalType = TypeInfo::typeFromAST($this->exeContext->schema, $typeConditionNode); + if ($conditionalType === $type) { + return true; + } + if ($conditionalType instanceof AbstractType) { + return $this->exeContext->schema->isPossibleType($conditionalType, $type); + } + + return false; + } + + /** + * Implements the "Evaluating selection sets" section of the spec + * for "write" mode. + * + * @param mixed[] $sourceValue + * @param mixed[] $path + * @param ArrayObject $fields + * + * @return Promise|stdClass|mixed[] + */ + private function executeFieldsSerially(ObjectType $parentType, $sourceValue, $path, $fields) + { + $result = $this->promiseReduce( + array_keys($fields->getArrayCopy()), + function ($results, $responseName) use ($path, $parentType, $sourceValue, $fields) { + $fieldNodes = $fields[$responseName]; + $fieldPath = $path; + $fieldPath[] = $responseName; + $result = $this->resolveField($parentType, $sourceValue, $fieldNodes, $fieldPath); + if ($result === self::$UNDEFINED) { + return $results; + } + $promise = $this->getPromise($result); + if ($promise) { + return $promise->then(static function ($resolvedResult) use ($responseName, $results) { + $results[$responseName] = $resolvedResult; + + return $results; + }); + } + $results[$responseName] = $result; + + return $results; + }, + [] + ); + if ($this->isPromise($result)) { + return $result->then(static function ($resolvedResults) { + return self::fixResultsIfEmptyArray($resolvedResults); + }); + } + + return self::fixResultsIfEmptyArray($result); + } + + /** + * Resolves the field on the given source object. In particular, this + * figures out the value that the field returns by calling its resolve function, + * then calls completeValue to complete promises, serialize scalars, or execute + * the sub-selection-set for objects. + * + * @param object|null $source + * @param FieldNode[] $fieldNodes + * @param mixed[] $path + * + * @return mixed[]|Exception|mixed|null + */ + private function resolveField(ObjectType $parentType, $source, $fieldNodes, $path) + { + $exeContext = $this->exeContext; + $fieldNode = $fieldNodes[0]; + $fieldName = $fieldNode->name->value; + $fieldDef = $this->getFieldDef($exeContext->schema, $parentType, $fieldName); + if (! $fieldDef) { + return self::$UNDEFINED; + } + $returnType = $fieldDef->getType(); + // The resolve function's optional third argument is a collection of + // information about the current execution state. + $info = new ResolveInfo( + $fieldName, + $fieldNodes, + $returnType, + $parentType, + $path, + $exeContext->schema, + $exeContext->fragments, + $exeContext->rootValue, + $exeContext->operation, + $exeContext->variableValues + ); + if ($fieldDef->resolveFn !== null) { + $resolveFn = $fieldDef->resolveFn; + } elseif ($parentType->resolveFieldFn !== null) { + $resolveFn = $parentType->resolveFieldFn; + } else { + $resolveFn = $this->exeContext->fieldResolver; + } + // The resolve function's optional third argument is a context value that + // is provided to every resolve function within an execution. It is commonly + // used to represent an authenticated user, or request-specific caches. + $context = $exeContext->contextValue; + // Get the resolve function, regardless of if its result is normal + // or abrupt (error). + $result = $this->resolveOrError( + $fieldDef, + $fieldNode, + $resolveFn, + $source, + $context, + $info + ); + $result = $this->completeValueCatchingError( + $returnType, + $fieldNodes, + $info, + $path, + $result + ); + + return $result; + } + + /** + * This method looks up the field on the given type definition. + * It has special casing for the two introspection fields, __schema + * and __typename. __typename is special because it can always be + * queried as a field, even in situations where no other fields + * are allowed, like on a Union. __schema could get automatically + * added to the query type, but that would require mutating type + * definitions, which would cause issues. + * + * @param string $fieldName + * + * @return FieldDefinition + */ + private function getFieldDef(Schema $schema, ObjectType $parentType, $fieldName) + { + static $schemaMetaFieldDef, $typeMetaFieldDef, $typeNameMetaFieldDef; + $schemaMetaFieldDef = $schemaMetaFieldDef ?: Introspection::schemaMetaFieldDef(); + $typeMetaFieldDef = $typeMetaFieldDef ?: Introspection::typeMetaFieldDef(); + $typeNameMetaFieldDef = $typeNameMetaFieldDef ?: Introspection::typeNameMetaFieldDef(); + if ($fieldName === $schemaMetaFieldDef->name && $schema->getQueryType() === $parentType) { + return $schemaMetaFieldDef; + } + + if ($fieldName === $typeMetaFieldDef->name && $schema->getQueryType() === $parentType) { + return $typeMetaFieldDef; + } + + if ($fieldName === $typeNameMetaFieldDef->name) { + return $typeNameMetaFieldDef; + } + $tmp = $parentType->getFields(); + + return $tmp[$fieldName] ?? null; + } + + /** + * Isolates the "ReturnOrAbrupt" behavior to not de-opt the `resolveField` + * function. Returns the result of resolveFn or the abrupt-return Error object. + * + * @param FieldDefinition $fieldDef + * @param FieldNode $fieldNode + * @param callable $resolveFn + * @param mixed $source + * @param mixed $context + * @param ResolveInfo $info + * + * @return Throwable|Promise|mixed + */ + private function resolveOrError($fieldDef, $fieldNode, $resolveFn, $source, $context, $info) + { + try { + // Build hash of arguments from the field.arguments AST, using the + // variables scope to fulfill any variable references. + $args = Values::getArgumentValues( + $fieldDef, + $fieldNode, + $this->exeContext->variableValues + ); + + return $resolveFn($source, $args, $context, $info); + } catch (Exception $error) { + return $error; + } catch (Throwable $error) { + return $error; + } + } + + /** + * This is a small wrapper around completeValue which detects and logs errors + * in the execution context. + * + * @param FieldNode[] $fieldNodes + * @param string[] $path + * @param mixed $result + * + * @return mixed[]|Promise|null + */ + private function completeValueCatchingError( + Type $returnType, + $fieldNodes, + ResolveInfo $info, + $path, + $result + ) { + $exeContext = $this->exeContext; + // If the field type is non-nullable, then it is resolved without any + // protection from errors. + if ($returnType instanceof NonNull) { + return $this->completeValueWithLocatedError( + $returnType, + $fieldNodes, + $info, + $path, + $result + ); + } + // Otherwise, error protection is applied, logging the error and resolving + // a null value for this field if one is encountered. + try { + $completed = $this->completeValueWithLocatedError( + $returnType, + $fieldNodes, + $info, + $path, + $result + ); + $promise = $this->getPromise($completed); + if ($promise) { + return $promise->then( + null, + function ($error) use ($exeContext) { + $exeContext->addError($error); + + return $this->exeContext->promises->createFulfilled(null); + } + ); + } + + return $completed; + } catch (Error $err) { + // If `completeValueWithLocatedError` returned abruptly (threw an error), log the error + // and return null. + $exeContext->addError($err); + + return null; + } + } + + /** + * This is a small wrapper around completeValue which annotates errors with + * location information. + * + * @param FieldNode[] $fieldNodes + * @param string[] $path + * @param mixed $result + * + * @return mixed[]|mixed|Promise|null + * + * @throws Error + */ + public function completeValueWithLocatedError( + Type $returnType, + $fieldNodes, + ResolveInfo $info, + $path, + $result + ) { + try { + $completed = $this->completeValue( + $returnType, + $fieldNodes, + $info, + $path, + $result + ); + $promise = $this->getPromise($completed); + if ($promise) { + return $promise->then( + null, + function ($error) use ($fieldNodes, $path) { + return $this->exeContext->promises->createRejected(Error::createLocatedError( + $error, + $fieldNodes, + $path + )); + } + ); + } + + return $completed; + } catch (Exception $error) { + throw Error::createLocatedError($error, $fieldNodes, $path); + } catch (Throwable $error) { + throw Error::createLocatedError($error, $fieldNodes, $path); + } + } + + /** + * Implements the instructions for completeValue as defined in the + * "Field entries" section of the spec. + * + * If the field type is Non-Null, then this recursively completes the value + * for the inner type. It throws a field error if that completion returns null, + * as per the "Nullability" section of the spec. + * + * If the field type is a List, then this recursively completes the value + * for the inner type on each item in the list. + * + * If the field type is a Scalar or Enum, ensures the completed value is a legal + * value of the type by calling the `serialize` method of GraphQL type + * definition. + * + * If the field is an abstract type, determine the runtime type of the value + * and then complete based on that type + * + * Otherwise, the field type expects a sub-selection set, and will complete the + * value by evaluating all sub-selections. + * + * @param FieldNode[] $fieldNodes + * @param string[] $path + * @param mixed $result + * + * @return mixed[]|mixed|Promise|null + * + * @throws Error + * @throws Throwable + */ + private function completeValue( + Type $returnType, + $fieldNodes, + ResolveInfo $info, + $path, + &$result + ) { + $promise = $this->getPromise($result); + // If result is a Promise, apply-lift over completeValue. + if ($promise) { + return $promise->then(function (&$resolved) use ($returnType, $fieldNodes, $info, $path) { + return $this->completeValue($returnType, $fieldNodes, $info, $path, $resolved); + }); + } + if ($result instanceof Exception || $result instanceof Throwable) { + throw $result; + } + // If field type is NonNull, complete for inner type, and throw field error + // if result is null. + if ($returnType instanceof NonNull) { + $completed = $this->completeValue( + $returnType->getWrappedType(), + $fieldNodes, + $info, + $path, + $result + ); + if ($completed === null) { + throw new InvariantViolation( + 'Cannot return null for non-nullable field ' . $info->parentType . '.' . $info->fieldName . '.' + ); + } + + return $completed; + } + // If result is null-like, return null. + if ($result === null) { + return null; + } + // If field type is List, complete each item in the list with the inner type + if ($returnType instanceof ListOfType) { + return $this->completeListValue($returnType, $fieldNodes, $info, $path, $result); + } + // Account for invalid schema definition when typeLoader returns different + // instance than `resolveType` or $field->getType() or $arg->getType() + if ($returnType !== $this->exeContext->schema->getType($returnType->name)) { + $hint = ''; + if ($this->exeContext->schema->getConfig()->typeLoader) { + $hint = sprintf( + 'Make sure that type loader returns the same instance as defined in %s.%s', + $info->parentType, + $info->fieldName + ); + } + throw new InvariantViolation( + sprintf( + 'Schema must contain unique named types but contains multiple types named "%s". %s ' . + '(see http://webonyx.github.io/graphql-php/type-system/#type-registry).', + $returnType, + $hint + ) + ); + } + // If field type is Scalar or Enum, serialize to a valid value, returning + // null if serialization is not possible. + if ($returnType instanceof LeafType) { + return $this->completeLeafValue($returnType, $result); + } + if ($returnType instanceof AbstractType) { + return $this->completeAbstractValue($returnType, $fieldNodes, $info, $path, $result); + } + // Field type must be Object, Interface or Union and expect sub-selections. + if ($returnType instanceof ObjectType) { + return $this->completeObjectValue($returnType, $fieldNodes, $info, $path, $result); + } + throw new RuntimeException(sprintf('Cannot complete value of unexpected type "%s".', $returnType)); + } + + /** + * @param mixed $value + * + * @return bool + */ + private function isPromise($value) + { + return $value instanceof Promise || $this->exeContext->promises->isThenable($value); + } + + /** + * Only returns the value if it acts like a Promise, i.e. has a "then" function, + * otherwise returns null. + * + * @param mixed $value + * + * @return Promise|null + */ + private function getPromise($value) + { + if ($value === null || $value instanceof Promise) { + return $value; + } + if ($this->exeContext->promises->isThenable($value)) { + $promise = $this->exeContext->promises->convertThenable($value); + if (! $promise instanceof Promise) { + throw new InvariantViolation(sprintf( + '%s::convertThenable is expected to return instance of GraphQL\Executor\Promise\Promise, got: %s', + get_class($this->exeContext->promises), + Utils::printSafe($promise) + )); + } + + return $promise; + } + + return null; + } + + /** + * Similar to array_reduce(), however the reducing callback may return + * a Promise, in which case reduction will continue after each promise resolves. + * + * If the callback does not return a Promise, then this function will also not + * return a Promise. + * + * @param mixed[] $values + * @param Promise|mixed|null $initialValue + * + * @return mixed[] + */ + private function promiseReduce(array $values, callable $callback, $initialValue) + { + return array_reduce( + $values, + function ($previous, $value) use ($callback) { + $promise = $this->getPromise($previous); + if ($promise) { + return $promise->then(static function ($resolved) use ($callback, $value) { + return $callback($resolved, $value); + }); + } + + return $callback($previous, $value); + }, + $initialValue + ); + } + + /** + * Complete a list value by completing each item in the list with the + * inner type + * + * @param FieldNode[] $fieldNodes + * @param mixed[] $path + * @param mixed $result + * + * @return mixed[]|Promise + * + * @throws Exception + */ + private function completeListValue(ListOfType $returnType, $fieldNodes, ResolveInfo $info, $path, &$result) + { + $itemType = $returnType->getWrappedType(); + Utils::invariant( + is_array($result) || $result instanceof Traversable, + 'User Error: expected iterable, but did not find one for field ' . $info->parentType . '.' . $info->fieldName . '.' + ); + $containsPromise = false; + $i = 0; + $completedItems = []; + foreach ($result as $item) { + $fieldPath = $path; + $fieldPath[] = $i++; + $completedItem = $this->completeValueCatchingError($itemType, $fieldNodes, $info, $fieldPath, $item); + if (! $containsPromise && $this->getPromise($completedItem)) { + $containsPromise = true; + } + $completedItems[] = $completedItem; + } + + return $containsPromise ? $this->exeContext->promises->all($completedItems) : $completedItems; + } + + /** + * Complete a Scalar or Enum by serializing to a valid value, throwing if serialization is not possible. + * + * @param mixed $result + * + * @return mixed + * + * @throws Exception + */ + private function completeLeafValue(LeafType $returnType, &$result) + { + try { + return $returnType->serialize($result); + } catch (Exception $error) { + throw new InvariantViolation( + 'Expected a value of type "' . Utils::printSafe($returnType) . '" but received: ' . Utils::printSafe($result), + 0, + $error + ); + } catch (Throwable $error) { + throw new InvariantViolation( + 'Expected a value of type "' . Utils::printSafe($returnType) . '" but received: ' . Utils::printSafe($result), + 0, + $error + ); + } + } + + /** + * Complete a value of an abstract type by determining the runtime object type + * of that value, then complete the value for that type. + * + * @param FieldNode[] $fieldNodes + * @param mixed[] $path + * @param mixed[] $result + * + * @return mixed + * + * @throws Error + */ + private function completeAbstractValue(AbstractType $returnType, $fieldNodes, ResolveInfo $info, $path, &$result) + { + $exeContext = $this->exeContext; + $runtimeType = $returnType->resolveType($result, $exeContext->contextValue, $info); + if ($runtimeType === null) { + $runtimeType = self::defaultTypeResolver($result, $exeContext->contextValue, $info, $returnType); + } + $promise = $this->getPromise($runtimeType); + if ($promise) { + return $promise->then(function ($resolvedRuntimeType) use ( + $returnType, + $fieldNodes, + $info, + $path, + &$result + ) { + return $this->completeObjectValue( + $this->ensureValidRuntimeType( + $resolvedRuntimeType, + $returnType, + $info, + $result + ), + $fieldNodes, + $info, + $path, + $result + ); + }); + } + + return $this->completeObjectValue( + $this->ensureValidRuntimeType( + $runtimeType, + $returnType, + $info, + $result + ), + $fieldNodes, + $info, + $path, + $result + ); + } + + /** + * If a resolveType function is not given, then a default resolve behavior is + * used which attempts two strategies: + * + * First, See if the provided value has a `__typename` field defined, if so, use + * that value as name of the resolved type. + * + * Otherwise, test each possible type for the abstract type by calling + * isTypeOf for the object being coerced, returning the first type that matches. + * + * @param mixed|null $value + * @param mixed|null $context + * + * @return ObjectType|Promise|null + */ + private function defaultTypeResolver($value, $context, ResolveInfo $info, AbstractType $abstractType) + { + // First, look for `__typename`. + if ($value !== null && + (is_array($value) || $value instanceof ArrayAccess) && + isset($value['__typename']) && + is_string($value['__typename']) + ) { + return $value['__typename']; + } + if ($abstractType instanceof InterfaceType && $info->schema->getConfig()->typeLoader) { + Warning::warnOnce( + sprintf( + 'GraphQL Interface Type `%s` returned `null` from its `resolveType` function ' . + 'for value: %s. Switching to slow resolution method using `isTypeOf` ' . + 'of all possible implementations. It requires full schema scan and degrades query performance significantly. ' . + ' Make sure your `resolveType` always returns valid implementation or throws.', + $abstractType->name, + Utils::printSafe($value) + ), + Warning::WARNING_FULL_SCHEMA_SCAN + ); + } + // Otherwise, test each possible type. + $possibleTypes = $info->schema->getPossibleTypes($abstractType); + $promisedIsTypeOfResults = []; + foreach ($possibleTypes as $index => $type) { + $isTypeOfResult = $type->isTypeOf($value, $context, $info); + if ($isTypeOfResult === null) { + continue; + } + $promise = $this->getPromise($isTypeOfResult); + if ($promise) { + $promisedIsTypeOfResults[$index] = $promise; + } elseif ($isTypeOfResult) { + return $type; + } + } + if (! empty($promisedIsTypeOfResults)) { + return $this->exeContext->promises->all($promisedIsTypeOfResults) + ->then(static function ($isTypeOfResults) use ($possibleTypes) { + foreach ($isTypeOfResults as $index => $result) { + if ($result) { + return $possibleTypes[$index]; + } + } + + return null; + }); + } + + return null; + } + + /** + * Complete an Object value by executing all sub-selections. + * + * @param FieldNode[] $fieldNodes + * @param mixed[] $path + * @param mixed $result + * + * @return mixed[]|Promise|stdClass + * + * @throws Error + */ + private function completeObjectValue(ObjectType $returnType, $fieldNodes, ResolveInfo $info, $path, &$result) + { + // If there is an isTypeOf predicate function, call it with the + // current result. If isTypeOf returns false, then raise an error rather + // than continuing execution. + $isTypeOf = $returnType->isTypeOf($result, $this->exeContext->contextValue, $info); + if ($isTypeOf !== null) { + $promise = $this->getPromise($isTypeOf); + if ($promise) { + return $promise->then(function ($isTypeOfResult) use ( + $returnType, + $fieldNodes, + $path, + &$result + ) { + if (! $isTypeOfResult) { + throw $this->invalidReturnTypeError($returnType, $result, $fieldNodes); + } + + return $this->collectAndExecuteSubfields( + $returnType, + $fieldNodes, + $path, + $result + ); + }); + } + if (! $isTypeOf) { + throw $this->invalidReturnTypeError($returnType, $result, $fieldNodes); + } + } + + return $this->collectAndExecuteSubfields( + $returnType, + $fieldNodes, + $path, + $result + ); + } + + /** + * @param mixed[] $result + * @param FieldNode[] $fieldNodes + * + * @return Error + */ + private function invalidReturnTypeError( + ObjectType $returnType, + $result, + $fieldNodes + ) { + return new Error( + 'Expected value of type "' . $returnType->name . '" but got: ' . Utils::printSafe($result) . '.', + $fieldNodes + ); + } + + /** + * @param FieldNode[] $fieldNodes + * @param mixed[] $path + * @param mixed[] $result + * + * @return mixed[]|Promise|stdClass + * + * @throws Error + */ + private function collectAndExecuteSubfields( + ObjectType $returnType, + $fieldNodes, + $path, + &$result + ) { + $subFieldNodes = $this->collectSubFields($returnType, $fieldNodes); + + return $this->executeFields($returnType, $result, $path, $subFieldNodes); + } + + private function collectSubFields(ObjectType $returnType, $fieldNodes) : ArrayObject + { + if (! isset($this->subFieldCache[$returnType])) { + $this->subFieldCache[$returnType] = new SplObjectStorage(); + } + if (! isset($this->subFieldCache[$returnType][$fieldNodes])) { + // Collect sub-fields to execute to complete this value. + $subFieldNodes = new ArrayObject(); + $visitedFragmentNames = new ArrayObject(); + foreach ($fieldNodes as $fieldNode) { + if (! isset($fieldNode->selectionSet)) { + continue; + } + $subFieldNodes = $this->collectFields( + $returnType, + $fieldNode->selectionSet, + $subFieldNodes, + $visitedFragmentNames + ); + } + $this->subFieldCache[$returnType][$fieldNodes] = $subFieldNodes; + } + + return $this->subFieldCache[$returnType][$fieldNodes]; + } + + /** + * Implements the "Evaluating selection sets" section of the spec + * for "read" mode. + * + * @param mixed|null $source + * @param mixed[] $path + * @param ArrayObject $fields + * + * @return Promise|stdClass|mixed[] + */ + private function executeFields(ObjectType $parentType, $source, $path, $fields) + { + $containsPromise = false; + $finalResults = []; + foreach ($fields as $responseName => $fieldNodes) { + $fieldPath = $path; + $fieldPath[] = $responseName; + $result = $this->resolveField($parentType, $source, $fieldNodes, $fieldPath); + if ($result === self::$UNDEFINED) { + continue; + } + if (! $containsPromise && $this->getPromise($result)) { + $containsPromise = true; + } + $finalResults[$responseName] = $result; + } + // If there are no promises, we can just return the object + if (! $containsPromise) { + return self::fixResultsIfEmptyArray($finalResults); + } + + // Otherwise, results is a map from field name to the result + // of resolving that field, which is possibly a promise. Return + // a promise that will return this same map, but with any + // promises replaced with the values they resolved to. + return $this->promiseForAssocArray($finalResults); + } + + /** + * @see https://github.com/webonyx/graphql-php/issues/59 + * + * @param mixed[] $results + * + * @return stdClass|mixed[] + */ + private static function fixResultsIfEmptyArray($results) + { + if ($results === []) { + return new stdClass(); + } + + return $results; + } + + /** + * This function transforms a PHP `array` into + * a `Promise>` + * + * In other words it returns a promise which resolves to normal PHP associative array which doesn't contain + * any promises. + * + * @param (string|Promise)[] $assoc + * + * @return mixed + */ + private function promiseForAssocArray(array $assoc) + { + $keys = array_keys($assoc); + $valuesAndPromises = array_values($assoc); + $promise = $this->exeContext->promises->all($valuesAndPromises); + + return $promise->then(static function ($values) use ($keys) { + $resolvedResults = []; + foreach ($values as $i => $value) { + $resolvedResults[$keys[$i]] = $value; + } + + return self::fixResultsIfEmptyArray($resolvedResults); + }); + } + + /** + * @param string|ObjectType|null $runtimeTypeOrName + * @param FieldNode[] $fieldNodes + * @param mixed $result + * + * @return ObjectType + */ + private function ensureValidRuntimeType( + $runtimeTypeOrName, + AbstractType $returnType, + ResolveInfo $info, + &$result + ) { + $runtimeType = is_string($runtimeTypeOrName) ? + $this->exeContext->schema->getType($runtimeTypeOrName) : + $runtimeTypeOrName; + if (! $runtimeType instanceof ObjectType) { + throw new InvariantViolation( + sprintf( + 'Abstract type %s must resolve to an Object type at ' . + 'runtime for field %s.%s with value "%s", received "%s". ' . + 'Either the %s type should provide a "resolveType" ' . + 'function or each possible type should provide an "isTypeOf" function.', + $returnType, + $info->parentType, + $info->fieldName, + Utils::printSafe($result), + Utils::printSafe($runtimeType), + $returnType + ) + ); + } + if (! $this->exeContext->schema->isPossibleType($returnType, $runtimeType)) { + throw new InvariantViolation( + sprintf('Runtime Object type "%s" is not a possible type for "%s".', $runtimeType, $returnType) + ); + } + if ($runtimeType !== $this->exeContext->schema->getType($runtimeType->name)) { + throw new InvariantViolation( + sprintf( + 'Schema must contain unique named types but contains multiple types named "%s". ' . + 'Make sure that `resolveType` function of abstract type "%s" returns the same ' . + 'type instance as referenced anywhere else within the schema ' . + '(see http://webonyx.github.io/graphql-php/type-system/#type-registry).', + $runtimeType, + $returnType + ) + ); + } + + return $runtimeType; + } +} diff --git a/vendor/webonyx/graphql-php/src/Executor/Values.php b/vendor/webonyx/graphql-php/src/Executor/Values.php new file mode 100644 index 0000000..5548bcb --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Executor/Values.php @@ -0,0 +1,278 @@ +variable->name->value; + /** @var InputType|Type $varType */ + $varType = TypeInfo::typeFromAST($schema, $varDefNode->type); + + if (Type::isInputType($varType)) { + if (array_key_exists($varName, $inputs)) { + $value = $inputs[$varName]; + $coerced = Value::coerceValue($value, $varType, $varDefNode); + /** @var Error[] $coercionErrors */ + $coercionErrors = $coerced['errors']; + if (empty($coercionErrors)) { + $coercedValues[$varName] = $coerced['value']; + } else { + $messagePrelude = sprintf( + 'Variable "$%s" got invalid value %s; ', + $varName, + Utils::printSafeJson($value) + ); + + foreach ($coercionErrors as $error) { + $errors[] = new Error( + $messagePrelude . $error->getMessage(), + $error->getNodes(), + $error->getSource(), + $error->getPositions(), + $error->getPath(), + $error->getPrevious(), + $error->getExtensions() + ); + } + } + } else { + if ($varType instanceof NonNull) { + $errors[] = new Error( + sprintf( + 'Variable "$%s" of required type "%s" was not provided.', + $varName, + $varType + ), + [$varDefNode] + ); + } elseif ($varDefNode->defaultValue) { + $coercedValues[$varName] = AST::valueFromAST($varDefNode->defaultValue, $varType); + } + } + } else { + $errors[] = new Error( + sprintf( + 'Variable "$%s" expected value of type "%s" which cannot be used as an input type.', + $varName, + Printer::doPrint($varDefNode->type) + ), + [$varDefNode->type] + ); + } + } + + if (! empty($errors)) { + return [$errors, null]; + } + + return [null, $coercedValues]; + } + + /** + * Prepares an object map of argument values given a directive definition + * and a AST node which may contain directives. Optionally also accepts a map + * of variable values. + * + * If the directive does not exist on the node, returns undefined. + * + * @param FragmentSpreadNode|FieldNode|InlineFragmentNode|EnumValueDefinitionNode|FieldDefinitionNode $node + * @param mixed[]|null $variableValues + * + * @return mixed[]|null + */ + public static function getDirectiveValues(Directive $directiveDef, $node, $variableValues = null) + { + if (isset($node->directives) && $node->directives instanceof NodeList) { + $directiveNode = Utils::find( + $node->directives, + static function (DirectiveNode $directive) use ($directiveDef) { + return $directive->name->value === $directiveDef->name; + } + ); + + if ($directiveNode !== null) { + return self::getArgumentValues($directiveDef, $directiveNode, $variableValues); + } + } + + return null; + } + + /** + * Prepares an object map of argument values given a list of argument + * definitions and list of argument AST nodes. + * + * @param FieldDefinition|Directive $def + * @param FieldNode|DirectiveNode $node + * @param mixed[] $variableValues + * + * @return mixed[] + * + * @throws Error + */ + public static function getArgumentValues($def, $node, $variableValues = null) + { + if (empty($def->args)) { + return []; + } + + $argumentNodes = $node->arguments; + if (empty($argumentNodes)) { + return []; + } + + $argumentValueMap = []; + foreach ($argumentNodes as $argumentNode) { + $argumentValueMap[$argumentNode->name->value] = $argumentNode->value; + } + + return static::getArgumentValuesForMap($def, $argumentValueMap, $variableValues, $node); + } + + /** + * @param FieldDefinition|Directive $fieldDefinition + * @param ArgumentNode[] $argumentValueMap + * @param mixed[] $variableValues + * @param Node|null $referenceNode + * + * @return mixed[] + * + * @throws Error + */ + public static function getArgumentValuesForMap($fieldDefinition, $argumentValueMap, $variableValues = null, $referenceNode = null) + { + $argumentDefinitions = $fieldDefinition->args; + $coercedValues = []; + + foreach ($argumentDefinitions as $argumentDefinition) { + $name = $argumentDefinition->name; + $argType = $argumentDefinition->getType(); + $argumentValueNode = $argumentValueMap[$name] ?? null; + + if (! $argumentValueNode) { + if ($argumentDefinition->defaultValueExists()) { + $coercedValues[$name] = $argumentDefinition->defaultValue; + } elseif ($argType instanceof NonNull) { + throw new Error( + 'Argument "' . $name . '" of required type ' . + '"' . Utils::printSafe($argType) . '" was not provided.', + $referenceNode + ); + } + } elseif ($argumentValueNode instanceof VariableNode) { + $variableName = $argumentValueNode->name->value; + + if ($variableValues && array_key_exists($variableName, $variableValues)) { + // Note: this does not check that this variable value is correct. + // This assumes that this query has been validated and the variable + // usage here is of the correct type. + $coercedValues[$name] = $variableValues[$variableName]; + } elseif ($argumentDefinition->defaultValueExists()) { + $coercedValues[$name] = $argumentDefinition->defaultValue; + } elseif ($argType instanceof NonNull) { + throw new Error( + 'Argument "' . $name . '" of required type "' . Utils::printSafe($argType) . '" was ' . + 'provided the variable "$' . $variableName . '" which was not provided ' . + 'a runtime value.', + [$argumentValueNode] + ); + } + } else { + $valueNode = $argumentValueNode; + $coercedValue = AST::valueFromAST($valueNode, $argType, $variableValues); + if (Utils::isInvalid($coercedValue)) { + // Note: ValuesOfCorrectType validation should catch this before + // execution. This is a runtime check to ensure execution does not + // continue with an invalid argument value. + throw new Error( + 'Argument "' . $name . '" has invalid value ' . Printer::doPrint($valueNode) . '.', + [$argumentValueNode] + ); + } + $coercedValues[$name] = $coercedValue; + } + } + + return $coercedValues; + } + + /** + * @deprecated as of 8.0 (Moved to \GraphQL\Utils\AST::valueFromAST) + * + * @param ValueNode $valueNode + * @param mixed[]|null $variables + * + * @return mixed[]|stdClass|null + */ + public static function valueFromAST($valueNode, InputType $type, ?array $variables = null) + { + return AST::valueFromAST($valueNode, $type, $variables); + } + + /** + * @deprecated as of 0.12 (Use coerceValue() directly for richer information) + * + * @param mixed[] $value + * + * @return string[] + */ + public static function isValidPHPValue($value, InputType $type) + { + $errors = Value::coerceValue($value, $type)['errors']; + + return $errors + ? array_map( + static function (Throwable $error) { + return $error->getMessage(); + }, + $errors + ) : []; + } +} diff --git a/vendor/webonyx/graphql-php/src/Experimental/Executor/Collector.php b/vendor/webonyx/graphql-php/src/Experimental/Executor/Collector.php new file mode 100644 index 0000000..99131ba --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Experimental/Executor/Collector.php @@ -0,0 +1,283 @@ +schema = $schema; + $this->runtime = $runtime; + } + + public function initialize(DocumentNode $documentNode, ?string $operationName = null) + { + $hasMultipleAssumedOperations = false; + + foreach ($documentNode->definitions as $definitionNode) { + /** @var DefinitionNode|Node $definitionNode */ + + if ($definitionNode->kind === NodeKind::OPERATION_DEFINITION) { + /** @var OperationDefinitionNode $definitionNode */ + if ($operationName === null && $this->operation !== null) { + $hasMultipleAssumedOperations = true; + } + if ($operationName === null || + (isset($definitionNode->name) && $definitionNode->name->value === $operationName) + ) { + $this->operation = $definitionNode; + } + } elseif ($definitionNode->kind === NodeKind::FRAGMENT_DEFINITION) { + /** @var FragmentDefinitionNode $definitionNode */ + $this->fragments[$definitionNode->name->value] = $definitionNode; + } + } + + if ($this->operation === null) { + if ($operationName !== null) { + $this->runtime->addError(new Error(sprintf('Unknown operation named "%s".', $operationName))); + } else { + $this->runtime->addError(new Error('Must provide an operation.')); + } + + return; + } + + if ($hasMultipleAssumedOperations) { + $this->runtime->addError(new Error('Must provide operation name if query contains multiple operations.')); + + return; + } + + if ($this->operation->operation === 'query') { + $this->rootType = $this->schema->getQueryType(); + } elseif ($this->operation->operation === 'mutation') { + $this->rootType = $this->schema->getMutationType(); + } elseif ($this->operation->operation === 'subscription') { + $this->rootType = $this->schema->getSubscriptionType(); + } else { + $this->runtime->addError(new Error(sprintf('Cannot initialize collector with operation type "%s".', $this->operation->operation))); + } + } + + /** + * @return Generator + */ + public function collectFields(ObjectType $runtimeType, ?SelectionSetNode $selectionSet) + { + $this->fields = []; + $this->visitedFragments = []; + + $this->doCollectFields($runtimeType, $selectionSet); + + foreach ($this->fields as $resultName => $fieldNodes) { + $fieldNode = $fieldNodes[0]; + $fieldName = $fieldNode->name->value; + + $argumentValueMap = null; + if (! empty($fieldNode->arguments)) { + foreach ($fieldNode->arguments as $argumentNode) { + $argumentValueMap = $argumentValueMap ?? []; + $argumentValueMap[$argumentNode->name->value] = $argumentNode->value; + } + } + + if ($fieldName !== Introspection::TYPE_NAME_FIELD_NAME && + ! ($runtimeType === $this->schema->getQueryType() && ($fieldName === Introspection::SCHEMA_FIELD_NAME || $fieldName === Introspection::TYPE_FIELD_NAME)) && + ! $runtimeType->hasField($fieldName) + ) { + // do not emit error + continue; + } + + yield new CoroutineContextShared($fieldNodes, $fieldName, $resultName, $argumentValueMap); + } + } + + private function doCollectFields(ObjectType $runtimeType, ?SelectionSetNode $selectionSet) + { + if ($selectionSet === null) { + return; + } + + foreach ($selectionSet->selections as $selection) { + /** @var FieldNode|FragmentSpreadNode|InlineFragmentNode $selection */ + + if (! empty($selection->directives)) { + foreach ($selection->directives as $directiveNode) { + if ($directiveNode->name->value === Directive::SKIP_NAME) { + /** @var ValueNode|null $condition */ + $condition = null; + foreach ($directiveNode->arguments as $argumentNode) { + if ($argumentNode->name->value === Directive::IF_ARGUMENT_NAME) { + $condition = $argumentNode->value; + break; + } + } + + if ($condition === null) { + $this->runtime->addError(new Error( + sprintf('@%s directive is missing "%s" argument.', Directive::SKIP_NAME, Directive::IF_ARGUMENT_NAME), + $selection + )); + } else { + if ($this->runtime->evaluate($condition, Type::boolean()) === true) { + continue 2; // !!! advances outer loop + } + } + } elseif ($directiveNode->name->value === Directive::INCLUDE_NAME) { + /** @var ValueNode|null $condition */ + $condition = null; + foreach ($directiveNode->arguments as $argumentNode) { + if ($argumentNode->name->value === Directive::IF_ARGUMENT_NAME) { + $condition = $argumentNode->value; + break; + } + } + + if ($condition === null) { + $this->runtime->addError(new Error( + sprintf('@%s directive is missing "%s" argument.', Directive::INCLUDE_NAME, Directive::IF_ARGUMENT_NAME), + $selection + )); + } else { + if ($this->runtime->evaluate($condition, Type::boolean()) !== true) { + continue 2; // !!! advances outer loop + } + } + } + } + } + + if ($selection->kind === NodeKind::FIELD) { + /** @var FieldNode $selection */ + + $resultName = $selection->alias ? $selection->alias->value : $selection->name->value; + + if (! isset($this->fields[$resultName])) { + $this->fields[$resultName] = []; + } + + $this->fields[$resultName][] = $selection; + } elseif ($selection->kind === NodeKind::FRAGMENT_SPREAD) { + /** @var FragmentSpreadNode $selection */ + + $fragmentName = $selection->name->value; + + if (isset($this->visitedFragments[$fragmentName])) { + continue; + } + + if (! isset($this->fragments[$fragmentName])) { + $this->runtime->addError(new Error( + sprintf('Fragment "%s" does not exist.', $fragmentName), + $selection + )); + continue; + } + + $this->visitedFragments[$fragmentName] = true; + + $fragmentDefinition = $this->fragments[$fragmentName]; + $conditionTypeName = $fragmentDefinition->typeCondition->name->value; + + if (! $this->schema->hasType($conditionTypeName)) { + $this->runtime->addError(new Error( + sprintf('Cannot spread fragment "%s", type "%s" does not exist.', $fragmentName, $conditionTypeName), + $selection + )); + continue; + } + + $conditionType = $this->schema->getType($conditionTypeName); + + if ($conditionType instanceof ObjectType) { + if ($runtimeType->name !== $conditionType->name) { + continue; + } + } elseif ($conditionType instanceof AbstractType) { + if (! $this->schema->isPossibleType($conditionType, $runtimeType)) { + continue; + } + } + + $this->doCollectFields($runtimeType, $fragmentDefinition->selectionSet); + } elseif ($selection->kind === NodeKind::INLINE_FRAGMENT) { + /** @var InlineFragmentNode $selection */ + + if ($selection->typeCondition !== null) { + $conditionTypeName = $selection->typeCondition->name->value; + + if (! $this->schema->hasType($conditionTypeName)) { + $this->runtime->addError(new Error( + sprintf('Cannot spread inline fragment, type "%s" does not exist.', $conditionTypeName), + $selection + )); + continue; + } + + $conditionType = $this->schema->getType($conditionTypeName); + + if ($conditionType instanceof ObjectType) { + if ($runtimeType->name !== $conditionType->name) { + continue; + } + } elseif ($conditionType instanceof AbstractType) { + if (! $this->schema->isPossibleType($conditionType, $runtimeType)) { + continue; + } + } + } + + $this->doCollectFields($runtimeType, $selection->selectionSet); + } + } + } +} diff --git a/vendor/webonyx/graphql-php/src/Experimental/Executor/CoroutineContext.php b/vendor/webonyx/graphql-php/src/Experimental/Executor/CoroutineContext.php new file mode 100644 index 0000000..910b41d --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Experimental/Executor/CoroutineContext.php @@ -0,0 +1,57 @@ +shared = $shared; + $this->type = $type; + $this->value = $value; + $this->result = $result; + $this->path = $path; + $this->nullFence = $nullFence; + } +} diff --git a/vendor/webonyx/graphql-php/src/Experimental/Executor/CoroutineContextShared.php b/vendor/webonyx/graphql-php/src/Experimental/Executor/CoroutineContextShared.php new file mode 100644 index 0000000..bbc5488 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Experimental/Executor/CoroutineContextShared.php @@ -0,0 +1,62 @@ +fieldNodes = $fieldNodes; + $this->fieldName = $fieldName; + $this->resultName = $resultName; + $this->argumentValueMap = $argumentValueMap; + } +} diff --git a/vendor/webonyx/graphql-php/src/Experimental/Executor/CoroutineExecutor.php b/vendor/webonyx/graphql-php/src/Experimental/Executor/CoroutineExecutor.php new file mode 100644 index 0000000..91091b4 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Experimental/Executor/CoroutineExecutor.php @@ -0,0 +1,948 @@ +schema = $schema; + $this->fieldResolver = $fieldResolver; + $this->promiseAdapter = $promiseAdapter; + $this->rootValue = $rootValue; + $this->contextValue = $contextValue; + $this->rawVariableValues = $rawVariableValues; + $this->documentNode = $documentNode; + $this->operationName = $operationName; + } + + public static function create( + PromiseAdapter $promiseAdapter, + Schema $schema, + DocumentNode $documentNode, + $rootValue, + $contextValue, + $variableValues, + ?string $operationName, + callable $fieldResolver + ) { + return new static( + $promiseAdapter, + $schema, + $documentNode, + $rootValue, + $contextValue, + $variableValues, + $operationName, + $fieldResolver + ); + } + + private static function resultToArray($value, $emptyObjectAsStdClass = true) + { + if ($value instanceof stdClass) { + $array = []; + foreach ($value as $propertyName => $propertyValue) { + $array[$propertyName] = self::resultToArray($propertyValue); + } + if ($emptyObjectAsStdClass && empty($array)) { + return new stdClass(); + } + + return $array; + } + + if (is_array($value)) { + $array = []; + foreach ($value as $key => $item) { + $array[$key] = self::resultToArray($item); + } + + return $array; + } + + return $value; + } + + public function doExecute() : Promise + { + $this->rootResult = new stdClass(); + $this->errors = []; + $this->queue = new SplQueue(); + $this->schedule = new SplQueue(); + $this->pending = 0; + + $this->collector = new Collector($this->schema, $this); + $this->collector->initialize($this->documentNode, $this->operationName); + + if (! empty($this->errors)) { + return $this->promiseAdapter->createFulfilled($this->finishExecute(null, $this->errors)); + } + + [$errors, $coercedVariableValues] = Values::getVariableValues( + $this->schema, + $this->collector->operation->variableDefinitions ?: [], + $this->rawVariableValues ?: [] + ); + + if (! empty($errors)) { + return $this->promiseAdapter->createFulfilled($this->finishExecute(null, $errors)); + } + + $this->variableValues = $coercedVariableValues; + + foreach ($this->collector->collectFields($this->collector->rootType, $this->collector->operation->selectionSet) as $shared) { + /** @var CoroutineContextShared $shared */ + + // !!! assign to keep object keys sorted + $this->rootResult->{$shared->resultName} = null; + + $ctx = new CoroutineContext( + $shared, + $this->collector->rootType, + $this->rootValue, + $this->rootResult, + [$shared->resultName] + ); + + $fieldDefinition = $this->findFieldDefinition($ctx); + if (! $fieldDefinition->getType() instanceof NonNull) { + $ctx->nullFence = [$shared->resultName]; + } + + if ($this->collector->operation->operation === 'mutation' && ! $this->queue->isEmpty()) { + $this->schedule->enqueue($ctx); + } else { + $this->queue->enqueue(new Strand($this->spawn($ctx))); + } + } + + $this->run(); + + if ($this->pending > 0) { + return $this->promiseAdapter->create(function (callable $resolve) { + $this->doResolve = $resolve; + }); + } + + return $this->promiseAdapter->createFulfilled($this->finishExecute($this->rootResult, $this->errors)); + } + + /** + * @param object|null $value + * @param Error[] $errors + */ + private function finishExecute($value, array $errors) : ExecutionResult + { + $this->rootResult = null; + $this->errors = null; + $this->queue = null; + $this->schedule = null; + $this->pending = null; + $this->collector = null; + $this->variableValues = null; + + if ($value !== null) { + $value = self::resultToArray($value, false); + } + + return new ExecutionResult($value, $errors); + } + + /** + * @internal + */ + public function evaluate(ValueNode $valueNode, InputType $type) + { + return AST::valueFromAST($valueNode, $type, $this->variableValues); + } + + /** + * @internal + */ + public function addError($error) + { + $this->errors[] = $error; + } + + private function run() + { + RUN: + while (! $this->queue->isEmpty()) { + /** @var Strand $strand */ + $strand = $this->queue->dequeue(); + + try { + if ($strand->success !== null) { + RESUME: + + if ($strand->success) { + $strand->current->send($strand->value); + } else { + $strand->current->throw($strand->value); + } + + $strand->success = null; + $strand->value = null; + } + + START: + if ($strand->current->valid()) { + $value = $strand->current->current(); + + if ($value instanceof Generator) { + $strand->stack[$strand->depth++] = $strand->current; + $strand->current = $value; + goto START; + } elseif ($this->isPromise($value)) { + // !!! increment pending before calling ->then() as it may invoke the callback right away + ++$this->pending; + + if (! $value instanceof Promise) { + $value = $this->promiseAdapter->convertThenable($value); + } + + $this->promiseAdapter + ->then( + $value, + function ($value) use ($strand) { + $strand->success = true; + $strand->value = $value; + $this->queue->enqueue($strand); + $this->done(); + }, + function (Throwable $throwable) use ($strand) { + $strand->success = false; + $strand->value = $throwable; + $this->queue->enqueue($strand); + $this->done(); + } + ); + continue; + } else { + $strand->success = true; + $strand->value = $value; + goto RESUME; + } + } + + $strand->success = true; + $strand->value = $strand->current->getReturn(); + } catch (Throwable $reason) { + $strand->success = false; + $strand->value = $reason; + } + + if ($strand->depth <= 0) { + continue; + } + + $current = &$strand->stack[--$strand->depth]; + $strand->current = $current; + $current = null; + goto RESUME; + } + + if ($this->pending > 0 || $this->schedule->isEmpty()) { + return; + } + + /** @var CoroutineContext $ctx */ + $ctx = $this->schedule->dequeue(); + $this->queue->enqueue(new Strand($this->spawn($ctx))); + goto RUN; + } + + private function done() + { + --$this->pending; + + $this->run(); + + if ($this->pending > 0) { + return; + } + + $doResolve = $this->doResolve; + $doResolve($this->finishExecute($this->rootResult, $this->errors)); + } + + private function spawn(CoroutineContext $ctx) + { + // short-circuit evaluation for __typename + if ($ctx->shared->fieldName === Introspection::TYPE_NAME_FIELD_NAME) { + $ctx->result->{$ctx->shared->resultName} = $ctx->type->name; + + return; + } + + try { + if ($ctx->shared->typeGuard1 === $ctx->type) { + $resolve = $ctx->shared->resolveIfType1; + $ctx->resolveInfo = clone $ctx->shared->resolveInfoIfType1; + $ctx->resolveInfo->path = $ctx->path; + $arguments = $ctx->shared->argumentsIfType1; + $returnType = $ctx->resolveInfo->returnType; + } else { + $fieldDefinition = $this->findFieldDefinition($ctx); + + if ($fieldDefinition->resolveFn !== null) { + $resolve = $fieldDefinition->resolveFn; + } elseif ($ctx->type->resolveFieldFn !== null) { + $resolve = $ctx->type->resolveFieldFn; + } else { + $resolve = $this->fieldResolver; + } + + $returnType = $fieldDefinition->getType(); + + $ctx->resolveInfo = new ResolveInfo( + $ctx->shared->fieldName, + $ctx->shared->fieldNodes, + $returnType, + $ctx->type, + $ctx->path, + $this->schema, + $this->collector->fragments, + $this->rootValue, + $this->collector->operation, + $this->variableValues + ); + + $arguments = Values::getArgumentValuesForMap( + $fieldDefinition, + $ctx->shared->argumentValueMap, + $this->variableValues + ); + + // !!! assign only in batch when no exception can be thrown in-between + $ctx->shared->typeGuard1 = $ctx->type; + $ctx->shared->resolveIfType1 = $resolve; + $ctx->shared->argumentsIfType1 = $arguments; + $ctx->shared->resolveInfoIfType1 = $ctx->resolveInfo; + } + + $value = $resolve($ctx->value, $arguments, $this->contextValue, $ctx->resolveInfo); + + if (! $this->completeValueFast($ctx, $returnType, $value, $ctx->path, $returnValue)) { + $returnValue = yield $this->completeValue( + $ctx, + $returnType, + $value, + $ctx->path, + $ctx->nullFence + ); + } + } catch (Throwable $reason) { + $this->addError(Error::createLocatedError( + $reason, + $ctx->shared->fieldNodes, + $ctx->path + )); + + $returnValue = self::$undefined; + } + + if ($returnValue !== self::$undefined) { + $ctx->result->{$ctx->shared->resultName} = $returnValue; + } elseif ($ctx->resolveInfo !== null && $ctx->resolveInfo->returnType instanceof NonNull) { // !!! $ctx->resolveInfo might not have been initialized yet + $result =& $this->rootResult; + foreach ($ctx->nullFence ?? [] as $key) { + if (is_string($key)) { + $result =& $result->{$key}; + } else { + $result =& $result[$key]; + } + } + $result = null; + } + } + + private function findFieldDefinition(CoroutineContext $ctx) + { + if ($ctx->shared->fieldName === Introspection::SCHEMA_FIELD_NAME && $ctx->type === $this->schema->getQueryType()) { + return Introspection::schemaMetaFieldDef(); + } + + if ($ctx->shared->fieldName === Introspection::TYPE_FIELD_NAME && $ctx->type === $this->schema->getQueryType()) { + return Introspection::typeMetaFieldDef(); + } + + if ($ctx->shared->fieldName === Introspection::TYPE_NAME_FIELD_NAME) { + return Introspection::typeNameMetaFieldDef(); + } + + return $ctx->type->getField($ctx->shared->fieldName); + } + + /** + * @param mixed $value + * @param string[] $path + * @param mixed $returnValue + */ + private function completeValueFast(CoroutineContext $ctx, Type $type, $value, array $path, &$returnValue) : bool + { + // special handling of Throwable inherited from JS reference implementation, but makes no sense in this PHP + if ($this->isPromise($value) || $value instanceof Throwable) { + return false; + } + + $nonNull = false; + if ($type instanceof NonNull) { + $nonNull = true; + $type = $type->getWrappedType(); + } + + if (! $type instanceof LeafType) { + return false; + } + + if ($type !== $this->schema->getType($type->name)) { + $hint = ''; + if ($this->schema->getConfig()->typeLoader) { + $hint = sprintf( + 'Make sure that type loader returns the same instance as defined in %s.%s', + $ctx->type, + $ctx->shared->fieldName + ); + } + $this->addError(Error::createLocatedError( + new InvariantViolation( + sprintf( + 'Schema must contain unique named types but contains multiple types named "%s". %s ' . + '(see http://webonyx.github.io/graphql-php/type-system/#type-registry).', + $type->name, + $hint + ) + ), + $ctx->shared->fieldNodes, + $path + )); + + $value = null; + } + + if ($value === null) { + $returnValue = null; + } else { + try { + $returnValue = $type->serialize($value); + } catch (Throwable $error) { + $this->addError(Error::createLocatedError( + new InvariantViolation( + 'Expected a value of type "' . Utils::printSafe($type) . '" but received: ' . Utils::printSafe($value), + 0, + $error + ), + $ctx->shared->fieldNodes, + $path + )); + $returnValue = null; + } + } + + if ($nonNull && $returnValue === null) { + $this->addError(Error::createLocatedError( + new InvariantViolation(sprintf( + 'Cannot return null for non-nullable field %s.%s.', + $ctx->type->name, + $ctx->shared->fieldName + )), + $ctx->shared->fieldNodes, + $path + )); + + $returnValue = self::$undefined; + } + + return true; + } + + /** + * @param mixed $value + * @param string[] $path + * @param string[]|null $nullFence + * + * @return mixed + */ + private function completeValue(CoroutineContext $ctx, Type $type, $value, array $path, ?array $nullFence) + { + $nonNull = false; + $returnValue = null; + + if ($type instanceof NonNull) { + $nonNull = true; + $type = $type->getWrappedType(); + } else { + $nullFence = $path; + } + + // !!! $value might be promise, yield to resolve + try { + if ($this->isPromise($value)) { + $value = yield $value; + } + } catch (Throwable $reason) { + $this->addError(Error::createLocatedError( + $reason, + $ctx->shared->fieldNodes, + $path + )); + if ($nonNull) { + $returnValue = self::$undefined; + } else { + $returnValue = null; + } + goto CHECKED_RETURN; + } + + if ($value === null) { + $returnValue = $value; + goto CHECKED_RETURN; + } elseif ($value instanceof Throwable) { + // special handling of Throwable inherited from JS reference implementation, but makes no sense in this PHP + $this->addError(Error::createLocatedError( + $value, + $ctx->shared->fieldNodes, + $path + )); + if ($nonNull) { + $returnValue = self::$undefined; + } else { + $returnValue = null; + } + goto CHECKED_RETURN; + } + + if ($type instanceof ListOfType) { + $returnValue = []; + $index = -1; + $itemType = $type->getWrappedType(); + foreach ($value as $itemValue) { + ++$index; + + $itemPath = $path; + $itemPath[] = $index; // !!! use arrays COW semantics + + try { + if (! $this->completeValueFast($ctx, $itemType, $itemValue, $itemPath, $itemReturnValue)) { + $itemReturnValue = yield $this->completeValue($ctx, $itemType, $itemValue, $itemPath, $nullFence); + } + } catch (Throwable $reason) { + $this->addError(Error::createLocatedError( + $reason, + $ctx->shared->fieldNodes, + $itemPath + )); + $itemReturnValue = null; + } + if ($itemReturnValue === self::$undefined) { + $returnValue = self::$undefined; + goto CHECKED_RETURN; + } + $returnValue[$index] = $itemReturnValue; + } + + goto CHECKED_RETURN; + } else { + if ($type !== $this->schema->getType($type->name)) { + $hint = ''; + if ($this->schema->getConfig()->typeLoader) { + $hint = sprintf( + 'Make sure that type loader returns the same instance as defined in %s.%s', + $ctx->type, + $ctx->shared->fieldName + ); + } + $this->addError(Error::createLocatedError( + new InvariantViolation( + sprintf( + 'Schema must contain unique named types but contains multiple types named "%s". %s ' . + '(see http://webonyx.github.io/graphql-php/type-system/#type-registry).', + $type->name, + $hint + ) + ), + $ctx->shared->fieldNodes, + $path + )); + + $returnValue = null; + goto CHECKED_RETURN; + } + + if ($type instanceof LeafType) { + try { + $returnValue = $type->serialize($value); + } catch (Throwable $error) { + $this->addError(Error::createLocatedError( + new InvariantViolation( + 'Expected a value of type "' . Utils::printSafe($type) . '" but received: ' . Utils::printSafe($value), + 0, + $error + ), + $ctx->shared->fieldNodes, + $path + )); + $returnValue = null; + } + goto CHECKED_RETURN; + } elseif ($type instanceof CompositeType) { + /** @var ObjectType|null $objectType */ + $objectType = null; + if ($type instanceof InterfaceType || $type instanceof UnionType) { + $objectType = $type->resolveType($value, $this->contextValue, $ctx->resolveInfo); + + if ($objectType === null) { + $objectType = yield $this->resolveTypeSlow($ctx, $value, $type); + } + + // !!! $objectType->resolveType() might return promise, yield to resolve + $objectType = yield $objectType; + if (is_string($objectType)) { + $objectType = $this->schema->getType($objectType); + } + + if ($objectType === null) { + $this->addError(Error::createLocatedError( + sprintf( + 'Composite type "%s" did not resolve concrete object type for value: %s.', + $type->name, + Utils::printSafe($value) + ), + $ctx->shared->fieldNodes, + $path + )); + + $returnValue = self::$undefined; + goto CHECKED_RETURN; + } elseif (! $objectType instanceof ObjectType) { + $this->addError(Error::createLocatedError( + new InvariantViolation(sprintf( + 'Abstract type %s must resolve to an Object type at ' . + 'runtime for field %s.%s with value "%s", received "%s". ' . + 'Either the %s type should provide a "resolveType" ' . + 'function or each possible type should provide an "isTypeOf" function.', + $type, + $ctx->resolveInfo->parentType, + $ctx->resolveInfo->fieldName, + Utils::printSafe($value), + Utils::printSafe($objectType), + $type + )), + $ctx->shared->fieldNodes, + $path + )); + + $returnValue = null; + goto CHECKED_RETURN; + } elseif (! $this->schema->isPossibleType($type, $objectType)) { + $this->addError(Error::createLocatedError( + new InvariantViolation(sprintf( + 'Runtime Object type "%s" is not a possible type for "%s".', + $objectType, + $type + )), + $ctx->shared->fieldNodes, + $path + )); + + $returnValue = null; + goto CHECKED_RETURN; + } elseif ($objectType !== $this->schema->getType($objectType->name)) { + $this->addError(Error::createLocatedError( + new InvariantViolation( + sprintf( + 'Schema must contain unique named types but contains multiple types named "%s". ' . + 'Make sure that `resolveType` function of abstract type "%s" returns the same ' . + 'type instance as referenced anywhere else within the schema ' . + '(see http://webonyx.github.io/graphql-php/type-system/#type-registry).', + $objectType, + $type + ) + ), + $ctx->shared->fieldNodes, + $path + )); + + $returnValue = null; + goto CHECKED_RETURN; + } + } elseif ($type instanceof ObjectType) { + $objectType = $type; + } else { + $this->addError(Error::createLocatedError( + sprintf( + 'Unexpected field type "%s".', + Utils::printSafe($type) + ), + $ctx->shared->fieldNodes, + $path + )); + + $returnValue = self::$undefined; + goto CHECKED_RETURN; + } + + $typeCheck = $objectType->isTypeOf($value, $this->contextValue, $ctx->resolveInfo); + if ($typeCheck !== null) { + // !!! $objectType->isTypeOf() might return promise, yield to resolve + $typeCheck = yield $typeCheck; + if (! $typeCheck) { + $this->addError(Error::createLocatedError( + sprintf('Expected value of type "%s" but got: %s.', $type->name, Utils::printSafe($value)), + $ctx->shared->fieldNodes, + $path + )); + + $returnValue = null; + goto CHECKED_RETURN; + } + } + + $returnValue = new stdClass(); + + if ($ctx->shared->typeGuard2 === $objectType) { + foreach ($ctx->shared->childContextsIfType2 as $childCtx) { + $childCtx = clone $childCtx; + $childCtx->type = $objectType; + $childCtx->value = $value; + $childCtx->result = $returnValue; + $childCtx->path = $path; + $childCtx->path[] = $childCtx->shared->resultName; // !!! uses array COW semantics + $childCtx->nullFence = $nullFence; + $childCtx->resolveInfo = null; + + $this->queue->enqueue(new Strand($this->spawn($childCtx))); + + // !!! assign null to keep object keys sorted + $returnValue->{$childCtx->shared->resultName} = null; + } + } else { + $childContexts = []; + + foreach ($this->collector->collectFields($objectType, $ctx->shared->mergedSelectionSet ?? $this->mergeSelectionSets($ctx)) as $childShared) { + /** @var CoroutineContextShared $childShared */ + + $childPath = $path; + $childPath[] = $childShared->resultName; // !!! uses array COW semantics + $childCtx = new CoroutineContext( + $childShared, + $objectType, + $value, + $returnValue, + $childPath, + $nullFence + ); + + $childContexts[] = $childCtx; + + $this->queue->enqueue(new Strand($this->spawn($childCtx))); + + // !!! assign null to keep object keys sorted + $returnValue->{$childShared->resultName} = null; + } + + $ctx->shared->typeGuard2 = $objectType; + $ctx->shared->childContextsIfType2 = $childContexts; + } + + goto CHECKED_RETURN; + } else { + $this->addError(Error::createLocatedError( + sprintf('Unhandled type "%s".', Utils::printSafe($type)), + $ctx->shared->fieldNodes, + $path + )); + + $returnValue = null; + goto CHECKED_RETURN; + } + } + + CHECKED_RETURN: + if ($nonNull && $returnValue === null) { + $this->addError(Error::createLocatedError( + new InvariantViolation(sprintf( + 'Cannot return null for non-nullable field %s.%s.', + $ctx->type->name, + $ctx->shared->fieldName + )), + $ctx->shared->fieldNodes, + $path + )); + + return self::$undefined; + } + + return $returnValue; + } + + private function mergeSelectionSets(CoroutineContext $ctx) + { + $selections = []; + + foreach ($ctx->shared->fieldNodes as $fieldNode) { + if ($fieldNode->selectionSet === null) { + continue; + } + + foreach ($fieldNode->selectionSet->selections as $selection) { + $selections[] = $selection; + } + } + + return $ctx->shared->mergedSelectionSet = new SelectionSetNode(['selections' => $selections]); + } + + private function resolveTypeSlow(CoroutineContext $ctx, $value, AbstractType $abstractType) + { + if ($value !== null && + is_array($value) && + isset($value['__typename']) && + is_string($value['__typename']) + ) { + return $this->schema->getType($value['__typename']); + } + + if ($abstractType instanceof InterfaceType && $this->schema->getConfig()->typeLoader) { + Warning::warnOnce( + sprintf( + 'GraphQL Interface Type `%s` returned `null` from its `resolveType` function ' . + 'for value: %s. Switching to slow resolution method using `isTypeOf` ' . + 'of all possible implementations. It requires full schema scan and degrades query performance significantly. ' . + ' Make sure your `resolveType` always returns valid implementation or throws.', + $abstractType->name, + Utils::printSafe($value) + ), + Warning::WARNING_FULL_SCHEMA_SCAN + ); + } + + $possibleTypes = $this->schema->getPossibleTypes($abstractType); + + // to be backward-compatible with old executor, ->isTypeOf() is called for all possible types, + // it cannot short-circuit when the match is found + + $selectedType = null; + foreach ($possibleTypes as $type) { + $typeCheck = yield $type->isTypeOf($value, $this->contextValue, $ctx->resolveInfo); + if ($selectedType !== null || $typeCheck !== true) { + continue; + } + + $selectedType = $type; + } + + return $selectedType; + } + + /** + * @param mixed $value + * + * @return bool + */ + private function isPromise($value) + { + return $value instanceof Promise || $this->promiseAdapter->isThenable($value); + } +} diff --git a/vendor/webonyx/graphql-php/src/Experimental/Executor/Runtime.php b/vendor/webonyx/graphql-php/src/Experimental/Executor/Runtime.php new file mode 100644 index 0000000..f8dc14a --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Experimental/Executor/Runtime.php @@ -0,0 +1,18 @@ +current = $coroutine; + $this->stack = []; + $this->depth = 0; + } +} diff --git a/vendor/webonyx/graphql-php/src/GraphQL.php b/vendor/webonyx/graphql-php/src/GraphQL.php new file mode 100644 index 0000000..a9819be --- /dev/null +++ b/vendor/webonyx/graphql-php/src/GraphQL.php @@ -0,0 +1,351 @@ +wait($promise); + } + + /** + * Same as executeQuery(), but requires PromiseAdapter and always returns a Promise. + * Useful for Async PHP platforms. + * + * @param string|DocumentNode $source + * @param mixed $rootValue + * @param mixed $context + * @param mixed[]|null $variableValues + * @param ValidationRule[]|null $validationRules + * + * @api + */ + public static function promiseToExecute( + PromiseAdapter $promiseAdapter, + SchemaType $schema, + $source, + $rootValue = null, + $context = null, + $variableValues = null, + ?string $operationName = null, + ?callable $fieldResolver = null, + ?array $validationRules = null + ) : Promise { + try { + if ($source instanceof DocumentNode) { + $documentNode = $source; + } else { + $documentNode = Parser::parse(new Source($source ?: '', 'GraphQL')); + } + + // FIXME + if (empty($validationRules)) { + /** @var QueryComplexity $queryComplexity */ + $queryComplexity = DocumentValidator::getRule(QueryComplexity::class); + $queryComplexity->setRawVariableValues($variableValues); + } else { + foreach ($validationRules as $rule) { + if (! ($rule instanceof QueryComplexity)) { + continue; + } + + $rule->setRawVariableValues($variableValues); + } + } + + $validationErrors = DocumentValidator::validate($schema, $documentNode, $validationRules); + + if (! empty($validationErrors)) { + return $promiseAdapter->createFulfilled( + new ExecutionResult(null, $validationErrors) + ); + } + + return Executor::promiseToExecute( + $promiseAdapter, + $schema, + $documentNode, + $rootValue, + $context, + $variableValues, + $operationName, + $fieldResolver + ); + } catch (Error $e) { + return $promiseAdapter->createFulfilled( + new ExecutionResult(null, [$e]) + ); + } + } + + /** + * @deprecated Use executeQuery()->toArray() instead + * + * @param string|DocumentNode $source + * @param mixed $rootValue + * @param mixed $contextValue + * @param mixed[]|null $variableValues + * + * @return Promise|mixed[] + */ + public static function execute( + SchemaType $schema, + $source, + $rootValue = null, + $contextValue = null, + $variableValues = null, + ?string $operationName = null + ) { + trigger_error( + __METHOD__ . ' is deprecated, use GraphQL::executeQuery()->toArray() as a quick replacement', + E_USER_DEPRECATED + ); + + $promiseAdapter = Executor::getPromiseAdapter(); + $result = self::promiseToExecute( + $promiseAdapter, + $schema, + $source, + $rootValue, + $contextValue, + $variableValues, + $operationName + ); + + if ($promiseAdapter instanceof SyncPromiseAdapter) { + $result = $promiseAdapter->wait($result)->toArray(); + } else { + $result = $result->then(static function (ExecutionResult $r) { + return $r->toArray(); + }); + } + + return $result; + } + + /** + * @deprecated renamed to executeQuery() + * + * @param string|DocumentNode $source + * @param mixed $rootValue + * @param mixed $contextValue + * @param mixed[]|null $variableValues + * + * @return ExecutionResult|Promise + */ + public static function executeAndReturnResult( + SchemaType $schema, + $source, + $rootValue = null, + $contextValue = null, + $variableValues = null, + ?string $operationName = null + ) { + trigger_error( + __METHOD__ . ' is deprecated, use GraphQL::executeQuery() as a quick replacement', + E_USER_DEPRECATED + ); + + $promiseAdapter = Executor::getPromiseAdapter(); + $result = self::promiseToExecute( + $promiseAdapter, + $schema, + $source, + $rootValue, + $contextValue, + $variableValues, + $operationName + ); + + if ($promiseAdapter instanceof SyncPromiseAdapter) { + $result = $promiseAdapter->wait($result); + } + + return $result; + } + + /** + * Returns directives defined in GraphQL spec + * + * @return Directive[] + * + * @api + */ + public static function getStandardDirectives() : array + { + return array_values(Directive::getInternalDirectives()); + } + + /** + * Returns types defined in GraphQL spec + * + * @return Type[] + * + * @api + */ + public static function getStandardTypes() : array + { + return array_values(Type::getStandardTypes()); + } + + /** + * Replaces standard types with types from this list (matching by name) + * Standard types not listed here remain untouched. + * + * @param Type[] $types + * + * @api + */ + public static function overrideStandardTypes(array $types) + { + Type::overrideStandardTypes($types); + } + + /** + * Returns standard validation rules implementing GraphQL spec + * + * @return ValidationRule[] + * + * @api + */ + public static function getStandardValidationRules() : array + { + return array_values(DocumentValidator::defaultRules()); + } + + /** + * Set default resolver implementation + * + * @api + */ + public static function setDefaultFieldResolver(callable $fn) : void + { + Executor::setDefaultFieldResolver($fn); + } + + public static function setPromiseAdapter(?PromiseAdapter $promiseAdapter = null) : void + { + Executor::setPromiseAdapter($promiseAdapter); + } + + /** + * Experimental: Switch to the new executor + */ + public static function useExperimentalExecutor() + { + Executor::setImplementationFactory([CoroutineExecutor::class, 'create']); + } + + /** + * Experimental: Switch back to the default executor + */ + public static function useReferenceExecutor() + { + Executor::setImplementationFactory([ReferenceExecutor::class, 'create']); + } + + /** + * Returns directives defined in GraphQL spec + * + * @deprecated Renamed to getStandardDirectives + * + * @return Directive[] + */ + public static function getInternalDirectives() : array + { + return self::getStandardDirectives(); + } +} diff --git a/vendor/webonyx/graphql-php/src/Language/AST/ArgumentNode.php b/vendor/webonyx/graphql-php/src/Language/AST/ArgumentNode.php new file mode 100644 index 0000000..545a855 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Language/AST/ArgumentNode.php @@ -0,0 +1,17 @@ +start = $start; + $tmp->end = $end; + + return $tmp; + } + + public function __construct(?Token $startToken = null, ?Token $endToken = null, ?Source $source = null) + { + $this->startToken = $startToken; + $this->endToken = $endToken; + $this->source = $source; + + if (! $startToken || ! $endToken) { + return; + } + + $this->start = $startToken->start; + $this->end = $endToken->end; + } +} diff --git a/vendor/webonyx/graphql-php/src/Language/AST/NameNode.php b/vendor/webonyx/graphql-php/src/Language/AST/NameNode.php new file mode 100644 index 0000000..ad91196 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Language/AST/NameNode.php @@ -0,0 +1,14 @@ +cloneValue($this); + } + + /** + * @param string|NodeList|Location|Node|(Node|NodeList|Location)[] $value + * + * @return string|NodeList|Location|Node + */ + private function cloneValue($value) + { + if (is_array($value)) { + $cloned = []; + foreach ($value as $key => $arrValue) { + $cloned[$key] = $this->cloneValue($arrValue); + } + } elseif ($value instanceof self) { + $cloned = clone $value; + foreach (get_object_vars($cloned) as $prop => $propValue) { + $cloned->{$prop} = $this->cloneValue($propValue); + } + } else { + $cloned = $value; + } + + return $cloned; + } + + /** + * @return string + */ + public function __toString() + { + $tmp = $this->toArray(true); + + return (string) json_encode($tmp); + } + + /** + * @param bool $recursive + * + * @return mixed[] + */ + public function toArray($recursive = false) + { + if ($recursive) { + return $this->recursiveToArray($this); + } + + $tmp = (array) $this; + + if ($this->loc) { + $tmp['loc'] = [ + 'start' => $this->loc->start, + 'end' => $this->loc->end, + ]; + } + + return $tmp; + } + + /** + * @return mixed[] + */ + private function recursiveToArray(Node $node) + { + $result = [ + 'kind' => $node->kind, + ]; + + if ($node->loc) { + $result['loc'] = [ + 'start' => $node->loc->start, + 'end' => $node->loc->end, + ]; + } + + foreach (get_object_vars($node) as $prop => $propValue) { + if (isset($result[$prop])) { + continue; + } + + if ($propValue === null) { + continue; + } + + if (is_array($propValue) || $propValue instanceof NodeList) { + $tmp = []; + foreach ($propValue as $tmp1) { + $tmp[] = $tmp1 instanceof Node ? $this->recursiveToArray($tmp1) : (array) $tmp1; + } + } elseif ($propValue instanceof Node) { + $tmp = $this->recursiveToArray($propValue); + } elseif (is_scalar($propValue) || $propValue === null) { + $tmp = $propValue; + } else { + $tmp = null; + } + + $result[$prop] = $tmp; + } + + return $result; + } +} diff --git a/vendor/webonyx/graphql-php/src/Language/AST/NodeKind.php b/vendor/webonyx/graphql-php/src/Language/AST/NodeKind.php new file mode 100644 index 0000000..7c0f300 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Language/AST/NodeKind.php @@ -0,0 +1,138 @@ + NameNode::class, + + // Document + self::DOCUMENT => DocumentNode::class, + self::OPERATION_DEFINITION => OperationDefinitionNode::class, + self::VARIABLE_DEFINITION => VariableDefinitionNode::class, + self::VARIABLE => VariableNode::class, + self::SELECTION_SET => SelectionSetNode::class, + self::FIELD => FieldNode::class, + self::ARGUMENT => ArgumentNode::class, + + // Fragments + self::FRAGMENT_SPREAD => FragmentSpreadNode::class, + self::INLINE_FRAGMENT => InlineFragmentNode::class, + self::FRAGMENT_DEFINITION => FragmentDefinitionNode::class, + + // Values + self::INT => IntValueNode::class, + self::FLOAT => FloatValueNode::class, + self::STRING => StringValueNode::class, + self::BOOLEAN => BooleanValueNode::class, + self::ENUM => EnumValueNode::class, + self::NULL => NullValueNode::class, + self::LST => ListValueNode::class, + self::OBJECT => ObjectValueNode::class, + self::OBJECT_FIELD => ObjectFieldNode::class, + + // Directives + self::DIRECTIVE => DirectiveNode::class, + + // Types + self::NAMED_TYPE => NamedTypeNode::class, + self::LIST_TYPE => ListTypeNode::class, + self::NON_NULL_TYPE => NonNullTypeNode::class, + + // Type System Definitions + self::SCHEMA_DEFINITION => SchemaDefinitionNode::class, + self::OPERATION_TYPE_DEFINITION => OperationTypeDefinitionNode::class, + + // Type Definitions + self::SCALAR_TYPE_DEFINITION => ScalarTypeDefinitionNode::class, + self::OBJECT_TYPE_DEFINITION => ObjectTypeDefinitionNode::class, + self::FIELD_DEFINITION => FieldDefinitionNode::class, + self::INPUT_VALUE_DEFINITION => InputValueDefinitionNode::class, + self::INTERFACE_TYPE_DEFINITION => InterfaceTypeDefinitionNode::class, + self::UNION_TYPE_DEFINITION => UnionTypeDefinitionNode::class, + self::ENUM_TYPE_DEFINITION => EnumTypeDefinitionNode::class, + self::ENUM_VALUE_DEFINITION => EnumValueDefinitionNode::class, + self::INPUT_OBJECT_TYPE_DEFINITION => InputObjectTypeDefinitionNode::class, + + // Type Extensions + self::SCALAR_TYPE_EXTENSION => ScalarTypeExtensionNode::class, + self::OBJECT_TYPE_EXTENSION => ObjectTypeExtensionNode::class, + self::INTERFACE_TYPE_EXTENSION => InterfaceTypeExtensionNode::class, + self::UNION_TYPE_EXTENSION => UnionTypeExtensionNode::class, + self::ENUM_TYPE_EXTENSION => EnumTypeExtensionNode::class, + self::INPUT_OBJECT_TYPE_EXTENSION => InputObjectTypeExtensionNode::class, + + // Directive Definitions + self::DIRECTIVE_DEFINITION => DirectiveDefinitionNode::class, + ]; +} diff --git a/vendor/webonyx/graphql-php/src/Language/AST/NodeList.php b/vendor/webonyx/graphql-php/src/Language/AST/NodeList.php new file mode 100644 index 0000000..648f68a --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Language/AST/NodeList.php @@ -0,0 +1,129 @@ +nodes = $nodes; + } + + /** + * @param mixed $offset + * + * @return bool + */ + public function offsetExists($offset) + { + return isset($this->nodes[$offset]); + } + + /** + * @param mixed $offset + * + * @return mixed + */ + public function offsetGet($offset) + { + $item = $this->nodes[$offset]; + + if (is_array($item) && isset($item['kind'])) { + $this->nodes[$offset] = $item = AST::fromArray($item); + } + + return $item; + } + + /** + * @param mixed $offset + * @param mixed $value + */ + public function offsetSet($offset, $value) + { + if (is_array($value) && isset($value['kind'])) { + $value = AST::fromArray($value); + } + $this->nodes[$offset] = $value; + } + + /** + * @param mixed $offset + */ + public function offsetUnset($offset) + { + unset($this->nodes[$offset]); + } + + /** + * @param int $offset + * @param int $length + * @param mixed $replacement + * + * @return NodeList + */ + public function splice($offset, $length, $replacement = null) + { + return new NodeList(array_splice($this->nodes, $offset, $length, $replacement)); + } + + /** + * @param NodeList|Node[] $list + * + * @return NodeList + */ + public function merge($list) + { + if ($list instanceof self) { + $list = $list->nodes; + } + + return new NodeList(array_merge($this->nodes, $list)); + } + + /** + * @return Generator + */ + public function getIterator() + { + foreach ($this->nodes as $key => $_) { + yield $this->offsetGet($key); + } + } + + /** + * @return int + */ + public function count() + { + return count($this->nodes); + } +} diff --git a/vendor/webonyx/graphql-php/src/Language/AST/NonNullTypeNode.php b/vendor/webonyx/graphql-php/src/Language/AST/NonNullTypeNode.php new file mode 100644 index 0000000..f8b97c0 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Language/AST/NonNullTypeNode.php @@ -0,0 +1,14 @@ + self::QUERY, + self::MUTATION => self::MUTATION, + self::SUBSCRIPTION => self::SUBSCRIPTION, + self::FIELD => self::FIELD, + self::FRAGMENT_DEFINITION => self::FRAGMENT_DEFINITION, + self::FRAGMENT_SPREAD => self::FRAGMENT_SPREAD, + self::INLINE_FRAGMENT => self::INLINE_FRAGMENT, + self::SCHEMA => self::SCHEMA, + self::SCALAR => self::SCALAR, + self::OBJECT => self::OBJECT, + self::FIELD_DEFINITION => self::FIELD_DEFINITION, + self::ARGUMENT_DEFINITION => self::ARGUMENT_DEFINITION, + self::IFACE => self::IFACE, + self::UNION => self::UNION, + self::ENUM => self::ENUM, + self::ENUM_VALUE => self::ENUM_VALUE, + self::INPUT_OBJECT => self::INPUT_OBJECT, + self::INPUT_FIELD_DEFINITION => self::INPUT_FIELD_DEFINITION, + ]; + + /** + * @param string $name + * + * @return bool + */ + public static function has($name) + { + return isset(self::$locations[$name]); + } +} diff --git a/vendor/webonyx/graphql-php/src/Language/Lexer.php b/vendor/webonyx/graphql-php/src/Language/Lexer.php new file mode 100644 index 0000000..3aad4dd --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Language/Lexer.php @@ -0,0 +1,804 @@ +source = $source; + $this->options = $options; + $this->lastToken = $startOfFileToken; + $this->token = $startOfFileToken; + $this->line = 1; + $this->lineStart = 0; + $this->position = $this->byteStreamPosition = 0; + } + + /** + * @return Token + */ + public function advance() + { + $this->lastToken = $this->token; + + return $this->token = $this->lookahead(); + } + + public function lookahead() + { + $token = $this->token; + if ($token->kind !== Token::EOF) { + do { + $token = $token->next ?: ($token->next = $this->readToken($token)); + } while ($token->kind === Token::COMMENT); + } + + return $token; + } + + /** + * @return Token + * + * @throws SyntaxError + */ + private function readToken(Token $prev) + { + $bodyLength = $this->source->length; + + $this->positionAfterWhitespace(); + $position = $this->position; + + $line = $this->line; + $col = 1 + $position - $this->lineStart; + + if ($position >= $bodyLength) { + return new Token(Token::EOF, $bodyLength, $bodyLength, $line, $col, $prev); + } + + // Read next char and advance string cursor: + [, $code, $bytes] = $this->readChar(true); + + switch ($code) { + case self::TOKEN_BANG: + return new Token(Token::BANG, $position, $position + 1, $line, $col, $prev); + case self::TOKEN_HASH: // # + $this->moveStringCursor(-1, -1 * $bytes); + + return $this->readComment($line, $col, $prev); + case self::TOKEN_DOLLAR: + return new Token(Token::DOLLAR, $position, $position + 1, $line, $col, $prev); + case self::TOKEN_AMP: + return new Token(Token::AMP, $position, $position + 1, $line, $col, $prev); + case self::TOKEN_PAREN_L: + return new Token(Token::PAREN_L, $position, $position + 1, $line, $col, $prev); + case self::TOKEN_PAREN_R: + return new Token(Token::PAREN_R, $position, $position + 1, $line, $col, $prev); + case self::TOKEN_DOT: // . + [, $charCode1] = $this->readChar(true); + [, $charCode2] = $this->readChar(true); + + if ($charCode1 === self::TOKEN_DOT && $charCode2 === self::TOKEN_DOT) { + return new Token(Token::SPREAD, $position, $position + 3, $line, $col, $prev); + } + break; + case self::TOKEN_COLON: + return new Token(Token::COLON, $position, $position + 1, $line, $col, $prev); + case self::TOKEN_EQUALS: + return new Token(Token::EQUALS, $position, $position + 1, $line, $col, $prev); + case self::TOKEN_AT: + return new Token(Token::AT, $position, $position + 1, $line, $col, $prev); + case self::TOKEN_BRACKET_L: + return new Token(Token::BRACKET_L, $position, $position + 1, $line, $col, $prev); + case self::TOKEN_BRACKET_R: + return new Token(Token::BRACKET_R, $position, $position + 1, $line, $col, $prev); + case self::TOKEN_BRACE_L: + return new Token(Token::BRACE_L, $position, $position + 1, $line, $col, $prev); + case self::TOKEN_PIPE: + return new Token(Token::PIPE, $position, $position + 1, $line, $col, $prev); + case self::TOKEN_BRACE_R: + return new Token(Token::BRACE_R, $position, $position + 1, $line, $col, $prev); + + // A-Z + case 65: + case 66: + case 67: + case 68: + case 69: + case 70: + case 71: + case 72: + case 73: + case 74: + case 75: + case 76: + case 77: + case 78: + case 79: + case 80: + case 81: + case 82: + case 83: + case 84: + case 85: + case 86: + case 87: + case 88: + case 89: + case 90: + // _ + case 95: + // a-z + case 97: + case 98: + case 99: + case 100: + case 101: + case 102: + case 103: + case 104: + case 105: + case 106: + case 107: + case 108: + case 109: + case 110: + case 111: + case 112: + case 113: + case 114: + case 115: + case 116: + case 117: + case 118: + case 119: + case 120: + case 121: + case 122: + return $this->moveStringCursor(-1, -1 * $bytes) + ->readName($line, $col, $prev); + + // - + case 45: + // 0-9 + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + return $this->moveStringCursor(-1, -1 * $bytes) + ->readNumber($line, $col, $prev); + + // " + case 34: + [, $nextCode] = $this->readChar(); + [, $nextNextCode] = $this->moveStringCursor(1, 1)->readChar(); + + if ($nextCode === 34 && $nextNextCode === 34) { + return $this->moveStringCursor(-2, (-1 * $bytes) - 1) + ->readBlockString($line, $col, $prev); + } + + return $this->moveStringCursor(-2, (-1 * $bytes) - 1) + ->readString($line, $col, $prev); + } + + throw new SyntaxError( + $this->source, + $position, + $this->unexpectedCharacterMessage($code) + ); + } + + private function unexpectedCharacterMessage($code) + { + // SourceCharacter + if ($code < 0x0020 && $code !== 0x0009 && $code !== 0x000A && $code !== 0x000D) { + return 'Cannot contain the invalid character ' . Utils::printCharCode($code); + } + + if ($code === 39) { + return "Unexpected single quote character ('), did you mean to use " . + 'a double quote (")?'; + } + + return 'Cannot parse the unexpected character ' . Utils::printCharCode($code) . '.'; + } + + /** + * Reads an alphanumeric + underscore name from the source. + * + * [_A-Za-z][_0-9A-Za-z]* + * + * @param int $line + * @param int $col + * + * @return Token + */ + private function readName($line, $col, Token $prev) + { + $value = ''; + $start = $this->position; + [$char, $code] = $this->readChar(); + + while ($code && ( + $code === 95 || // _ + $code >= 48 && $code <= 57 || // 0-9 + $code >= 65 && $code <= 90 || // A-Z + $code >= 97 && $code <= 122 // a-z + )) { + $value .= $char; + [$char, $code] = $this->moveStringCursor(1, 1)->readChar(); + } + + return new Token( + Token::NAME, + $start, + $this->position, + $line, + $col, + $prev, + $value + ); + } + + /** + * Reads a number token from the source file, either a float + * or an int depending on whether a decimal point appears. + * + * Int: -?(0|[1-9][0-9]*) + * Float: -?(0|[1-9][0-9]*)(\.[0-9]+)?((E|e)(+|-)?[0-9]+)? + * + * @param int $line + * @param int $col + * + * @return Token + * + * @throws SyntaxError + */ + private function readNumber($line, $col, Token $prev) + { + $value = ''; + $start = $this->position; + [$char, $code] = $this->readChar(); + + $isFloat = false; + + if ($code === 45) { // - + $value .= $char; + [$char, $code] = $this->moveStringCursor(1, 1)->readChar(); + } + + // guard against leading zero's + if ($code === 48) { // 0 + $value .= $char; + [$char, $code] = $this->moveStringCursor(1, 1)->readChar(); + + if ($code >= 48 && $code <= 57) { + throw new SyntaxError( + $this->source, + $this->position, + 'Invalid number, unexpected digit after 0: ' . Utils::printCharCode($code) + ); + } + } else { + $value .= $this->readDigits(); + [$char, $code] = $this->readChar(); + } + + if ($code === 46) { // . + $isFloat = true; + $this->moveStringCursor(1, 1); + + $value .= $char; + $value .= $this->readDigits(); + [$char, $code] = $this->readChar(); + } + + if ($code === 69 || $code === 101) { // E e + $isFloat = true; + $value .= $char; + [$char, $code] = $this->moveStringCursor(1, 1)->readChar(); + + if ($code === 43 || $code === 45) { // + - + $value .= $char; + $this->moveStringCursor(1, 1); + } + $value .= $this->readDigits(); + } + + return new Token( + $isFloat ? Token::FLOAT : Token::INT, + $start, + $this->position, + $line, + $col, + $prev, + $value + ); + } + + /** + * Returns string with all digits + changes current string cursor position to point to the first char after digits + */ + private function readDigits() + { + [$char, $code] = $this->readChar(); + + if ($code >= 48 && $code <= 57) { // 0 - 9 + $value = ''; + + do { + $value .= $char; + [$char, $code] = $this->moveStringCursor(1, 1)->readChar(); + } while ($code >= 48 && $code <= 57); // 0 - 9 + + return $value; + } + + if ($this->position > $this->source->length - 1) { + $code = null; + } + + throw new SyntaxError( + $this->source, + $this->position, + 'Invalid number, expected digit but got: ' . Utils::printCharCode($code) + ); + } + + /** + * @param int $line + * @param int $col + * + * @return Token + * + * @throws SyntaxError + */ + private function readString($line, $col, Token $prev) + { + $start = $this->position; + + // Skip leading quote and read first string char: + [$char, $code, $bytes] = $this->moveStringCursor(1, 1)->readChar(); + + $chunk = ''; + $value = ''; + + while ($code !== null && + // not LineTerminator + $code !== 10 && $code !== 13 + ) { + // Closing Quote (") + if ($code === 34) { + $value .= $chunk; + + // Skip quote + $this->moveStringCursor(1, 1); + + return new Token( + Token::STRING, + $start, + $this->position, + $line, + $col, + $prev, + $value + ); + } + + $this->assertValidStringCharacterCode($code, $this->position); + $this->moveStringCursor(1, $bytes); + + if ($code === 92) { // \ + $value .= $chunk; + [, $code] = $this->readChar(true); + + switch ($code) { + case 34: + $value .= '"'; + break; + case 47: + $value .= '/'; + break; + case 92: + $value .= '\\'; + break; + case 98: + $value .= chr(8); + break; // \b (backspace) + case 102: + $value .= "\f"; + break; + case 110: + $value .= "\n"; + break; + case 114: + $value .= "\r"; + break; + case 116: + $value .= "\t"; + break; + case 117: + $position = $this->position; + [$hex] = $this->readChars(4, true); + if (! preg_match('/[0-9a-fA-F]{4}/', $hex)) { + throw new SyntaxError( + $this->source, + $position - 1, + 'Invalid character escape sequence: \\u' . $hex + ); + } + $code = hexdec($hex); + $this->assertValidStringCharacterCode($code, $position - 2); + $value .= Utils::chr($code); + break; + default: + throw new SyntaxError( + $this->source, + $this->position - 1, + 'Invalid character escape sequence: \\' . Utils::chr($code) + ); + } + $chunk = ''; + } else { + $chunk .= $char; + } + + [$char, $code, $bytes] = $this->readChar(); + } + + throw new SyntaxError( + $this->source, + $this->position, + 'Unterminated string.' + ); + } + + /** + * Reads a block string token from the source file. + * + * """("?"?(\\"""|\\(?!=""")|[^"\\]))*""" + */ + private function readBlockString($line, $col, Token $prev) + { + $start = $this->position; + + // Skip leading quotes and read first string char: + [$char, $code, $bytes] = $this->moveStringCursor(3, 3)->readChar(); + + $chunk = ''; + $value = ''; + + while ($code !== null) { + // Closing Triple-Quote (""") + if ($code === 34) { + // Move 2 quotes + [, $nextCode] = $this->moveStringCursor(1, 1)->readChar(); + [, $nextNextCode] = $this->moveStringCursor(1, 1)->readChar(); + + if ($nextCode === 34 && $nextNextCode === 34) { + $value .= $chunk; + + $this->moveStringCursor(1, 1); + + return new Token( + Token::BLOCK_STRING, + $start, + $this->position, + $line, + $col, + $prev, + BlockString::value($value) + ); + } + + // move cursor back to before the first quote + $this->moveStringCursor(-2, -2); + } + + $this->assertValidBlockStringCharacterCode($code, $this->position); + $this->moveStringCursor(1, $bytes); + + [, $nextCode] = $this->readChar(); + [, $nextNextCode] = $this->moveStringCursor(1, 1)->readChar(); + [, $nextNextNextCode] = $this->moveStringCursor(1, 1)->readChar(); + + // Escape Triple-Quote (\""") + if ($code === 92 && + $nextCode === 34 && + $nextNextCode === 34 && + $nextNextNextCode === 34 + ) { + $this->moveStringCursor(1, 1); + $value .= $chunk . '"""'; + $chunk = ''; + } else { + $this->moveStringCursor(-2, -2); + $chunk .= $char; + } + + [$char, $code, $bytes] = $this->readChar(); + } + + throw new SyntaxError( + $this->source, + $this->position, + 'Unterminated string.' + ); + } + + private function assertValidStringCharacterCode($code, $position) + { + // SourceCharacter + if ($code < 0x0020 && $code !== 0x0009) { + throw new SyntaxError( + $this->source, + $position, + 'Invalid character within String: ' . Utils::printCharCode($code) + ); + } + } + + private function assertValidBlockStringCharacterCode($code, $position) + { + // SourceCharacter + if ($code < 0x0020 && $code !== 0x0009 && $code !== 0x000A && $code !== 0x000D) { + throw new SyntaxError( + $this->source, + $position, + 'Invalid character within String: ' . Utils::printCharCode($code) + ); + } + } + + /** + * Reads from body starting at startPosition until it finds a non-whitespace + * or commented character, then places cursor to the position of that character. + */ + private function positionAfterWhitespace() + { + while ($this->position < $this->source->length) { + [, $code, $bytes] = $this->readChar(); + + // Skip whitespace + // tab | space | comma | BOM + if ($code === 9 || $code === 32 || $code === 44 || $code === 0xFEFF) { + $this->moveStringCursor(1, $bytes); + } elseif ($code === 10) { // new line + $this->moveStringCursor(1, $bytes); + $this->line++; + $this->lineStart = $this->position; + } elseif ($code === 13) { // carriage return + [, $nextCode, $nextBytes] = $this->moveStringCursor(1, $bytes)->readChar(); + + if ($nextCode === 10) { // lf after cr + $this->moveStringCursor(1, $nextBytes); + } + $this->line++; + $this->lineStart = $this->position; + } else { + break; + } + } + } + + /** + * Reads a comment token from the source file. + * + * #[\u0009\u0020-\uFFFF]* + * + * @param int $line + * @param int $col + * + * @return Token + */ + private function readComment($line, $col, Token $prev) + { + $start = $this->position; + $value = ''; + $bytes = 1; + + do { + [$char, $code, $bytes] = $this->moveStringCursor(1, $bytes)->readChar(); + $value .= $char; + } while ($code && + // SourceCharacter but not LineTerminator + ($code > 0x001F || $code === 0x0009) + ); + + return new Token( + Token::COMMENT, + $start, + $this->position, + $line, + $col, + $prev, + $value + ); + } + + /** + * Reads next UTF8Character from the byte stream, starting from $byteStreamPosition. + * + * @param bool $advance + * @param int $byteStreamPosition + * + * @return (string|int)[] + */ + private function readChar($advance = false, $byteStreamPosition = null) + { + if ($byteStreamPosition === null) { + $byteStreamPosition = $this->byteStreamPosition; + } + + $code = null; + $utf8char = ''; + $bytes = 0; + $positionOffset = 0; + + if (isset($this->source->body[$byteStreamPosition])) { + $ord = ord($this->source->body[$byteStreamPosition]); + + if ($ord < 128) { + $bytes = 1; + } elseif ($ord < 224) { + $bytes = 2; + } elseif ($ord < 240) { + $bytes = 3; + } else { + $bytes = 4; + } + + $utf8char = ''; + for ($pos = $byteStreamPosition; $pos < $byteStreamPosition + $bytes; $pos++) { + $utf8char .= $this->source->body[$pos]; + } + $positionOffset = 1; + $code = $bytes === 1 ? $ord : Utils::ord($utf8char); + } + + if ($advance) { + $this->moveStringCursor($positionOffset, $bytes); + } + + return [$utf8char, $code, $bytes]; + } + + /** + * Reads next $numberOfChars UTF8 characters from the byte stream, starting from $byteStreamPosition. + * + * @param int $charCount + * @param bool $advance + * @param null $byteStreamPosition + * + * @return (string|int)[] + */ + private function readChars($charCount, $advance = false, $byteStreamPosition = null) + { + $result = ''; + $totalBytes = 0; + $byteOffset = $byteStreamPosition ?: $this->byteStreamPosition; + + for ($i = 0; $i < $charCount; $i++) { + [$char, $code, $bytes] = $this->readChar(false, $byteOffset); + $totalBytes += $bytes; + $byteOffset += $bytes; + $result .= $char; + } + if ($advance) { + $this->moveStringCursor($charCount, $totalBytes); + } + + return [$result, $totalBytes]; + } + + /** + * Moves internal string cursor position + * + * @param int $positionOffset + * @param int $byteStreamOffset + * + * @return self + */ + private function moveStringCursor($positionOffset, $byteStreamOffset) + { + $this->position += $positionOffset; + $this->byteStreamPosition += $byteStreamOffset; + + return $this; + } +} diff --git a/vendor/webonyx/graphql-php/src/Language/Parser.php b/vendor/webonyx/graphql-php/src/Language/Parser.php new file mode 100644 index 0000000..f5c9280 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Language/Parser.php @@ -0,0 +1,1786 @@ +parseDocument(); + } + + /** + * Given a string containing a GraphQL value (ex. `[42]`), parse the AST for + * that value. + * Throws `GraphQL\Error\SyntaxError` if a syntax error is encountered. + * + * This is useful within tools that operate upon GraphQL Values directly and + * in isolation of complete GraphQL documents. + * + * Consider providing the results to the utility function: `GraphQL\Utils\AST::valueFromAST()`. + * + * @param Source|string $source + * @param bool[] $options + * + * @return BooleanValueNode|EnumValueNode|FloatValueNode|IntValueNode|ListValueNode|ObjectValueNode|StringValueNode|VariableNode + * + * @api + */ + public static function parseValue($source, array $options = []) + { + $sourceObj = $source instanceof Source ? $source : new Source($source); + $parser = new Parser($sourceObj, $options); + $parser->expect(Token::SOF); + $value = $parser->parseValueLiteral(false); + $parser->expect(Token::EOF); + + return $value; + } + + /** + * Given a string containing a GraphQL Type (ex. `[Int!]`), parse the AST for + * that type. + * Throws `GraphQL\Error\SyntaxError` if a syntax error is encountered. + * + * This is useful within tools that operate upon GraphQL Types directly and + * in isolation of complete GraphQL documents. + * + * Consider providing the results to the utility function: `GraphQL\Utils\AST::typeFromAST()`. + * + * @param Source|string $source + * @param bool[] $options + * + * @return ListTypeNode|NameNode|NonNullTypeNode + * + * @api + */ + public static function parseType($source, array $options = []) + { + $sourceObj = $source instanceof Source ? $source : new Source($source); + $parser = new Parser($sourceObj, $options); + $parser->expect(Token::SOF); + $type = $parser->parseTypeReference(); + $parser->expect(Token::EOF); + + return $type; + } + + /** @var Lexer */ + private $lexer; + + /** + * @param bool[] $options + */ + public function __construct(Source $source, array $options = []) + { + $this->lexer = new Lexer($source, $options); + } + + /** + * Returns a location object, used to identify the place in + * the source that created a given parsed object. + * + * @return Location|null + */ + private function loc(Token $startToken) + { + if (empty($this->lexer->options['noLocation'])) { + return new Location($startToken, $this->lexer->lastToken, $this->lexer->source); + } + + return null; + } + + /** + * Determines if the next token is of a given kind + * + * @param string $kind + * + * @return bool + */ + private function peek($kind) + { + return $this->lexer->token->kind === $kind; + } + + /** + * If the next token is of the given kind, return true after advancing + * the parser. Otherwise, do not change the parser state and return false. + * + * @param string $kind + * + * @return bool + */ + private function skip($kind) + { + $match = $this->lexer->token->kind === $kind; + + if ($match) { + $this->lexer->advance(); + } + + return $match; + } + + /** + * If the next token is of the given kind, return that token after advancing + * the parser. Otherwise, do not change the parser state and return false. + * + * @param string $kind + * + * @return Token + * + * @throws SyntaxError + */ + private function expect($kind) + { + $token = $this->lexer->token; + + if ($token->kind === $kind) { + $this->lexer->advance(); + + return $token; + } + + throw new SyntaxError( + $this->lexer->source, + $token->start, + sprintf('Expected %s, found %s', $kind, $token->getDescription()) + ); + } + + /** + * If the next token is a keyword with the given value, return that token after + * advancing the parser. Otherwise, do not change the parser state and return + * false. + * + * @param string $value + * + * @return Token + * + * @throws SyntaxError + */ + private function expectKeyword($value) + { + $token = $this->lexer->token; + + if ($token->kind === Token::NAME && $token->value === $value) { + $this->lexer->advance(); + + return $token; + } + throw new SyntaxError( + $this->lexer->source, + $token->start, + 'Expected "' . $value . '", found ' . $token->getDescription() + ); + } + + /** + * @return SyntaxError + */ + private function unexpected(?Token $atToken = null) + { + $token = $atToken ?: $this->lexer->token; + + return new SyntaxError($this->lexer->source, $token->start, 'Unexpected ' . $token->getDescription()); + } + + /** + * Returns a possibly empty list of parse nodes, determined by + * the parseFn. This list begins with a lex token of openKind + * and ends with a lex token of closeKind. Advances the parser + * to the next lex token after the closing token. + * + * @param string $openKind + * @param callable $parseFn + * @param string $closeKind + * + * @return NodeList + * + * @throws SyntaxError + */ + private function any($openKind, $parseFn, $closeKind) + { + $this->expect($openKind); + + $nodes = []; + while (! $this->skip($closeKind)) { + $nodes[] = $parseFn($this); + } + + return new NodeList($nodes); + } + + /** + * Returns a non-empty list of parse nodes, determined by + * the parseFn. This list begins with a lex token of openKind + * and ends with a lex token of closeKind. Advances the parser + * to the next lex token after the closing token. + * + * @param string $openKind + * @param callable $parseFn + * @param string $closeKind + * + * @return NodeList + * + * @throws SyntaxError + */ + private function many($openKind, $parseFn, $closeKind) + { + $this->expect($openKind); + + $nodes = [$parseFn($this)]; + while (! $this->skip($closeKind)) { + $nodes[] = $parseFn($this); + } + + return new NodeList($nodes); + } + + /** + * Converts a name lex token into a name parse node. + * + * @return NameNode + * + * @throws SyntaxError + */ + private function parseName() + { + $token = $this->expect(Token::NAME); + + return new NameNode([ + 'value' => $token->value, + 'loc' => $this->loc($token), + ]); + } + + /** + * Implements the parsing rules in the Document section. + * + * @return DocumentNode + * + * @throws SyntaxError + */ + private function parseDocument() + { + $start = $this->lexer->token; + $this->expect(Token::SOF); + + $definitions = []; + do { + $definitions[] = $this->parseDefinition(); + } while (! $this->skip(Token::EOF)); + + return new DocumentNode([ + 'definitions' => new NodeList($definitions), + 'loc' => $this->loc($start), + ]); + } + + /** + * @return ExecutableDefinitionNode|TypeSystemDefinitionNode + * + * @throws SyntaxError + */ + private function parseDefinition() + { + if ($this->peek(Token::NAME)) { + switch ($this->lexer->token->value) { + case 'query': + case 'mutation': + case 'subscription': + case 'fragment': + return $this->parseExecutableDefinition(); + + // Note: The schema definition language is an experimental addition. + case 'schema': + case 'scalar': + case 'type': + case 'interface': + case 'union': + case 'enum': + case 'input': + case 'extend': + case 'directive': + // Note: The schema definition language is an experimental addition. + return $this->parseTypeSystemDefinition(); + } + } elseif ($this->peek(Token::BRACE_L)) { + return $this->parseExecutableDefinition(); + } elseif ($this->peekDescription()) { + // Note: The schema definition language is an experimental addition. + return $this->parseTypeSystemDefinition(); + } + + throw $this->unexpected(); + } + + /** + * @return ExecutableDefinitionNode + * + * @throws SyntaxError + */ + private function parseExecutableDefinition() + { + if ($this->peek(Token::NAME)) { + switch ($this->lexer->token->value) { + case 'query': + case 'mutation': + case 'subscription': + return $this->parseOperationDefinition(); + case 'fragment': + return $this->parseFragmentDefinition(); + } + } elseif ($this->peek(Token::BRACE_L)) { + return $this->parseOperationDefinition(); + } + + throw $this->unexpected(); + } + + // Implements the parsing rules in the Operations section. + + /** + * @return OperationDefinitionNode + * + * @throws SyntaxError + */ + private function parseOperationDefinition() + { + $start = $this->lexer->token; + if ($this->peek(Token::BRACE_L)) { + return new OperationDefinitionNode([ + 'operation' => 'query', + 'name' => null, + 'variableDefinitions' => new NodeList([]), + 'directives' => new NodeList([]), + 'selectionSet' => $this->parseSelectionSet(), + 'loc' => $this->loc($start), + ]); + } + + $operation = $this->parseOperationType(); + + $name = null; + if ($this->peek(Token::NAME)) { + $name = $this->parseName(); + } + + return new OperationDefinitionNode([ + 'operation' => $operation, + 'name' => $name, + 'variableDefinitions' => $this->parseVariableDefinitions(), + 'directives' => $this->parseDirectives(false), + 'selectionSet' => $this->parseSelectionSet(), + 'loc' => $this->loc($start), + ]); + } + + /** + * @return string + * + * @throws SyntaxError + */ + private function parseOperationType() + { + $operationToken = $this->expect(Token::NAME); + switch ($operationToken->value) { + case 'query': + return 'query'; + case 'mutation': + return 'mutation'; + case 'subscription': + return 'subscription'; + } + + throw $this->unexpected($operationToken); + } + + /** + * @return VariableDefinitionNode[]|NodeList + */ + private function parseVariableDefinitions() + { + return $this->peek(Token::PAREN_L) ? + $this->many( + Token::PAREN_L, + function () { + return $this->parseVariableDefinition(); + }, + Token::PAREN_R + ) : + new NodeList([]); + } + + /** + * @return VariableDefinitionNode + * + * @throws SyntaxError + */ + private function parseVariableDefinition() + { + $start = $this->lexer->token; + $var = $this->parseVariable(); + + $this->expect(Token::COLON); + $type = $this->parseTypeReference(); + + return new VariableDefinitionNode([ + 'variable' => $var, + 'type' => $type, + 'defaultValue' => + ($this->skip(Token::EQUALS) ? $this->parseValueLiteral(true) : null), + 'loc' => $this->loc($start), + ]); + } + + /** + * @return VariableNode + * + * @throws SyntaxError + */ + private function parseVariable() + { + $start = $this->lexer->token; + $this->expect(Token::DOLLAR); + + return new VariableNode([ + 'name' => $this->parseName(), + 'loc' => $this->loc($start), + ]); + } + + /** + * @return SelectionSetNode + */ + private function parseSelectionSet() + { + $start = $this->lexer->token; + + return new SelectionSetNode( + [ + 'selections' => $this->many( + Token::BRACE_L, + function () { + return $this->parseSelection(); + }, + Token::BRACE_R + ), + 'loc' => $this->loc($start), + ] + ); + } + + /** + * Selection : + * - Field + * - FragmentSpread + * - InlineFragment + * + * @return mixed + */ + private function parseSelection() + { + return $this->peek(Token::SPREAD) ? + $this->parseFragment() : + $this->parseField(); + } + + /** + * @return FieldNode + * + * @throws SyntaxError + */ + private function parseField() + { + $start = $this->lexer->token; + $nameOrAlias = $this->parseName(); + + if ($this->skip(Token::COLON)) { + $alias = $nameOrAlias; + $name = $this->parseName(); + } else { + $alias = null; + $name = $nameOrAlias; + } + + return new FieldNode([ + 'alias' => $alias, + 'name' => $name, + 'arguments' => $this->parseArguments(false), + 'directives' => $this->parseDirectives(false), + 'selectionSet' => $this->peek(Token::BRACE_L) ? $this->parseSelectionSet() : null, + 'loc' => $this->loc($start), + ]); + } + + /** + * @param bool $isConst + * + * @return ArgumentNode[]|NodeList + * + * @throws SyntaxError + */ + private function parseArguments($isConst) + { + $parseFn = $isConst ? + function () { + return $this->parseConstArgument(); + } : + function () { + return $this->parseArgument(); + }; + + return $this->peek(Token::PAREN_L) ? + $this->many(Token::PAREN_L, $parseFn, Token::PAREN_R) : + new NodeList([]); + } + + /** + * @return ArgumentNode + * + * @throws SyntaxError + */ + private function parseArgument() + { + $start = $this->lexer->token; + $name = $this->parseName(); + + $this->expect(Token::COLON); + $value = $this->parseValueLiteral(false); + + return new ArgumentNode([ + 'name' => $name, + 'value' => $value, + 'loc' => $this->loc($start), + ]); + } + + /** + * @return ArgumentNode + * + * @throws SyntaxError + */ + private function parseConstArgument() + { + $start = $this->lexer->token; + $name = $this->parseName(); + + $this->expect(Token::COLON); + $value = $this->parseConstValue(); + + return new ArgumentNode([ + 'name' => $name, + 'value' => $value, + 'loc' => $this->loc($start), + ]); + } + + // Implements the parsing rules in the Fragments section. + + /** + * @return FragmentSpreadNode|InlineFragmentNode + * + * @throws SyntaxError + */ + private function parseFragment() + { + $start = $this->lexer->token; + $this->expect(Token::SPREAD); + + if ($this->peek(Token::NAME) && $this->lexer->token->value !== 'on') { + return new FragmentSpreadNode([ + 'name' => $this->parseFragmentName(), + 'directives' => $this->parseDirectives(false), + 'loc' => $this->loc($start), + ]); + } + + $typeCondition = null; + if ($this->lexer->token->value === 'on') { + $this->lexer->advance(); + $typeCondition = $this->parseNamedType(); + } + + return new InlineFragmentNode([ + 'typeCondition' => $typeCondition, + 'directives' => $this->parseDirectives(false), + 'selectionSet' => $this->parseSelectionSet(), + 'loc' => $this->loc($start), + ]); + } + + /** + * @return FragmentDefinitionNode + * + * @throws SyntaxError + */ + private function parseFragmentDefinition() + { + $start = $this->lexer->token; + $this->expectKeyword('fragment'); + + $name = $this->parseFragmentName(); + + // Experimental support for defining variables within fragments changes + // the grammar of FragmentDefinition: + // - fragment FragmentName VariableDefinitions? on TypeCondition Directives? SelectionSet + $variableDefinitions = null; + if (isset($this->lexer->options['experimentalFragmentVariables'])) { + $variableDefinitions = $this->parseVariableDefinitions(); + } + $this->expectKeyword('on'); + $typeCondition = $this->parseNamedType(); + + return new FragmentDefinitionNode([ + 'name' => $name, + 'variableDefinitions' => $variableDefinitions, + 'typeCondition' => $typeCondition, + 'directives' => $this->parseDirectives(false), + 'selectionSet' => $this->parseSelectionSet(), + 'loc' => $this->loc($start), + ]); + } + + /** + * @return NameNode + * + * @throws SyntaxError + */ + private function parseFragmentName() + { + if ($this->lexer->token->value === 'on') { + throw $this->unexpected(); + } + + return $this->parseName(); + } + + // Implements the parsing rules in the Values section. + + /** + * Value[Const] : + * - [~Const] Variable + * - IntValue + * - FloatValue + * - StringValue + * - BooleanValue + * - NullValue + * - EnumValue + * - ListValue[?Const] + * - ObjectValue[?Const] + * + * BooleanValue : one of `true` `false` + * + * NullValue : `null` + * + * EnumValue : Name but not `true`, `false` or `null` + * + * @param bool $isConst + * + * @return BooleanValueNode|EnumValueNode|FloatValueNode|IntValueNode|StringValueNode|VariableNode|ListValueNode|ObjectValueNode|NullValueNode + * + * @throws SyntaxError + */ + private function parseValueLiteral($isConst) + { + $token = $this->lexer->token; + switch ($token->kind) { + case Token::BRACKET_L: + return $this->parseArray($isConst); + case Token::BRACE_L: + return $this->parseObject($isConst); + case Token::INT: + $this->lexer->advance(); + + return new IntValueNode([ + 'value' => $token->value, + 'loc' => $this->loc($token), + ]); + case Token::FLOAT: + $this->lexer->advance(); + + return new FloatValueNode([ + 'value' => $token->value, + 'loc' => $this->loc($token), + ]); + case Token::STRING: + case Token::BLOCK_STRING: + return $this->parseStringLiteral(); + case Token::NAME: + if ($token->value === 'true' || $token->value === 'false') { + $this->lexer->advance(); + + return new BooleanValueNode([ + 'value' => $token->value === 'true', + 'loc' => $this->loc($token), + ]); + } + + if ($token->value === 'null') { + $this->lexer->advance(); + + return new NullValueNode([ + 'loc' => $this->loc($token), + ]); + } else { + $this->lexer->advance(); + + return new EnumValueNode([ + 'value' => $token->value, + 'loc' => $this->loc($token), + ]); + } + break; + + case Token::DOLLAR: + if (! $isConst) { + return $this->parseVariable(); + } + break; + } + throw $this->unexpected(); + } + + /** + * @return StringValueNode + */ + private function parseStringLiteral() + { + $token = $this->lexer->token; + $this->lexer->advance(); + + return new StringValueNode([ + 'value' => $token->value, + 'block' => $token->kind === Token::BLOCK_STRING, + 'loc' => $this->loc($token), + ]); + } + + /** + * @return BooleanValueNode|EnumValueNode|FloatValueNode|IntValueNode|StringValueNode|VariableNode + * + * @throws SyntaxError + */ + private function parseConstValue() + { + return $this->parseValueLiteral(true); + } + + /** + * @return BooleanValueNode|EnumValueNode|FloatValueNode|IntValueNode|ListValueNode|ObjectValueNode|StringValueNode|VariableNode + */ + private function parseVariableValue() + { + return $this->parseValueLiteral(false); + } + + /** + * @param bool $isConst + * + * @return ListValueNode + */ + private function parseArray($isConst) + { + $start = $this->lexer->token; + $parseFn = $isConst ? function () { + return $this->parseConstValue(); + } : function () { + return $this->parseVariableValue(); + }; + + return new ListValueNode( + [ + 'values' => $this->any(Token::BRACKET_L, $parseFn, Token::BRACKET_R), + 'loc' => $this->loc($start), + ] + ); + } + + /** + * @param bool $isConst + * + * @return ObjectValueNode + */ + private function parseObject($isConst) + { + $start = $this->lexer->token; + $this->expect(Token::BRACE_L); + $fields = []; + while (! $this->skip(Token::BRACE_R)) { + $fields[] = $this->parseObjectField($isConst); + } + + return new ObjectValueNode([ + 'fields' => new NodeList($fields), + 'loc' => $this->loc($start), + ]); + } + + /** + * @param bool $isConst + * + * @return ObjectFieldNode + */ + private function parseObjectField($isConst) + { + $start = $this->lexer->token; + $name = $this->parseName(); + + $this->expect(Token::COLON); + + return new ObjectFieldNode([ + 'name' => $name, + 'value' => $this->parseValueLiteral($isConst), + 'loc' => $this->loc($start), + ]); + } + + // Implements the parsing rules in the Directives section. + + /** + * @param bool $isConst + * + * @return DirectiveNode[]|NodeList + * + * @throws SyntaxError + */ + private function parseDirectives($isConst) + { + $directives = []; + while ($this->peek(Token::AT)) { + $directives[] = $this->parseDirective($isConst); + } + + return new NodeList($directives); + } + + /** + * @param bool $isConst + * + * @return DirectiveNode + * + * @throws SyntaxError + */ + private function parseDirective($isConst) + { + $start = $this->lexer->token; + $this->expect(Token::AT); + + return new DirectiveNode([ + 'name' => $this->parseName(), + 'arguments' => $this->parseArguments($isConst), + 'loc' => $this->loc($start), + ]); + } + + // Implements the parsing rules in the Types section. + + /** + * Handles the Type: TypeName, ListType, and NonNullType parsing rules. + * + * @return ListTypeNode|NameNode|NonNullTypeNode + * + * @throws SyntaxError + */ + private function parseTypeReference() + { + $start = $this->lexer->token; + + if ($this->skip(Token::BRACKET_L)) { + $type = $this->parseTypeReference(); + $this->expect(Token::BRACKET_R); + $type = new ListTypeNode([ + 'type' => $type, + 'loc' => $this->loc($start), + ]); + } else { + $type = $this->parseNamedType(); + } + if ($this->skip(Token::BANG)) { + return new NonNullTypeNode([ + 'type' => $type, + 'loc' => $this->loc($start), + ]); + } + + return $type; + } + + private function parseNamedType() + { + $start = $this->lexer->token; + + return new NamedTypeNode([ + 'name' => $this->parseName(), + 'loc' => $this->loc($start), + ]); + } + + // Implements the parsing rules in the Type Definition section. + + /** + * TypeSystemDefinition : + * - SchemaDefinition + * - TypeDefinition + * - TypeExtension + * - DirectiveDefinition + * + * TypeDefinition : + * - ScalarTypeDefinition + * - ObjectTypeDefinition + * - InterfaceTypeDefinition + * - UnionTypeDefinition + * - EnumTypeDefinition + * - InputObjectTypeDefinition + * + * @return TypeSystemDefinitionNode + * + * @throws SyntaxError + */ + private function parseTypeSystemDefinition() + { + // Many definitions begin with a description and require a lookahead. + $keywordToken = $this->peekDescription() + ? $this->lexer->lookahead() + : $this->lexer->token; + + if ($keywordToken->kind === Token::NAME) { + switch ($keywordToken->value) { + case 'schema': + return $this->parseSchemaDefinition(); + case 'scalar': + return $this->parseScalarTypeDefinition(); + case 'type': + return $this->parseObjectTypeDefinition(); + case 'interface': + return $this->parseInterfaceTypeDefinition(); + case 'union': + return $this->parseUnionTypeDefinition(); + case 'enum': + return $this->parseEnumTypeDefinition(); + case 'input': + return $this->parseInputObjectTypeDefinition(); + case 'extend': + return $this->parseTypeExtension(); + case 'directive': + return $this->parseDirectiveDefinition(); + } + } + + throw $this->unexpected($keywordToken); + } + + /** + * @return bool + */ + private function peekDescription() + { + return $this->peek(Token::STRING) || $this->peek(Token::BLOCK_STRING); + } + + /** + * @return StringValueNode|null + */ + private function parseDescription() + { + if ($this->peekDescription()) { + return $this->parseStringLiteral(); + } + } + + /** + * @return SchemaDefinitionNode + * + * @throws SyntaxError + */ + private function parseSchemaDefinition() + { + $start = $this->lexer->token; + $this->expectKeyword('schema'); + $directives = $this->parseDirectives(true); + + $operationTypes = $this->many( + Token::BRACE_L, + function () { + return $this->parseOperationTypeDefinition(); + }, + Token::BRACE_R + ); + + return new SchemaDefinitionNode([ + 'directives' => $directives, + 'operationTypes' => $operationTypes, + 'loc' => $this->loc($start), + ]); + } + + /** + * @return OperationTypeDefinitionNode + * + * @throws SyntaxError + */ + private function parseOperationTypeDefinition() + { + $start = $this->lexer->token; + $operation = $this->parseOperationType(); + $this->expect(Token::COLON); + $type = $this->parseNamedType(); + + return new OperationTypeDefinitionNode([ + 'operation' => $operation, + 'type' => $type, + 'loc' => $this->loc($start), + ]); + } + + /** + * @return ScalarTypeDefinitionNode + * + * @throws SyntaxError + */ + private function parseScalarTypeDefinition() + { + $start = $this->lexer->token; + $description = $this->parseDescription(); + $this->expectKeyword('scalar'); + $name = $this->parseName(); + $directives = $this->parseDirectives(true); + + return new ScalarTypeDefinitionNode([ + 'name' => $name, + 'directives' => $directives, + 'loc' => $this->loc($start), + 'description' => $description, + ]); + } + + /** + * @return ObjectTypeDefinitionNode + * + * @throws SyntaxError + */ + private function parseObjectTypeDefinition() + { + $start = $this->lexer->token; + $description = $this->parseDescription(); + $this->expectKeyword('type'); + $name = $this->parseName(); + $interfaces = $this->parseImplementsInterfaces(); + $directives = $this->parseDirectives(true); + $fields = $this->parseFieldsDefinition(); + + return new ObjectTypeDefinitionNode([ + 'name' => $name, + 'interfaces' => $interfaces, + 'directives' => $directives, + 'fields' => $fields, + 'loc' => $this->loc($start), + 'description' => $description, + ]); + } + + /** + * ImplementsInterfaces : + * - implements `&`? NamedType + * - ImplementsInterfaces & NamedType + * + * @return NamedTypeNode[] + */ + private function parseImplementsInterfaces() + { + $types = []; + if ($this->lexer->token->value === 'implements') { + $this->lexer->advance(); + // Optional leading ampersand + $this->skip(Token::AMP); + do { + $types[] = $this->parseNamedType(); + } while ($this->skip(Token::AMP) || + // Legacy support for the SDL? + (! empty($this->lexer->options['allowLegacySDLImplementsInterfaces']) && $this->peek(Token::NAME)) + ); + } + + return $types; + } + + /** + * @return FieldDefinitionNode[]|NodeList + * + * @throws SyntaxError + */ + private function parseFieldsDefinition() + { + // Legacy support for the SDL? + if (! empty($this->lexer->options['allowLegacySDLEmptyFields']) && + $this->peek(Token::BRACE_L) && + $this->lexer->lookahead()->kind === Token::BRACE_R + ) { + $this->lexer->advance(); + $this->lexer->advance(); + + return []; + } + + return $this->peek(Token::BRACE_L) + ? $this->many( + Token::BRACE_L, + function () { + return $this->parseFieldDefinition(); + }, + Token::BRACE_R + ) + : new NodeList([]); + } + + /** + * @return FieldDefinitionNode + * + * @throws SyntaxError + */ + private function parseFieldDefinition() + { + $start = $this->lexer->token; + $description = $this->parseDescription(); + $name = $this->parseName(); + $args = $this->parseArgumentDefs(); + $this->expect(Token::COLON); + $type = $this->parseTypeReference(); + $directives = $this->parseDirectives(true); + + return new FieldDefinitionNode([ + 'name' => $name, + 'arguments' => $args, + 'type' => $type, + 'directives' => $directives, + 'loc' => $this->loc($start), + 'description' => $description, + ]); + } + + /** + * @return InputValueDefinitionNode[]|NodeList + * + * @throws SyntaxError + */ + private function parseArgumentDefs() + { + if (! $this->peek(Token::PAREN_L)) { + return new NodeList([]); + } + + return $this->many( + Token::PAREN_L, + function () { + return $this->parseInputValueDef(); + }, + Token::PAREN_R + ); + } + + /** + * @return InputValueDefinitionNode + * + * @throws SyntaxError + */ + private function parseInputValueDef() + { + $start = $this->lexer->token; + $description = $this->parseDescription(); + $name = $this->parseName(); + $this->expect(Token::COLON); + $type = $this->parseTypeReference(); + $defaultValue = null; + if ($this->skip(Token::EQUALS)) { + $defaultValue = $this->parseConstValue(); + } + $directives = $this->parseDirectives(true); + + return new InputValueDefinitionNode([ + 'name' => $name, + 'type' => $type, + 'defaultValue' => $defaultValue, + 'directives' => $directives, + 'loc' => $this->loc($start), + 'description' => $description, + ]); + } + + /** + * @return InterfaceTypeDefinitionNode + * + * @throws SyntaxError + */ + private function parseInterfaceTypeDefinition() + { + $start = $this->lexer->token; + $description = $this->parseDescription(); + $this->expectKeyword('interface'); + $name = $this->parseName(); + $directives = $this->parseDirectives(true); + $fields = $this->parseFieldsDefinition(); + + return new InterfaceTypeDefinitionNode([ + 'name' => $name, + 'directives' => $directives, + 'fields' => $fields, + 'loc' => $this->loc($start), + 'description' => $description, + ]); + } + + /** + * UnionTypeDefinition : + * - Description? union Name Directives[Const]? UnionMemberTypes? + * + * @return UnionTypeDefinitionNode + * + * @throws SyntaxError + */ + private function parseUnionTypeDefinition() + { + $start = $this->lexer->token; + $description = $this->parseDescription(); + $this->expectKeyword('union'); + $name = $this->parseName(); + $directives = $this->parseDirectives(true); + $types = $this->parseUnionMemberTypes(); + + return new UnionTypeDefinitionNode([ + 'name' => $name, + 'directives' => $directives, + 'types' => $types, + 'loc' => $this->loc($start), + 'description' => $description, + ]); + } + + /** + * UnionMemberTypes : + * - = `|`? NamedType + * - UnionMemberTypes | NamedType + * + * @return NamedTypeNode[] + */ + private function parseUnionMemberTypes() + { + $types = []; + if ($this->skip(Token::EQUALS)) { + // Optional leading pipe + $this->skip(Token::PIPE); + do { + $types[] = $this->parseNamedType(); + } while ($this->skip(Token::PIPE)); + } + + return $types; + } + + /** + * @return EnumTypeDefinitionNode + * + * @throws SyntaxError + */ + private function parseEnumTypeDefinition() + { + $start = $this->lexer->token; + $description = $this->parseDescription(); + $this->expectKeyword('enum'); + $name = $this->parseName(); + $directives = $this->parseDirectives(true); + $values = $this->parseEnumValuesDefinition(); + + return new EnumTypeDefinitionNode([ + 'name' => $name, + 'directives' => $directives, + 'values' => $values, + 'loc' => $this->loc($start), + 'description' => $description, + ]); + } + + /** + * @return EnumValueDefinitionNode[]|NodeList + * + * @throws SyntaxError + */ + private function parseEnumValuesDefinition() + { + return $this->peek(Token::BRACE_L) + ? $this->many( + Token::BRACE_L, + function () { + return $this->parseEnumValueDefinition(); + }, + Token::BRACE_R + ) + : new NodeList([]); + } + + /** + * @return EnumValueDefinitionNode + * + * @throws SyntaxError + */ + private function parseEnumValueDefinition() + { + $start = $this->lexer->token; + $description = $this->parseDescription(); + $name = $this->parseName(); + $directives = $this->parseDirectives(true); + + return new EnumValueDefinitionNode([ + 'name' => $name, + 'directives' => $directives, + 'loc' => $this->loc($start), + 'description' => $description, + ]); + } + + /** + * @return InputObjectTypeDefinitionNode + * + * @throws SyntaxError + */ + private function parseInputObjectTypeDefinition() + { + $start = $this->lexer->token; + $description = $this->parseDescription(); + $this->expectKeyword('input'); + $name = $this->parseName(); + $directives = $this->parseDirectives(true); + $fields = $this->parseInputFieldsDefinition(); + + return new InputObjectTypeDefinitionNode([ + 'name' => $name, + 'directives' => $directives, + 'fields' => $fields, + 'loc' => $this->loc($start), + 'description' => $description, + ]); + } + + /** + * @return InputValueDefinitionNode[]|NodeList + * + * @throws SyntaxError + */ + private function parseInputFieldsDefinition() + { + return $this->peek(Token::BRACE_L) + ? $this->many( + Token::BRACE_L, + function () { + return $this->parseInputValueDef(); + }, + Token::BRACE_R + ) + : new NodeList([]); + } + + /** + * TypeExtension : + * - ScalarTypeExtension + * - ObjectTypeExtension + * - InterfaceTypeExtension + * - UnionTypeExtension + * - EnumTypeExtension + * - InputObjectTypeDefinition + * + * @return TypeExtensionNode + * + * @throws SyntaxError + */ + private function parseTypeExtension() + { + $keywordToken = $this->lexer->lookahead(); + + if ($keywordToken->kind === Token::NAME) { + switch ($keywordToken->value) { + case 'schema': + return $this->parseSchemaTypeExtension(); + case 'scalar': + return $this->parseScalarTypeExtension(); + case 'type': + return $this->parseObjectTypeExtension(); + case 'interface': + return $this->parseInterfaceTypeExtension(); + case 'union': + return $this->parseUnionTypeExtension(); + case 'enum': + return $this->parseEnumTypeExtension(); + case 'input': + return $this->parseInputObjectTypeExtension(); + } + } + + throw $this->unexpected($keywordToken); + } + + /** + * @return SchemaTypeExtensionNode + * + * @throws SyntaxError + */ + private function parseSchemaTypeExtension() + { + $start = $this->lexer->token; + $this->expectKeyword('extend'); + $this->expectKeyword('schema'); + $directives = $this->parseDirectives(true); + $operationTypes = $this->peek(Token::BRACE_L) + ? $this->many( + Token::BRACE_L, + [$this, 'parseOperationTypeDefinition'], + Token::BRACE_R + ) : []; + if (count($directives) === 0 && count($operationTypes) === 0) { + $this->unexpected(); + } + + return new SchemaTypeExtensionNode([ + 'directives' => $directives, + 'operationTypes' => $operationTypes, + 'loc' => $this->loc($start), + ]); + } + + /** + * @return ScalarTypeExtensionNode + * + * @throws SyntaxError + */ + private function parseScalarTypeExtension() + { + $start = $this->lexer->token; + $this->expectKeyword('extend'); + $this->expectKeyword('scalar'); + $name = $this->parseName(); + $directives = $this->parseDirectives(true); + if (count($directives) === 0) { + throw $this->unexpected(); + } + + return new ScalarTypeExtensionNode([ + 'name' => $name, + 'directives' => $directives, + 'loc' => $this->loc($start), + ]); + } + + /** + * @return ObjectTypeExtensionNode + * + * @throws SyntaxError + */ + private function parseObjectTypeExtension() + { + $start = $this->lexer->token; + $this->expectKeyword('extend'); + $this->expectKeyword('type'); + $name = $this->parseName(); + $interfaces = $this->parseImplementsInterfaces(); + $directives = $this->parseDirectives(true); + $fields = $this->parseFieldsDefinition(); + + if (count($interfaces) === 0 && + count($directives) === 0 && + count($fields) === 0 + ) { + throw $this->unexpected(); + } + + return new ObjectTypeExtensionNode([ + 'name' => $name, + 'interfaces' => $interfaces, + 'directives' => $directives, + 'fields' => $fields, + 'loc' => $this->loc($start), + ]); + } + + /** + * @return InterfaceTypeExtensionNode + * + * @throws SyntaxError + */ + private function parseInterfaceTypeExtension() + { + $start = $this->lexer->token; + $this->expectKeyword('extend'); + $this->expectKeyword('interface'); + $name = $this->parseName(); + $directives = $this->parseDirectives(true); + $fields = $this->parseFieldsDefinition(); + if (count($directives) === 0 && + count($fields) === 0 + ) { + throw $this->unexpected(); + } + + return new InterfaceTypeExtensionNode([ + 'name' => $name, + 'directives' => $directives, + 'fields' => $fields, + 'loc' => $this->loc($start), + ]); + } + + /** + * UnionTypeExtension : + * - extend union Name Directives[Const]? UnionMemberTypes + * - extend union Name Directives[Const] + * + * @return UnionTypeExtensionNode + * + * @throws SyntaxError + */ + private function parseUnionTypeExtension() + { + $start = $this->lexer->token; + $this->expectKeyword('extend'); + $this->expectKeyword('union'); + $name = $this->parseName(); + $directives = $this->parseDirectives(true); + $types = $this->parseUnionMemberTypes(); + if (count($directives) === 0 && + ! $types + ) { + throw $this->unexpected(); + } + + return new UnionTypeExtensionNode([ + 'name' => $name, + 'directives' => $directives, + 'types' => $types, + 'loc' => $this->loc($start), + ]); + } + + /** + * @return EnumTypeExtensionNode + * + * @throws SyntaxError + */ + private function parseEnumTypeExtension() + { + $start = $this->lexer->token; + $this->expectKeyword('extend'); + $this->expectKeyword('enum'); + $name = $this->parseName(); + $directives = $this->parseDirectives(true); + $values = $this->parseEnumValuesDefinition(); + if (count($directives) === 0 && + count($values) === 0 + ) { + throw $this->unexpected(); + } + + return new EnumTypeExtensionNode([ + 'name' => $name, + 'directives' => $directives, + 'values' => $values, + 'loc' => $this->loc($start), + ]); + } + + /** + * @return InputObjectTypeExtensionNode + * + * @throws SyntaxError + */ + private function parseInputObjectTypeExtension() + { + $start = $this->lexer->token; + $this->expectKeyword('extend'); + $this->expectKeyword('input'); + $name = $this->parseName(); + $directives = $this->parseDirectives(true); + $fields = $this->parseInputFieldsDefinition(); + if (count($directives) === 0 && + count($fields) === 0 + ) { + throw $this->unexpected(); + } + + return new InputObjectTypeExtensionNode([ + 'name' => $name, + 'directives' => $directives, + 'fields' => $fields, + 'loc' => $this->loc($start), + ]); + } + + /** + * DirectiveDefinition : + * - directive @ Name ArgumentsDefinition? on DirectiveLocations + * + * @return DirectiveDefinitionNode + * + * @throws SyntaxError + */ + private function parseDirectiveDefinition() + { + $start = $this->lexer->token; + $description = $this->parseDescription(); + $this->expectKeyword('directive'); + $this->expect(Token::AT); + $name = $this->parseName(); + $args = $this->parseArgumentDefs(); + $this->expectKeyword('on'); + $locations = $this->parseDirectiveLocations(); + + return new DirectiveDefinitionNode([ + 'name' => $name, + 'arguments' => $args, + 'locations' => $locations, + 'loc' => $this->loc($start), + 'description' => $description, + ]); + } + + /** + * @return NameNode[] + * + * @throws SyntaxError + */ + private function parseDirectiveLocations() + { + // Optional leading pipe + $this->skip(Token::PIPE); + $locations = []; + do { + $locations[] = $this->parseDirectiveLocation(); + } while ($this->skip(Token::PIPE)); + + return $locations; + } + + /** + * @return NameNode + * + * @throws SyntaxError + */ + private function parseDirectiveLocation() + { + $start = $this->lexer->token; + $name = $this->parseName(); + if (DirectiveLocation::has($name->value)) { + return $name; + } + + throw $this->unexpected($start); + } +} diff --git a/vendor/webonyx/graphql-php/src/Language/Printer.php b/vendor/webonyx/graphql-php/src/Language/Printer.php new file mode 100644 index 0000000..ae96222 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Language/Printer.php @@ -0,0 +1,520 @@ +printAST($ast); + } + + protected function __construct() + { + } + + public function printAST($ast) + { + return Visitor::visit( + $ast, + [ + 'leave' => [ + NodeKind::NAME => static function (Node $node) { + return '' . $node->value; + }, + + NodeKind::VARIABLE => static function ($node) { + return '$' . $node->name; + }, + + NodeKind::DOCUMENT => function (DocumentNode $node) { + return $this->join($node->definitions, "\n\n") . "\n"; + }, + + NodeKind::OPERATION_DEFINITION => function (OperationDefinitionNode $node) { + $op = $node->operation; + $name = $node->name; + $varDefs = $this->wrap('(', $this->join($node->variableDefinitions, ', '), ')'); + $directives = $this->join($node->directives, ' '); + $selectionSet = $node->selectionSet; + + // Anonymous queries with no directives or variable definitions can use + // the query short form. + return ! $name && ! $directives && ! $varDefs && $op === 'query' + ? $selectionSet + : $this->join([$op, $this->join([$name, $varDefs]), $directives, $selectionSet], ' '); + }, + + NodeKind::VARIABLE_DEFINITION => function (VariableDefinitionNode $node) { + return $node->variable . ': ' . $node->type . $this->wrap(' = ', $node->defaultValue); + }, + + NodeKind::SELECTION_SET => function (SelectionSetNode $node) { + return $this->block($node->selections); + }, + + NodeKind::FIELD => function (FieldNode $node) { + return $this->join( + [ + $this->wrap('', $node->alias, ': ') . $node->name . $this->wrap( + '(', + $this->join($node->arguments, ', '), + ')' + ), + $this->join($node->directives, ' '), + $node->selectionSet, + ], + ' ' + ); + }, + + NodeKind::ARGUMENT => static function (ArgumentNode $node) { + return $node->name . ': ' . $node->value; + }, + + NodeKind::FRAGMENT_SPREAD => function (FragmentSpreadNode $node) { + return '...' . $node->name . $this->wrap(' ', $this->join($node->directives, ' ')); + }, + + NodeKind::INLINE_FRAGMENT => function (InlineFragmentNode $node) { + return $this->join( + [ + '...', + $this->wrap('on ', $node->typeCondition), + $this->join($node->directives, ' '), + $node->selectionSet, + ], + ' ' + ); + }, + + NodeKind::FRAGMENT_DEFINITION => function (FragmentDefinitionNode $node) { + // Note: fragment variable definitions are experimental and may be changed or removed in the future. + return sprintf('fragment %s', $node->name) + . $this->wrap('(', $this->join($node->variableDefinitions, ', '), ')') + . sprintf(' on %s ', $node->typeCondition) + . $this->wrap('', $this->join($node->directives, ' '), ' ') + . $node->selectionSet; + }, + + NodeKind::INT => static function (IntValueNode $node) { + return $node->value; + }, + + NodeKind::FLOAT => static function (FloatValueNode $node) { + return $node->value; + }, + + NodeKind::STRING => function (StringValueNode $node, $key) { + if ($node->block) { + return $this->printBlockString($node->value, $key === 'description'); + } + + return json_encode($node->value); + }, + + NodeKind::BOOLEAN => static function (BooleanValueNode $node) { + return $node->value ? 'true' : 'false'; + }, + + NodeKind::NULL => static function (NullValueNode $node) { + return 'null'; + }, + + NodeKind::ENUM => static function (EnumValueNode $node) { + return $node->value; + }, + + NodeKind::LST => function (ListValueNode $node) { + return '[' . $this->join($node->values, ', ') . ']'; + }, + + NodeKind::OBJECT => function (ObjectValueNode $node) { + return '{' . $this->join($node->fields, ', ') . '}'; + }, + + NodeKind::OBJECT_FIELD => static function (ObjectFieldNode $node) { + return $node->name . ': ' . $node->value; + }, + + NodeKind::DIRECTIVE => function (DirectiveNode $node) { + return '@' . $node->name . $this->wrap('(', $this->join($node->arguments, ', '), ')'); + }, + + NodeKind::NAMED_TYPE => static function (NamedTypeNode $node) { + return $node->name; + }, + + NodeKind::LIST_TYPE => static function (ListTypeNode $node) { + return '[' . $node->type . ']'; + }, + + NodeKind::NON_NULL_TYPE => static function (NonNullTypeNode $node) { + return $node->type . '!'; + }, + + NodeKind::SCHEMA_DEFINITION => function (SchemaDefinitionNode $def) { + return $this->join( + [ + 'schema', + $this->join($def->directives, ' '), + $this->block($def->operationTypes), + ], + ' ' + ); + }, + + NodeKind::OPERATION_TYPE_DEFINITION => static function (OperationTypeDefinitionNode $def) { + return $def->operation . ': ' . $def->type; + }, + + NodeKind::SCALAR_TYPE_DEFINITION => $this->addDescription(function (ScalarTypeDefinitionNode $def) { + return $this->join(['scalar', $def->name, $this->join($def->directives, ' ')], ' '); + }), + + NodeKind::OBJECT_TYPE_DEFINITION => $this->addDescription(function (ObjectTypeDefinitionNode $def) { + return $this->join( + [ + 'type', + $def->name, + $this->wrap('implements ', $this->join($def->interfaces, ' & ')), + $this->join($def->directives, ' '), + $this->block($def->fields), + ], + ' ' + ); + }), + + NodeKind::FIELD_DEFINITION => $this->addDescription(function (FieldDefinitionNode $def) { + $noIndent = Utils::every($def->arguments, static function (string $arg) { + return strpos($arg, "\n") === false; + }); + + return $def->name + . ($noIndent + ? $this->wrap('(', $this->join($def->arguments, ', '), ')') + : $this->wrap("(\n", $this->indent($this->join($def->arguments, "\n")), "\n)")) + . ': ' . $def->type + . $this->wrap(' ', $this->join($def->directives, ' ')); + }), + + NodeKind::INPUT_VALUE_DEFINITION => $this->addDescription(function (InputValueDefinitionNode $def) { + return $this->join( + [ + $def->name . ': ' . $def->type, + $this->wrap('= ', $def->defaultValue), + $this->join($def->directives, ' '), + ], + ' ' + ); + }), + + NodeKind::INTERFACE_TYPE_DEFINITION => $this->addDescription( + function (InterfaceTypeDefinitionNode $def) { + return $this->join( + [ + 'interface', + $def->name, + $this->join($def->directives, ' '), + $this->block($def->fields), + ], + ' ' + ); + } + ), + + NodeKind::UNION_TYPE_DEFINITION => $this->addDescription(function (UnionTypeDefinitionNode $def) { + return $this->join( + [ + 'union', + $def->name, + $this->join($def->directives, ' '), + $def->types + ? '= ' . $this->join($def->types, ' | ') + : '', + ], + ' ' + ); + }), + + NodeKind::ENUM_TYPE_DEFINITION => $this->addDescription(function (EnumTypeDefinitionNode $def) { + return $this->join( + [ + 'enum', + $def->name, + $this->join($def->directives, ' '), + $this->block($def->values), + ], + ' ' + ); + }), + + NodeKind::ENUM_VALUE_DEFINITION => $this->addDescription(function (EnumValueDefinitionNode $def) { + return $this->join([$def->name, $this->join($def->directives, ' ')], ' '); + }), + + NodeKind::INPUT_OBJECT_TYPE_DEFINITION => $this->addDescription(function ( + InputObjectTypeDefinitionNode $def + ) { + return $this->join( + [ + 'input', + $def->name, + $this->join($def->directives, ' '), + $this->block($def->fields), + ], + ' ' + ); + }), + + NodeKind::SCHEMA_EXTENSION => function (SchemaTypeExtensionNode $def) { + return $this->join( + [ + 'extend schema', + $this->join($def->directives, ' '), + $this->block($def->operationTypes), + ], + ' ' + ); + }, + + NodeKind::SCALAR_TYPE_EXTENSION => function (ScalarTypeExtensionNode $def) { + return $this->join( + [ + 'extend scalar', + $def->name, + $this->join($def->directives, ' '), + ], + ' ' + ); + }, + + NodeKind::OBJECT_TYPE_EXTENSION => function (ObjectTypeExtensionNode $def) { + return $this->join( + [ + 'extend type', + $def->name, + $this->wrap('implements ', $this->join($def->interfaces, ' & ')), + $this->join($def->directives, ' '), + $this->block($def->fields), + ], + ' ' + ); + }, + + NodeKind::INTERFACE_TYPE_EXTENSION => function (InterfaceTypeExtensionNode $def) { + return $this->join( + [ + 'extend interface', + $def->name, + $this->join($def->directives, ' '), + $this->block($def->fields), + ], + ' ' + ); + }, + + NodeKind::UNION_TYPE_EXTENSION => function (UnionTypeExtensionNode $def) { + return $this->join( + [ + 'extend union', + $def->name, + $this->join($def->directives, ' '), + $def->types + ? '= ' . $this->join($def->types, ' | ') + : '', + ], + ' ' + ); + }, + + NodeKind::ENUM_TYPE_EXTENSION => function (EnumTypeExtensionNode $def) { + return $this->join( + [ + 'extend enum', + $def->name, + $this->join($def->directives, ' '), + $this->block($def->values), + ], + ' ' + ); + }, + + NodeKind::INPUT_OBJECT_TYPE_EXTENSION => function (InputObjectTypeExtensionNode $def) { + return $this->join( + [ + 'extend input', + $def->name, + $this->join($def->directives, ' '), + $this->block($def->fields), + ], + ' ' + ); + }, + + NodeKind::DIRECTIVE_DEFINITION => $this->addDescription(function (DirectiveDefinitionNode $def) { + $noIndent = Utils::every($def->arguments, static function (string $arg) { + return strpos($arg, "\n") === false; + }); + + return 'directive @' + . $def->name + . ($noIndent + ? $this->wrap('(', $this->join($def->arguments, ', '), ')') + : $this->wrap("(\n", $this->indent($this->join($def->arguments, "\n")), "\n")) + . ' on ' . $this->join($def->locations, ' | '); + }), + ], + ] + ); + } + + public function addDescription(callable $cb) + { + return function ($node) use ($cb) { + return $this->join([$node->description, $cb($node)], "\n"); + }; + } + + /** + * If maybeString is not null or empty, then wrap with start and end, otherwise + * print an empty string. + */ + public function wrap($start, $maybeString, $end = '') + { + return $maybeString ? ($start . $maybeString . $end) : ''; + } + + /** + * Given array, print each item on its own line, wrapped in an + * indented "{ }" block. + */ + public function block($array) + { + return $array && $this->length($array) + ? "{\n" . $this->indent($this->join($array, "\n")) . "\n}" + : ''; + } + + public function indent($maybeString) + { + return $maybeString ? ' ' . str_replace("\n", "\n ", $maybeString) : ''; + } + + public function manyList($start, $list, $separator, $end) + { + return $this->length($list) === 0 ? null : ($start . $this->join($list, $separator) . $end); + } + + public function length($maybeArray) + { + return $maybeArray ? count($maybeArray) : 0; + } + + public function join($maybeArray, $separator = '') + { + return $maybeArray + ? implode( + $separator, + Utils::filter( + $maybeArray, + static function ($x) { + return (bool) $x; + } + ) + ) + : ''; + } + + /** + * Print a block string in the indented block form by adding a leading and + * trailing blank line. However, if a block string starts with whitespace and is + * a single-line, adding a leading blank line would strip that whitespace. + */ + private function printBlockString($value, $isDescription) + { + $escaped = str_replace('"""', '\\"""', $value); + + return ($value[0] === ' ' || $value[0] === "\t") && strpos($value, "\n") === false + ? ('"""' . preg_replace('/"$/', "\"\n", $escaped) . '"""') + : ('"""' . "\n" . ($isDescription ? $escaped : $this->indent($escaped)) . "\n" . '"""'); + } +} diff --git a/vendor/webonyx/graphql-php/src/Language/Source.php b/vendor/webonyx/graphql-php/src/Language/Source.php new file mode 100644 index 0000000..7e94030 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Language/Source.php @@ -0,0 +1,85 @@ +body = $body; + $this->length = mb_strlen($body, 'UTF-8'); + $this->name = $name ?: 'GraphQL request'; + $this->locationOffset = $location ?: new SourceLocation(1, 1); + + Utils::invariant( + $this->locationOffset->line > 0, + 'line in locationOffset is 1-indexed and must be positive' + ); + Utils::invariant( + $this->locationOffset->column > 0, + 'column in locationOffset is 1-indexed and must be positive' + ); + } + + /** + * @param int $position + * + * @return SourceLocation + */ + public function getLocation($position) + { + $line = 1; + $column = $position + 1; + + $utfChars = json_decode('"\u2028\u2029"'); + $lineRegexp = '/\r\n|[\n\r' . $utfChars . ']/su'; + $matches = []; + preg_match_all($lineRegexp, mb_substr($this->body, 0, $position, 'UTF-8'), $matches, PREG_OFFSET_CAPTURE); + + foreach ($matches[0] as $index => $match) { + $line += 1; + + $column = $position + 1 - ($match[1] + mb_strlen($match[0], 'UTF-8')); + } + + return new SourceLocation($line, $column); + } +} diff --git a/vendor/webonyx/graphql-php/src/Language/SourceLocation.php b/vendor/webonyx/graphql-php/src/Language/SourceLocation.php new file mode 100644 index 0000000..8877f84 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Language/SourceLocation.php @@ -0,0 +1,53 @@ +line = $line; + $this->column = $col; + } + + /** + * @return int[] + */ + public function toArray() + { + return [ + 'line' => $this->line, + 'column' => $this->column, + ]; + } + + /** + * @return int[] + */ + public function toSerializableArray() + { + return $this->toArray(); + } + + /** + * @return int[] + */ + public function jsonSerialize() + { + return $this->toSerializableArray(); + } +} diff --git a/vendor/webonyx/graphql-php/src/Language/Token.php b/vendor/webonyx/graphql-php/src/Language/Token.php new file mode 100644 index 0000000..831b3ad --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Language/Token.php @@ -0,0 +1,127 @@ +'; + const EOF = ''; + const BANG = '!'; + const DOLLAR = '$'; + const AMP = '&'; + const PAREN_L = '('; + const PAREN_R = ')'; + const SPREAD = '...'; + const COLON = ':'; + const EQUALS = '='; + const AT = '@'; + const BRACKET_L = '['; + const BRACKET_R = ']'; + const BRACE_L = '{'; + const PIPE = '|'; + const BRACE_R = '}'; + const NAME = 'Name'; + const INT = 'Int'; + const FLOAT = 'Float'; + const STRING = 'String'; + const BLOCK_STRING = 'BlockString'; + const COMMENT = 'Comment'; + + /** + * The kind of Token (see one of constants above). + * + * @var string + */ + public $kind; + + /** + * The character offset at which this Node begins. + * + * @var int + */ + public $start; + + /** + * The character offset at which this Node ends. + * + * @var int + */ + public $end; + + /** + * The 1-indexed line number on which this Token appears. + * + * @var int + */ + public $line; + + /** + * The 1-indexed column number at which this Token begins. + * + * @var int + */ + public $column; + + /** @var string|null */ + public $value; + + /** + * Tokens exist as nodes in a double-linked-list amongst all tokens + * including ignored tokens. is always the first node and + * the last. + * + * @var Token + */ + public $prev; + + /** @var Token */ + public $next; + + /** + * @param string $kind + * @param int $start + * @param int $end + * @param int $line + * @param int $column + * @param mixed|null $value + */ + public function __construct($kind, $start, $end, $line, $column, ?Token $previous = null, $value = null) + { + $this->kind = $kind; + $this->start = $start; + $this->end = $end; + $this->line = $line; + $this->column = $column; + $this->prev = $previous; + $this->next = null; + $this->value = $value; + } + + /** + * @return string + */ + public function getDescription() + { + return $this->kind . ($this->value ? ' "' . $this->value . '"' : ''); + } + + /** + * @return (string|int|null)[] + */ + public function toArray() + { + return [ + 'kind' => $this->kind, + 'value' => $this->value, + 'line' => $this->line, + 'column' => $this->column, + ]; + } +} diff --git a/vendor/webonyx/graphql-php/src/Language/Visitor.php b/vendor/webonyx/graphql-php/src/Language/Visitor.php new file mode 100644 index 0000000..45f8fff --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Language/Visitor.php @@ -0,0 +1,543 @@ + function ($node, $key, $parent, $path, $ancestors) { + * // return + * // null: no action + * // Visitor::skipNode(): skip visiting this node + * // Visitor::stop(): stop visiting altogether + * // Visitor::removeNode(): delete this node + * // any value: replace this node with the returned value + * }, + * 'leave' => function ($node, $key, $parent, $path, $ancestors) { + * // return + * // null: no action + * // Visitor::stop(): stop visiting altogether + * // Visitor::removeNode(): delete this node + * // any value: replace this node with the returned value + * } + * ]); + * + * Alternatively to providing enter() and leave() functions, a visitor can + * instead provide functions named the same as the [kinds of AST nodes](reference.md#graphqllanguageastnodekind), + * or enter/leave visitors at a named key, leading to four permutations of + * visitor API: + * + * 1) Named visitors triggered when entering a node a specific kind. + * + * Visitor::visit($ast, [ + * 'Kind' => function ($node) { + * // enter the "Kind" node + * } + * ]); + * + * 2) Named visitors that trigger upon entering and leaving a node of + * a specific kind. + * + * Visitor::visit($ast, [ + * 'Kind' => [ + * 'enter' => function ($node) { + * // enter the "Kind" node + * } + * 'leave' => function ($node) { + * // leave the "Kind" node + * } + * ] + * ]); + * + * 3) Generic visitors that trigger upon entering and leaving any node. + * + * Visitor::visit($ast, [ + * 'enter' => function ($node) { + * // enter any node + * }, + * 'leave' => function ($node) { + * // leave any node + * } + * ]); + * + * 4) Parallel visitors for entering and leaving nodes of a specific kind. + * + * Visitor::visit($ast, [ + * 'enter' => [ + * 'Kind' => function($node) { + * // enter the "Kind" node + * } + * }, + * 'leave' => [ + * 'Kind' => function ($node) { + * // leave the "Kind" node + * } + * ] + * ]); + */ +class Visitor +{ + /** @var string[][] */ + public static $visitorKeys = [ + NodeKind::NAME => [], + NodeKind::DOCUMENT => ['definitions'], + NodeKind::OPERATION_DEFINITION => ['name', 'variableDefinitions', 'directives', 'selectionSet'], + NodeKind::VARIABLE_DEFINITION => ['variable', 'type', 'defaultValue'], + NodeKind::VARIABLE => ['name'], + NodeKind::SELECTION_SET => ['selections'], + NodeKind::FIELD => ['alias', 'name', 'arguments', 'directives', 'selectionSet'], + NodeKind::ARGUMENT => ['name', 'value'], + NodeKind::FRAGMENT_SPREAD => ['name', 'directives'], + NodeKind::INLINE_FRAGMENT => ['typeCondition', 'directives', 'selectionSet'], + NodeKind::FRAGMENT_DEFINITION => [ + 'name', + // Note: fragment variable definitions are experimental and may be changed + // or removed in the future. + 'variableDefinitions', + 'typeCondition', + 'directives', + 'selectionSet', + ], + + NodeKind::INT => [], + NodeKind::FLOAT => [], + NodeKind::STRING => [], + NodeKind::BOOLEAN => [], + NodeKind::NULL => [], + NodeKind::ENUM => [], + NodeKind::LST => ['values'], + NodeKind::OBJECT => ['fields'], + NodeKind::OBJECT_FIELD => ['name', 'value'], + NodeKind::DIRECTIVE => ['name', 'arguments'], + NodeKind::NAMED_TYPE => ['name'], + NodeKind::LIST_TYPE => ['type'], + NodeKind::NON_NULL_TYPE => ['type'], + + NodeKind::SCHEMA_DEFINITION => ['directives', 'operationTypes'], + NodeKind::OPERATION_TYPE_DEFINITION => ['type'], + NodeKind::SCALAR_TYPE_DEFINITION => ['description', 'name', 'directives'], + NodeKind::OBJECT_TYPE_DEFINITION => ['description', 'name', 'interfaces', 'directives', 'fields'], + NodeKind::FIELD_DEFINITION => ['description', 'name', 'arguments', 'type', 'directives'], + NodeKind::INPUT_VALUE_DEFINITION => ['description', 'name', 'type', 'defaultValue', 'directives'], + NodeKind::INTERFACE_TYPE_DEFINITION => ['description', 'name', 'directives', 'fields'], + NodeKind::UNION_TYPE_DEFINITION => ['description', 'name', 'directives', 'types'], + NodeKind::ENUM_TYPE_DEFINITION => ['description', 'name', 'directives', 'values'], + NodeKind::ENUM_VALUE_DEFINITION => ['description', 'name', 'directives'], + NodeKind::INPUT_OBJECT_TYPE_DEFINITION => ['description', 'name', 'directives', 'fields'], + + NodeKind::SCALAR_TYPE_EXTENSION => ['name', 'directives'], + NodeKind::OBJECT_TYPE_EXTENSION => ['name', 'interfaces', 'directives', 'fields'], + NodeKind::INTERFACE_TYPE_EXTENSION => ['name', 'directives', 'fields'], + NodeKind::UNION_TYPE_EXTENSION => ['name', 'directives', 'types'], + NodeKind::ENUM_TYPE_EXTENSION => ['name', 'directives', 'values'], + NodeKind::INPUT_OBJECT_TYPE_EXTENSION => ['name', 'directives', 'fields'], + + NodeKind::DIRECTIVE_DEFINITION => ['description', 'name', 'arguments', 'locations'], + + NodeKind::SCHEMA_EXTENSION => ['directives', 'operationTypes'], + ]; + + /** + * Visit the AST (see class description for details) + * + * @param Node|ArrayObject|stdClass $root + * @param callable[] $visitor + * @param mixed[]|null $keyMap + * + * @return Node|mixed + * + * @throws Exception + * + * @api + */ + public static function visit($root, $visitor, $keyMap = null) + { + $visitorKeys = $keyMap ?: self::$visitorKeys; + + $stack = null; + $inArray = $root instanceof NodeList || is_array($root); + $keys = [$root]; + $index = -1; + $edits = []; + $parent = null; + $path = []; + $ancestors = []; + $newRoot = $root; + + $UNDEFINED = null; + + do { + $index++; + $isLeaving = $index === count($keys); + $key = null; + $node = null; + $isEdited = $isLeaving && count($edits) !== 0; + + if ($isLeaving) { + $key = ! $ancestors ? $UNDEFINED : $path[count($path) - 1]; + $node = $parent; + $parent = array_pop($ancestors); + + if ($isEdited) { + if ($inArray) { + // $node = $node; // arrays are value types in PHP + if ($node instanceof NodeList) { + $node = clone $node; + } + } else { + $node = clone $node; + } + $editOffset = 0; + for ($ii = 0; $ii < count($edits); $ii++) { + $editKey = $edits[$ii][0]; + $editValue = $edits[$ii][1]; + + if ($inArray) { + $editKey -= $editOffset; + } + if ($inArray && $editValue === null) { + if ($node instanceof NodeList) { + $node->splice($editKey, 1); + } else { + array_splice($node, $editKey, 1); + } + $editOffset++; + } else { + if ($node instanceof NodeList || is_array($node)) { + $node[$editKey] = $editValue; + } else { + $node->{$editKey} = $editValue; + } + } + } + } + $index = $stack['index']; + $keys = $stack['keys']; + $edits = $stack['edits']; + $inArray = $stack['inArray']; + $stack = $stack['prev']; + } else { + $key = $parent !== null ? ($inArray ? $index : $keys[$index]) : $UNDEFINED; + $node = $parent !== null ? ($parent instanceof NodeList || is_array($parent) ? $parent[$key] : $parent->{$key}) : $newRoot; + if ($node === null || $node === $UNDEFINED) { + continue; + } + if ($parent !== null) { + $path[] = $key; + } + } + + $result = null; + if (! $node instanceof NodeList && ! is_array($node)) { + if (! ($node instanceof Node)) { + throw new Exception('Invalid AST Node: ' . json_encode($node)); + } + + $visitFn = self::getVisitFn($visitor, $node->kind, $isLeaving); + + if ($visitFn) { + $result = call_user_func($visitFn, $node, $key, $parent, $path, $ancestors); + $editValue = null; + + if ($result !== null) { + if ($result instanceof VisitorOperation) { + if ($result->doBreak) { + break; + } + if (! $isLeaving && $result->doContinue) { + array_pop($path); + continue; + } + if ($result->removeNode) { + $editValue = null; + } + } else { + $editValue = $result; + } + + $edits[] = [$key, $editValue]; + if (! $isLeaving) { + if (! ($editValue instanceof Node)) { + array_pop($path); + continue; + } + + $node = $editValue; + } + } + } + } + + if ($result === null && $isEdited) { + $edits[] = [$key, $node]; + } + + if ($isLeaving) { + array_pop($path); + } else { + $stack = [ + 'inArray' => $inArray, + 'index' => $index, + 'keys' => $keys, + 'edits' => $edits, + 'prev' => $stack, + ]; + $inArray = $node instanceof NodeList || is_array($node); + + $keys = ($inArray ? $node : $visitorKeys[$node->kind]) ?: []; + $index = -1; + $edits = []; + if ($parent !== null) { + $ancestors[] = $parent; + } + $parent = $node; + } + } while ($stack); + + if (count($edits) !== 0) { + $newRoot = $edits[0][1]; + } + + return $newRoot; + } + + /** + * Returns marker for visitor break + * + * @return VisitorOperation + * + * @api + */ + public static function stop() + { + $r = new VisitorOperation(); + $r->doBreak = true; + + return $r; + } + + /** + * Returns marker for skipping current node + * + * @return VisitorOperation + * + * @api + */ + public static function skipNode() + { + $r = new VisitorOperation(); + $r->doContinue = true; + + return $r; + } + + /** + * Returns marker for removing a node + * + * @return VisitorOperation + * + * @api + */ + public static function removeNode() + { + $r = new VisitorOperation(); + $r->removeNode = true; + + return $r; + } + + /** + * @param callable[][] $visitors + * + * @return callable[][] + */ + public static function visitInParallel($visitors) + { + $visitorsCount = count($visitors); + $skipping = new SplFixedArray($visitorsCount); + + return [ + 'enter' => static function (Node $node) use ($visitors, $skipping, $visitorsCount) { + for ($i = 0; $i < $visitorsCount; $i++) { + if (! empty($skipping[$i])) { + continue; + } + + $fn = self::getVisitFn( + $visitors[$i], + $node->kind, /* isLeaving */ + false + ); + + if (! $fn) { + continue; + } + + $result = call_user_func_array($fn, func_get_args()); + + if ($result instanceof VisitorOperation) { + if ($result->doContinue) { + $skipping[$i] = $node; + } elseif ($result->doBreak) { + $skipping[$i] = $result; + } elseif ($result->removeNode) { + return $result; + } + } elseif ($result !== null) { + return $result; + } + } + }, + 'leave' => static function (Node $node) use ($visitors, $skipping, $visitorsCount) { + for ($i = 0; $i < $visitorsCount; $i++) { + if (empty($skipping[$i])) { + $fn = self::getVisitFn( + $visitors[$i], + $node->kind, /* isLeaving */ + true + ); + + if ($fn) { + $result = call_user_func_array($fn, func_get_args()); + if ($result instanceof VisitorOperation) { + if ($result->doBreak) { + $skipping[$i] = $result; + } elseif ($result->removeNode) { + return $result; + } + } elseif ($result !== null) { + return $result; + } + } + } elseif ($skipping[$i] === $node) { + $skipping[$i] = null; + } + } + }, + ]; + } + + /** + * Creates a new visitor instance which maintains a provided TypeInfo instance + * along with visiting visitor. + */ + public static function visitWithTypeInfo(TypeInfo $typeInfo, $visitor) + { + return [ + 'enter' => static function (Node $node) use ($typeInfo, $visitor) { + $typeInfo->enter($node); + $fn = self::getVisitFn($visitor, $node->kind, false); + + if ($fn) { + $result = call_user_func_array($fn, func_get_args()); + if ($result !== null) { + $typeInfo->leave($node); + if ($result instanceof Node) { + $typeInfo->enter($result); + } + } + + return $result; + } + + return null; + }, + 'leave' => static function (Node $node) use ($typeInfo, $visitor) { + $fn = self::getVisitFn($visitor, $node->kind, true); + $result = $fn ? call_user_func_array($fn, func_get_args()) : null; + $typeInfo->leave($node); + + return $result; + }, + ]; + } + + /** + * @param callable[]|null $visitor + * @param string $kind + * @param bool $isLeaving + * + * @return callable|null + */ + public static function getVisitFn($visitor, $kind, $isLeaving) + { + if ($visitor === null) { + return null; + } + + $kindVisitor = $visitor[$kind] ?? null; + + if (! $isLeaving && is_callable($kindVisitor)) { + // { Kind() {} } + return $kindVisitor; + } + + if (is_array($kindVisitor)) { + if ($isLeaving) { + $kindSpecificVisitor = $kindVisitor['leave'] ?? null; + } else { + $kindSpecificVisitor = $kindVisitor['enter'] ?? null; + } + + if ($kindSpecificVisitor && is_callable($kindSpecificVisitor)) { + // { Kind: { enter() {}, leave() {} } } + return $kindSpecificVisitor; + } + + return null; + } + + $visitor += ['leave' => null, 'enter' => null]; + + $specificVisitor = $isLeaving ? $visitor['leave'] : $visitor['enter']; + + if ($specificVisitor) { + if (is_callable($specificVisitor)) { + // { enter() {}, leave() {} } + return $specificVisitor; + } + $specificKindVisitor = $specificVisitor[$kind] ?? null; + + if (is_callable($specificKindVisitor)) { + // { enter: { Kind() {} }, leave: { Kind() {} } } + return $specificKindVisitor; + } + } + + return null; + } +} diff --git a/vendor/webonyx/graphql-php/src/Language/VisitorOperation.php b/vendor/webonyx/graphql-php/src/Language/VisitorOperation.php new file mode 100644 index 0000000..2316261 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Language/VisitorOperation.php @@ -0,0 +1,17 @@ +readRawBody(); + $bodyParams = ['query' => $rawBody ?: '']; + } elseif (stripos($contentType, 'application/json') !== false) { + $rawBody = $readRawBodyFn ? $readRawBodyFn() : $this->readRawBody(); + $bodyParams = json_decode($rawBody ?: '', true); + + if (json_last_error()) { + throw new RequestError('Could not parse JSON: ' . json_last_error_msg()); + } + + if (! is_array($bodyParams)) { + throw new RequestError( + 'GraphQL Server expects JSON object or array, but got ' . + Utils::printSafeJson($bodyParams) + ); + } + } elseif (stripos($contentType, 'application/x-www-form-urlencoded') !== false) { + $bodyParams = $_POST; + } elseif (stripos($contentType, 'multipart/form-data') !== false) { + $bodyParams = $_POST; + } else { + throw new RequestError('Unexpected content type: ' . Utils::printSafeJson($contentType)); + } + } + + return $this->parseRequestParams($method, $bodyParams, $urlParams); + } + + /** + * Parses normalized request params and returns instance of OperationParams + * or array of OperationParams in case of batch operation. + * + * Returned value is a suitable input for `executeOperation` or `executeBatch` (if array) + * + * @param string $method + * @param mixed[] $bodyParams + * @param mixed[] $queryParams + * + * @return OperationParams|OperationParams[] + * + * @throws RequestError + * + * @api + */ + public function parseRequestParams($method, array $bodyParams, array $queryParams) + { + if ($method === 'GET') { + $result = OperationParams::create($queryParams, true); + } elseif ($method === 'POST') { + if (isset($bodyParams[0])) { + $result = []; + foreach ($bodyParams as $index => $entry) { + $op = OperationParams::create($entry); + $result[] = $op; + } + } else { + $result = OperationParams::create($bodyParams); + } + } else { + throw new RequestError('HTTP Method "' . $method . '" is not supported'); + } + + return $result; + } + + /** + * Checks validity of OperationParams extracted from HTTP request and returns an array of errors + * if params are invalid (or empty array when params are valid) + * + * @return Error[] + * + * @api + */ + public function validateOperationParams(OperationParams $params) + { + $errors = []; + if (! $params->query && ! $params->queryId) { + $errors[] = new RequestError('GraphQL Request must include at least one of those two parameters: "query" or "queryId"'); + } + + if ($params->query && $params->queryId) { + $errors[] = new RequestError('GraphQL Request parameters "query" and "queryId" are mutually exclusive'); + } + + if ($params->query !== null && (! is_string($params->query) || empty($params->query))) { + $errors[] = new RequestError( + 'GraphQL Request parameter "query" must be string, but got ' . + Utils::printSafeJson($params->query) + ); + } + + if ($params->queryId !== null && (! is_string($params->queryId) || empty($params->queryId))) { + $errors[] = new RequestError( + 'GraphQL Request parameter "queryId" must be string, but got ' . + Utils::printSafeJson($params->queryId) + ); + } + + if ($params->operation !== null && (! is_string($params->operation) || empty($params->operation))) { + $errors[] = new RequestError( + 'GraphQL Request parameter "operation" must be string, but got ' . + Utils::printSafeJson($params->operation) + ); + } + + if ($params->variables !== null && (! is_array($params->variables) || isset($params->variables[0]))) { + $errors[] = new RequestError( + 'GraphQL Request parameter "variables" must be object or JSON string parsed to object, but got ' . + Utils::printSafeJson($params->getOriginalInput('variables')) + ); + } + + return $errors; + } + + /** + * Executes GraphQL operation with given server configuration and returns execution result + * (or promise when promise adapter is different from SyncPromiseAdapter) + * + * @return ExecutionResult|Promise + * + * @api + */ + public function executeOperation(ServerConfig $config, OperationParams $op) + { + $promiseAdapter = $config->getPromiseAdapter() ?: Executor::getPromiseAdapter(); + $result = $this->promiseToExecuteOperation($promiseAdapter, $config, $op); + + if ($promiseAdapter instanceof SyncPromiseAdapter) { + $result = $promiseAdapter->wait($result); + } + + return $result; + } + + /** + * Executes batched GraphQL operations with shared promise queue + * (thus, effectively batching deferreds|promises of all queries at once) + * + * @param OperationParams[] $operations + * + * @return ExecutionResult|ExecutionResult[]|Promise + * + * @api + */ + public function executeBatch(ServerConfig $config, array $operations) + { + $promiseAdapter = $config->getPromiseAdapter() ?: Executor::getPromiseAdapter(); + $result = []; + + foreach ($operations as $operation) { + $result[] = $this->promiseToExecuteOperation($promiseAdapter, $config, $operation, true); + } + + $result = $promiseAdapter->all($result); + + // Wait for promised results when using sync promises + if ($promiseAdapter instanceof SyncPromiseAdapter) { + $result = $promiseAdapter->wait($result); + } + + return $result; + } + + /** + * @param bool $isBatch + * + * @return Promise + */ + private function promiseToExecuteOperation( + PromiseAdapter $promiseAdapter, + ServerConfig $config, + OperationParams $op, + $isBatch = false + ) { + try { + if (! $config->getSchema()) { + throw new InvariantViolation('Schema is required for the server'); + } + + if ($isBatch && ! $config->getQueryBatching()) { + throw new RequestError('Batched queries are not supported by this server'); + } + + $errors = $this->validateOperationParams($op); + + if (! empty($errors)) { + $errors = Utils::map( + $errors, + static function (RequestError $err) { + return Error::createLocatedError($err, null, null); + } + ); + + return $promiseAdapter->createFulfilled( + new ExecutionResult(null, $errors) + ); + } + + $doc = $op->queryId ? $this->loadPersistedQuery($config, $op) : $op->query; + + if (! $doc instanceof DocumentNode) { + $doc = Parser::parse($doc); + } + + $operationType = AST::getOperation($doc, $op->operation); + if ($operationType !== 'query' && $op->isReadOnly()) { + throw new RequestError('GET supports only query operation'); + } + + $result = GraphQL::promiseToExecute( + $promiseAdapter, + $config->getSchema(), + $doc, + $this->resolveRootValue($config, $op, $doc, $operationType), + $this->resolveContextValue($config, $op, $doc, $operationType), + $op->variables, + $op->operation, + $config->getFieldResolver(), + $this->resolveValidationRules($config, $op, $doc, $operationType) + ); + } catch (RequestError $e) { + $result = $promiseAdapter->createFulfilled( + new ExecutionResult(null, [Error::createLocatedError($e)]) + ); + } catch (Error $e) { + $result = $promiseAdapter->createFulfilled( + new ExecutionResult(null, [$e]) + ); + } + + $applyErrorHandling = static function (ExecutionResult $result) use ($config) { + if ($config->getErrorsHandler()) { + $result->setErrorsHandler($config->getErrorsHandler()); + } + if ($config->getErrorFormatter() || $config->getDebug()) { + $result->setErrorFormatter( + FormattedError::prepareFormatter( + $config->getErrorFormatter(), + $config->getDebug() + ) + ); + } + + return $result; + }; + + return $result->then($applyErrorHandling); + } + + /** + * @return mixed + * + * @throws RequestError + */ + private function loadPersistedQuery(ServerConfig $config, OperationParams $operationParams) + { + // Load query if we got persisted query id: + $loader = $config->getPersistentQueryLoader(); + + if (! $loader) { + throw new RequestError('Persisted queries are not supported by this server'); + } + + $source = $loader($operationParams->queryId, $operationParams); + + if (! is_string($source) && ! $source instanceof DocumentNode) { + throw new InvariantViolation(sprintf( + 'Persistent query loader must return query string or instance of %s but got: %s', + DocumentNode::class, + Utils::printSafe($source) + )); + } + + return $source; + } + + /** + * @param string $operationType + * + * @return mixed[]|null + */ + private function resolveValidationRules( + ServerConfig $config, + OperationParams $params, + DocumentNode $doc, + $operationType + ) { + // Allow customizing validation rules per operation: + $validationRules = $config->getValidationRules(); + + if (is_callable($validationRules)) { + $validationRules = $validationRules($params, $doc, $operationType); + + if (! is_array($validationRules)) { + throw new InvariantViolation(sprintf( + 'Expecting validation rules to be array or callable returning array, but got: %s', + Utils::printSafe($validationRules) + )); + } + } + + return $validationRules; + } + + /** + * @param string $operationType + * + * @return mixed + */ + private function resolveRootValue(ServerConfig $config, OperationParams $params, DocumentNode $doc, $operationType) + { + $root = $config->getRootValue(); + + if (is_callable($root)) { + $root = $root($params, $doc, $operationType); + } + + return $root; + } + + /** + * @param string $operationType + * + * @return mixed + */ + private function resolveContextValue( + ServerConfig $config, + OperationParams $params, + DocumentNode $doc, + $operationType + ) { + $context = $config->getContext(); + + if (is_callable($context)) { + $context = $context($params, $doc, $operationType); + } + + return $context; + } + + /** + * Send response using standard PHP `header()` and `echo`. + * + * @param Promise|ExecutionResult|ExecutionResult[] $result + * @param bool $exitWhenDone + * + * @api + */ + public function sendResponse($result, $exitWhenDone = false) + { + if ($result instanceof Promise) { + $result->then(function ($actualResult) use ($exitWhenDone) { + $this->doSendResponse($actualResult, $exitWhenDone); + }); + } else { + $this->doSendResponse($result, $exitWhenDone); + } + } + + private function doSendResponse($result, $exitWhenDone) + { + $httpStatus = $this->resolveHttpStatus($result); + $this->emitResponse($result, $httpStatus, $exitWhenDone); + } + + /** + * @param mixed[]|JsonSerializable $jsonSerializable + * @param int $httpStatus + * @param bool $exitWhenDone + */ + public function emitResponse($jsonSerializable, $httpStatus, $exitWhenDone) + { + $body = json_encode($jsonSerializable); + header('Content-Type: application/json', true, $httpStatus); + echo $body; + + if ($exitWhenDone) { + exit; + } + } + + /** + * @return bool|string + */ + private function readRawBody() + { + return file_get_contents('php://input'); + } + + /** + * @param ExecutionResult|mixed[] $result + * + * @return int + */ + private function resolveHttpStatus($result) + { + if (is_array($result) && isset($result[0])) { + Utils::each( + $result, + static function ($executionResult, $index) { + if (! $executionResult instanceof ExecutionResult) { + throw new InvariantViolation(sprintf( + 'Expecting every entry of batched query result to be instance of %s but entry at position %d is %s', + ExecutionResult::class, + $index, + Utils::printSafe($executionResult) + )); + } + } + ); + $httpStatus = 200; + } else { + if (! $result instanceof ExecutionResult) { + throw new InvariantViolation(sprintf( + 'Expecting query result to be instance of %s but got %s', + ExecutionResult::class, + Utils::printSafe($result) + )); + } + if ($result->data === null && ! empty($result->errors)) { + $httpStatus = 400; + } else { + $httpStatus = 200; + } + } + + return $httpStatus; + } + + /** + * Converts PSR-7 request to OperationParams[] + * + * @return OperationParams[]|OperationParams + * + * @throws RequestError + * + * @api + */ + public function parsePsrRequest(ServerRequestInterface $request) + { + if ($request->getMethod() === 'GET') { + $bodyParams = []; + } else { + $contentType = $request->getHeader('content-type'); + + if (! isset($contentType[0])) { + throw new RequestError('Missing "Content-Type" header'); + } + + if (stripos($contentType[0], 'application/graphql') !== false) { + $bodyParams = ['query' => $request->getBody()->getContents()]; + } elseif (stripos($contentType[0], 'application/json') !== false) { + $bodyParams = $request->getParsedBody(); + + if ($bodyParams === null) { + throw new InvariantViolation( + 'PSR-7 request is expected to provide parsed body for "application/json" requests but got null' + ); + } + + if (! is_array($bodyParams)) { + throw new RequestError( + 'GraphQL Server expects JSON object or array, but got ' . + Utils::printSafeJson($bodyParams) + ); + } + } else { + $bodyParams = $request->getParsedBody(); + + if (! is_array($bodyParams)) { + throw new RequestError('Unexpected content type: ' . Utils::printSafeJson($contentType[0])); + } + } + } + + return $this->parseRequestParams( + $request->getMethod(), + $bodyParams, + $request->getQueryParams() + ); + } + + /** + * Converts query execution result to PSR-7 response + * + * @param Promise|ExecutionResult|ExecutionResult[] $result + * + * @return Promise|ResponseInterface + * + * @api + */ + public function toPsrResponse($result, ResponseInterface $response, StreamInterface $writableBodyStream) + { + if ($result instanceof Promise) { + return $result->then(function ($actualResult) use ($response, $writableBodyStream) { + return $this->doConvertToPsrResponse($actualResult, $response, $writableBodyStream); + }); + } + + return $this->doConvertToPsrResponse($result, $response, $writableBodyStream); + } + + private function doConvertToPsrResponse($result, ResponseInterface $response, StreamInterface $writableBodyStream) + { + $httpStatus = $this->resolveHttpStatus($result); + + $result = json_encode($result); + $writableBodyStream->write($result); + + return $response + ->withStatus($httpStatus) + ->withHeader('Content-Type', 'application/json') + ->withBody($writableBodyStream); + } +} diff --git a/vendor/webonyx/graphql-php/src/Server/OperationParams.php b/vendor/webonyx/graphql-php/src/Server/OperationParams.php new file mode 100644 index 0000000..3ab12de --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Server/OperationParams.php @@ -0,0 +1,142 @@ +originalInput = $params; + + $params += [ + 'query' => null, + 'queryid' => null, + 'documentid' => null, // alias to queryid + 'id' => null, // alias to queryid + 'operationname' => null, + 'variables' => null, + 'extensions' => null, + ]; + + if ($params['variables'] === '') { + $params['variables'] = null; + } + + // Some parameters could be provided as serialized JSON. + foreach (['extensions', 'variables'] as $param) { + if (! is_string($params[$param])) { + continue; + } + + $tmp = json_decode($params[$param], true); + if (json_last_error()) { + continue; + } + + $params[$param] = $tmp; + } + + $instance->query = $params['query']; + $instance->queryId = $params['queryid'] ?: $params['documentid'] ?: $params['id']; + $instance->operation = $params['operationname']; + $instance->variables = $params['variables']; + $instance->extensions = $params['extensions']; + $instance->readOnly = $readonly; + + // Apollo server/client compatibility: look for the queryid in extensions + if (isset($instance->extensions['persistedQuery']['sha256Hash']) && empty($instance->query) && empty($instance->queryId)) { + $instance->queryId = $instance->extensions['persistedQuery']['sha256Hash']; + } + + return $instance; + } + + /** + * @param string $key + * + * @return mixed + * + * @api + */ + public function getOriginalInput($key) + { + return $this->originalInput[$key] ?? null; + } + + /** + * Indicates that operation is executed in read-only context + * (e.g. via HTTP GET request) + * + * @return bool + * + * @api + */ + public function isReadOnly() + { + return $this->readOnly; + } +} diff --git a/vendor/webonyx/graphql-php/src/Server/RequestError.php b/vendor/webonyx/graphql-php/src/Server/RequestError.php new file mode 100644 index 0000000..320aad4 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Server/RequestError.php @@ -0,0 +1,33 @@ +setSchema($mySchema) + * ->setContext($myContext); + * + * $server = new GraphQL\Server\StandardServer($config); + */ +class ServerConfig +{ + /** + * Converts an array of options to instance of ServerConfig + * (or just returns empty config when array is not passed). + * + * @param mixed[] $config + * + * @return ServerConfig + * + * @api + */ + public static function create(array $config = []) + { + $instance = new static(); + foreach ($config as $key => $value) { + $method = 'set' . ucfirst($key); + if (! method_exists($instance, $method)) { + throw new InvariantViolation(sprintf('Unknown server config option "%s"', $key)); + } + $instance->$method($value); + } + + return $instance; + } + + /** @var Schema */ + private $schema; + + /** @var mixed|callable */ + private $context; + + /** @var mixed|callable */ + private $rootValue; + + /** @var callable|null */ + private $errorFormatter; + + /** @var callable|null */ + private $errorsHandler; + + /** @var bool */ + private $debug = false; + + /** @var bool */ + private $queryBatching = false; + + /** @var ValidationRule[]|callable */ + private $validationRules; + + /** @var callable */ + private $fieldResolver; + + /** @var PromiseAdapter */ + private $promiseAdapter; + + /** @var callable */ + private $persistentQueryLoader; + + /** + * @return self + * + * @api + */ + public function setSchema(Schema $schema) + { + $this->schema = $schema; + + return $this; + } + + /** + * @param mixed|callable $context + * + * @return self + * + * @api + */ + public function setContext($context) + { + $this->context = $context; + + return $this; + } + + /** + * @param mixed|callable $rootValue + * + * @return self + * + * @api + */ + public function setRootValue($rootValue) + { + $this->rootValue = $rootValue; + + return $this; + } + + /** + * Expects function(Throwable $e) : array + * + * @return self + * + * @api + */ + public function setErrorFormatter(callable $errorFormatter) + { + $this->errorFormatter = $errorFormatter; + + return $this; + } + + /** + * Expects function(array $errors, callable $formatter) : array + * + * @return self + * + * @api + */ + public function setErrorsHandler(callable $handler) + { + $this->errorsHandler = $handler; + + return $this; + } + + /** + * Set validation rules for this server. + * + * @param ValidationRule[]|callable $validationRules + * + * @return self + * + * @api + */ + public function setValidationRules($validationRules) + { + if (! is_callable($validationRules) && ! is_array($validationRules) && $validationRules !== null) { + throw new InvariantViolation( + 'Server config expects array of validation rules or callable returning such array, but got ' . + Utils::printSafe($validationRules) + ); + } + + $this->validationRules = $validationRules; + + return $this; + } + + /** + * @return self + * + * @api + */ + public function setFieldResolver(callable $fieldResolver) + { + $this->fieldResolver = $fieldResolver; + + return $this; + } + + /** + * Expects function($queryId, OperationParams $params) : string|DocumentNode + * + * This function must return query string or valid DocumentNode. + * + * @return self + * + * @api + */ + public function setPersistentQueryLoader(callable $persistentQueryLoader) + { + $this->persistentQueryLoader = $persistentQueryLoader; + + return $this; + } + + /** + * Set response debug flags. See GraphQL\Error\Debug class for a list of all available flags + * + * @param bool|int $set + * + * @return self + * + * @api + */ + public function setDebug($set = true) + { + $this->debug = $set; + + return $this; + } + + /** + * Allow batching queries (disabled by default) + * + * @api + */ + public function setQueryBatching(bool $enableBatching) : self + { + $this->queryBatching = $enableBatching; + + return $this; + } + + /** + * @return self + * + * @api + */ + public function setPromiseAdapter(PromiseAdapter $promiseAdapter) + { + $this->promiseAdapter = $promiseAdapter; + + return $this; + } + + /** + * @return mixed|callable + */ + public function getContext() + { + return $this->context; + } + + /** + * @return mixed|callable + */ + public function getRootValue() + { + return $this->rootValue; + } + + /** + * @return Schema + */ + public function getSchema() + { + return $this->schema; + } + + /** + * @return callable|null + */ + public function getErrorFormatter() + { + return $this->errorFormatter; + } + + /** + * @return callable|null + */ + public function getErrorsHandler() + { + return $this->errorsHandler; + } + + /** + * @return PromiseAdapter + */ + public function getPromiseAdapter() + { + return $this->promiseAdapter; + } + + /** + * @return ValidationRule[]|callable + */ + public function getValidationRules() + { + return $this->validationRules; + } + + /** + * @return callable + */ + public function getFieldResolver() + { + return $this->fieldResolver; + } + + /** + * @return callable + */ + public function getPersistentQueryLoader() + { + return $this->persistentQueryLoader; + } + + /** + * @return bool + */ + public function getDebug() + { + return $this->debug; + } + + /** + * @return bool + */ + public function getQueryBatching() + { + return $this->queryBatching; + } +} diff --git a/vendor/webonyx/graphql-php/src/Server/StandardServer.php b/vendor/webonyx/graphql-php/src/Server/StandardServer.php new file mode 100644 index 0000000..7b7e627 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Server/StandardServer.php @@ -0,0 +1,185 @@ + $mySchema + * ]); + * $server->handleRequest(); + * + * Or using [ServerConfig](reference.md#graphqlserverserverconfig) instance: + * + * $config = GraphQL\Server\ServerConfig::create() + * ->setSchema($mySchema) + * ->setContext($myContext); + * + * $server = new GraphQL\Server\StandardServer($config); + * $server->handleRequest(); + * + * See [dedicated section in docs](executing-queries.md#using-server) for details. + */ +class StandardServer +{ + /** @var ServerConfig */ + private $config; + + /** @var Helper */ + private $helper; + + /** + * Converts and exception to error and sends spec-compliant HTTP 500 error. + * Useful when an exception is thrown somewhere outside of server execution context + * (e.g. during schema instantiation). + * + * @param Throwable $error + * @param bool $debug + * @param bool $exitWhenDone + * + * @api + */ + public static function send500Error($error, $debug = false, $exitWhenDone = false) + { + $response = [ + 'errors' => [FormattedError::createFromException($error, $debug)], + ]; + $helper = new Helper(); + $helper->emitResponse($response, 500, $exitWhenDone); + } + + /** + * Creates new instance of a standard GraphQL HTTP server + * + * @param ServerConfig|mixed[] $config + * + * @api + */ + public function __construct($config) + { + if (is_array($config)) { + $config = ServerConfig::create($config); + } + if (! $config instanceof ServerConfig) { + throw new InvariantViolation('Expecting valid server config, but got ' . Utils::printSafe($config)); + } + $this->config = $config; + $this->helper = new Helper(); + } + + /** + * Parses HTTP request, executes and emits response (using standard PHP `header` function and `echo`) + * + * By default (when $parsedBody is not set) it uses PHP globals to parse a request. + * It is possible to implement request parsing elsewhere (e.g. using framework Request instance) + * and then pass it to the server. + * + * See `executeRequest()` if you prefer to emit response yourself + * (e.g. using Response object of some framework) + * + * @param OperationParams|OperationParams[] $parsedBody + * @param bool $exitWhenDone + * + * @api + */ + public function handleRequest($parsedBody = null, $exitWhenDone = false) + { + $result = $this->executeRequest($parsedBody); + $this->helper->sendResponse($result, $exitWhenDone); + } + + /** + * Executes GraphQL operation and returns execution result + * (or promise when promise adapter is different from SyncPromiseAdapter). + * + * By default (when $parsedBody is not set) it uses PHP globals to parse a request. + * It is possible to implement request parsing elsewhere (e.g. using framework Request instance) + * and then pass it to the server. + * + * PSR-7 compatible method executePsrRequest() does exactly this. + * + * @param OperationParams|OperationParams[] $parsedBody + * + * @return ExecutionResult|ExecutionResult[]|Promise + * + * @throws InvariantViolation + * + * @api + */ + public function executeRequest($parsedBody = null) + { + if ($parsedBody === null) { + $parsedBody = $this->helper->parseHttpRequest(); + } + + if (is_array($parsedBody)) { + return $this->helper->executeBatch($this->config, $parsedBody); + } + + return $this->helper->executeOperation($this->config, $parsedBody); + } + + /** + * Executes PSR-7 request and fulfills PSR-7 response. + * + * See `executePsrRequest()` if you prefer to create response yourself + * (e.g. using specific JsonResponse instance of some framework). + * + * @return ResponseInterface|Promise + * + * @api + */ + public function processPsrRequest( + ServerRequestInterface $request, + ResponseInterface $response, + StreamInterface $writableBodyStream + ) { + $result = $this->executePsrRequest($request); + + return $this->helper->toPsrResponse($result, $response, $writableBodyStream); + } + + /** + * Executes GraphQL operation and returns execution result + * (or promise when promise adapter is different from SyncPromiseAdapter) + * + * @return ExecutionResult|ExecutionResult[]|Promise + * + * @api + */ + public function executePsrRequest(ServerRequestInterface $request) + { + $parsedBody = $this->helper->parsePsrRequest($request); + + return $this->executeRequest($parsedBody); + } + + /** + * Returns an instance of Server helper, which contains most of the actual logic for + * parsing / validating / executing request (which could be re-used by other server implementations) + * + * @return Helper + * + * @api + */ + public function getHelper() + { + return $this->helper; + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/AbstractType.php b/vendor/webonyx/graphql-php/src/Type/Definition/AbstractType.php new file mode 100644 index 0000000..356dceb --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/AbstractType.php @@ -0,0 +1,24 @@ +value; + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/CompositeType.php b/vendor/webonyx/graphql-php/src/Type/Definition/CompositeType.php new file mode 100644 index 0000000..7223ebe --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/CompositeType.php @@ -0,0 +1,16 @@ +config['serialize'], $value); + } + + /** + * @param mixed $value + * + * @return mixed + */ + public function parseValue($value) + { + if (isset($this->config['parseValue'])) { + return call_user_func($this->config['parseValue'], $value); + } + + return $value; + } + + /** + * @param Node $valueNode + * @param mixed[]|null $variables + * + * @return mixed + * + * @throws Exception + */ + public function parseLiteral(/* GraphQL\Language\AST\ValueNode */ + $valueNode, + ?array $variables = null + ) { + if (isset($this->config['parseLiteral'])) { + return call_user_func($this->config['parseLiteral'], $valueNode, $variables); + } + + return AST::valueFromASTUntyped($valueNode, $variables); + } + + public function assertValid() + { + parent::assertValid(); + + Utils::invariant( + isset($this->config['serialize']) && is_callable($this->config['serialize']), + sprintf('%s must provide "serialize" function. If this custom Scalar ', $this->name) . + 'is also used as an input type, ensure "parseValue" and "parseLiteral" ' . + 'functions are also provided.' + ); + if (! isset($this->config['parseValue']) && ! isset($this->config['parseLiteral'])) { + return; + } + + Utils::invariant( + isset($this->config['parseValue']) && isset($this->config['parseLiteral']) && + is_callable($this->config['parseValue']) && is_callable($this->config['parseLiteral']), + sprintf('%s must provide both "parseValue" and "parseLiteral" functions.', $this->name) + ); + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/Directive.php b/vendor/webonyx/graphql-php/src/Type/Definition/Directive.php new file mode 100644 index 0000000..0ffe496 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/Directive.php @@ -0,0 +1,172 @@ + $arg) { + if (is_array($arg)) { + $args[] = new FieldArgument($arg + ['name' => $name]); + } else { + $args[] = $arg; + } + } + $this->args = $args; + unset($config['args']); + } + foreach ($config as $key => $value) { + $this->{$key} = $value; + } + + Utils::invariant($this->name, 'Directive must be named.'); + Utils::invariant(is_array($this->locations), 'Must provide locations for directive.'); + $this->config = $config; + } + + /** + * @return Directive + */ + public static function includeDirective() + { + $internal = self::getInternalDirectives(); + + return $internal['include']; + } + + /** + * @return Directive[] + */ + public static function getInternalDirectives() + { + if (! self::$internalDirectives) { + self::$internalDirectives = [ + 'include' => new self([ + 'name' => self::INCLUDE_NAME, + 'description' => 'Directs the executor to include this field or fragment only when the `if` argument is true.', + 'locations' => [ + DirectiveLocation::FIELD, + DirectiveLocation::FRAGMENT_SPREAD, + DirectiveLocation::INLINE_FRAGMENT, + ], + 'args' => [new FieldArgument([ + 'name' => self::IF_ARGUMENT_NAME, + 'type' => Type::nonNull(Type::boolean()), + 'description' => 'Included when true.', + ]), + ], + ]), + 'skip' => new self([ + 'name' => self::SKIP_NAME, + 'description' => 'Directs the executor to skip this field or fragment when the `if` argument is true.', + 'locations' => [ + DirectiveLocation::FIELD, + DirectiveLocation::FRAGMENT_SPREAD, + DirectiveLocation::INLINE_FRAGMENT, + ], + 'args' => [new FieldArgument([ + 'name' => self::IF_ARGUMENT_NAME, + 'type' => Type::nonNull(Type::boolean()), + 'description' => 'Skipped when true.', + ]), + ], + ]), + 'deprecated' => new self([ + 'name' => self::DEPRECATED_NAME, + 'description' => 'Marks an element of a GraphQL schema as no longer supported.', + 'locations' => [ + DirectiveLocation::FIELD_DEFINITION, + DirectiveLocation::ENUM_VALUE, + ], + 'args' => [new FieldArgument([ + 'name' => self::REASON_ARGUMENT_NAME, + 'type' => Type::string(), + 'description' => + 'Explains why this element was deprecated, usually also including a ' . + 'suggestion for how to access supported similar data. Formatted ' . + 'in [Markdown](https://daringfireball.net/projects/markdown/).', + 'defaultValue' => self::DEFAULT_DEPRECATION_REASON, + ]), + ], + ]), + ]; + } + + return self::$internalDirectives; + } + + /** + * @return Directive + */ + public static function skipDirective() + { + $internal = self::getInternalDirectives(); + + return $internal['skip']; + } + + /** + * @return Directive + */ + public static function deprecatedDirective() + { + $internal = self::getInternalDirectives(); + + return $internal['deprecated']; + } + + /** + * @return bool + */ + public static function isSpecifiedDirective(Directive $directive) + { + return array_key_exists($directive->name, self::getInternalDirectives()); + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/EnumType.php b/vendor/webonyx/graphql-php/src/Type/Definition/EnumType.php new file mode 100644 index 0000000..dc83d69 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/EnumType.php @@ -0,0 +1,222 @@ + */ + private $valueLookup; + + /** @var ArrayObject */ + private $nameLookup; + + /** @var EnumTypeExtensionNode[] */ + public $extensionASTNodes; + + public function __construct($config) + { + if (! isset($config['name'])) { + $config['name'] = $this->tryInferName(); + } + + Utils::invariant(is_string($config['name']), 'Must provide name.'); + + $this->name = $config['name']; + $this->description = $config['description'] ?? null; + $this->astNode = $config['astNode'] ?? null; + $this->extensionASTNodes = $config['extensionASTNodes'] ?? null; + $this->config = $config; + } + + /** + * @param string|mixed[] $name + * + * @return EnumValueDefinition|null + */ + public function getValue($name) + { + $lookup = $this->getNameLookup(); + + if (! is_string($name)) { + return null; + } + + return $lookup[$name] ?? null; + } + + /** + * @return ArrayObject + */ + private function getNameLookup() + { + if (! $this->nameLookup) { + $lookup = new ArrayObject(); + foreach ($this->getValues() as $value) { + $lookup[$value->name] = $value; + } + $this->nameLookup = $lookup; + } + + return $this->nameLookup; + } + + /** + * @return EnumValueDefinition[] + */ + public function getValues() + { + if ($this->values === null) { + $this->values = []; + $config = $this->config; + + if (isset($config['values'])) { + if (! is_array($config['values'])) { + throw new InvariantViolation(sprintf('%s values must be an array', $this->name)); + } + foreach ($config['values'] as $name => $value) { + if (is_string($name)) { + if (is_array($value)) { + $value += ['name' => $name, 'value' => $name]; + } else { + $value = ['name' => $name, 'value' => $value]; + } + } elseif (is_int($name) && is_string($value)) { + $value = ['name' => $value, 'value' => $value]; + } else { + throw new InvariantViolation( + sprintf( + '%s values must be an array with value names as keys.', + $this->name + ) + ); + } + $this->values[] = new EnumValueDefinition($value); + } + } + } + + return $this->values; + } + + /** + * @param mixed $value + * + * @return mixed + * + * @throws Error + */ + public function serialize($value) + { + $lookup = $this->getValueLookup(); + if (isset($lookup[$value])) { + return $lookup[$value]->name; + } + + throw new Error('Cannot serialize value as enum: ' . Utils::printSafe($value)); + } + + /** + * @return MixedStore + */ + private function getValueLookup() + { + if ($this->valueLookup === null) { + $this->valueLookup = new MixedStore(); + + foreach ($this->getValues() as $valueName => $value) { + $this->valueLookup->offsetSet($value->value, $value); + } + } + + return $this->valueLookup; + } + + /** + * @param mixed $value + * + * @return mixed + * + * @throws Error + */ + public function parseValue($value) + { + $lookup = $this->getNameLookup(); + if (isset($lookup[$value])) { + return $lookup[$value]->value; + } + + throw new Error('Cannot represent value as enum: ' . Utils::printSafe($value)); + } + + /** + * @param Node $valueNode + * @param mixed[]|null $variables + * + * @return null + * + * @throws Exception + */ + public function parseLiteral($valueNode, ?array $variables = null) + { + if ($valueNode instanceof EnumValueNode) { + $lookup = $this->getNameLookup(); + if (isset($lookup[$valueNode->value])) { + $enumValue = $lookup[$valueNode->value]; + if ($enumValue !== null) { + return $enumValue->value; + } + } + } + + // Intentionally without message, as all information already in wrapped Exception + throw new Exception(); + } + + /** + * @throws InvariantViolation + */ + public function assertValid() + { + parent::assertValid(); + + Utils::invariant( + isset($this->config['values']), + sprintf('%s values must be an array.', $this->name) + ); + + $values = $this->getValues(); + foreach ($values as $value) { + Utils::invariant( + ! isset($value->config['isDeprecated']), + sprintf( + '%s.%s should provide "deprecationReason" instead of "isDeprecated".', + $this->name, + $value->name + ) + ); + } + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/EnumValueDefinition.php b/vendor/webonyx/graphql-php/src/Type/Definition/EnumValueDefinition.php new file mode 100644 index 0000000..9454f35 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/EnumValueDefinition.php @@ -0,0 +1,50 @@ +name = $config['name'] ?? null; + $this->value = $config['value'] ?? null; + $this->deprecationReason = $config['deprecationReason'] ?? null; + $this->description = $config['description'] ?? null; + $this->astNode = $config['astNode'] ?? null; + + $this->config = $config; + } + + /** + * @return bool + */ + public function isDeprecated() + { + return (bool) $this->deprecationReason; + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/FieldArgument.php b/vendor/webonyx/graphql-php/src/Type/Definition/FieldArgument.php new file mode 100644 index 0000000..3bffe57 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/FieldArgument.php @@ -0,0 +1,133 @@ + $value) { + switch ($key) { + case 'type': + $this->type = $value; + break; + case 'name': + $this->name = $value; + break; + case 'defaultValue': + $this->defaultValue = $value; + $this->defaultValueExists = true; + break; + case 'description': + $this->description = $value; + break; + case 'astNode': + $this->astNode = $value; + break; + } + } + $this->config = $def; + } + + /** + * @param mixed[] $config + * + * @return FieldArgument[] + */ + public static function createMap(array $config) + { + $map = []; + foreach ($config as $name => $argConfig) { + if (! is_array($argConfig)) { + $argConfig = ['type' => $argConfig]; + } + $map[] = new self($argConfig + ['name' => $name]); + } + + return $map; + } + + /** + * @return InputType + */ + public function getType() + { + return $this->type; + } + + /** + * @return bool + */ + public function defaultValueExists() + { + return $this->defaultValueExists; + } + + public function assertValid(FieldDefinition $parentField, Type $parentType) + { + try { + Utils::assertValidName($this->name); + } catch (InvariantViolation $e) { + throw new InvariantViolation( + sprintf('%s.%s(%s:) %s', $parentType->name, $parentField->name, $this->name, $e->getMessage()) + ); + } + $type = $this->type; + if ($type instanceof WrappingType) { + $type = $type->getWrappedType(true); + } + Utils::invariant( + $type instanceof InputType, + sprintf( + '%s.%s(%s): argument type must be Input Type but got: %s', + $parentType->name, + $parentField->name, + $this->name, + Utils::printSafe($this->type) + ) + ); + Utils::invariant( + $this->description === null || is_string($this->description), + sprintf( + '%s.%s(%s): argument description type must be string but got: %s', + $parentType->name, + $parentField->name, + $this->name, + Utils::printSafe($this->description) + ) + ); + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/FieldDefinition.php b/vendor/webonyx/graphql-php/src/Type/Definition/FieldDefinition.php new file mode 100644 index 0000000..8f409bf --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/FieldDefinition.php @@ -0,0 +1,243 @@ +name = $config['name']; + $this->type = $config['type']; + $this->resolveFn = $config['resolve'] ?? null; + $this->mapFn = $config['map'] ?? null; + $this->args = isset($config['args']) ? FieldArgument::createMap($config['args']) : []; + + $this->description = $config['description'] ?? null; + $this->deprecationReason = $config['deprecationReason'] ?? null; + $this->astNode = $config['astNode'] ?? null; + + $this->config = $config; + + $this->complexityFn = $config['complexity'] ?? self::DEFAULT_COMPLEXITY_FN; + } + + public static function defineFieldMap(Type $type, $fields) + { + if (is_callable($fields)) { + $fields = $fields(); + } + if (! is_array($fields)) { + throw new InvariantViolation( + sprintf('%s fields must be an array or a callable which returns such an array.', $type->name) + ); + } + $map = []; + foreach ($fields as $name => $field) { + if (is_array($field)) { + if (! isset($field['name'])) { + if (! is_string($name)) { + throw new InvariantViolation( + sprintf( + '%s fields must be an associative array with field names as keys or a function which returns such an array.', + $type->name + ) + ); + } + + $field['name'] = $name; + } + if (isset($field['args']) && ! is_array($field['args'])) { + throw new InvariantViolation( + sprintf('%s.%s args must be an array.', $type->name, $name) + ); + } + $fieldDef = self::create($field); + } elseif ($field instanceof self) { + $fieldDef = $field; + } else { + if (! is_string($name) || ! $field) { + throw new InvariantViolation( + sprintf( + '%s.%s field config must be an array, but got: %s', + $type->name, + $name, + Utils::printSafe($field) + ) + ); + } + + $fieldDef = self::create(['name' => $name, 'type' => $field]); + } + $map[$fieldDef->name] = $fieldDef; + } + + return $map; + } + + /** + * @param mixed[] $field + * + * @return FieldDefinition + */ + public static function create($field) + { + return new self($field); + } + + /** + * @param int $childrenComplexity + * + * @return mixed + */ + public static function defaultComplexity($childrenComplexity) + { + return $childrenComplexity + 1; + } + + /** + * @param string $name + * + * @return FieldArgument|null + */ + public function getArg($name) + { + foreach ($this->args ?: [] as $arg) { + /** @var FieldArgument $arg */ + if ($arg->name === $name) { + return $arg; + } + } + + return null; + } + + /** + * @return Type + */ + public function getType() + { + return $this->type; + } + + /** + * @return bool + */ + public function isDeprecated() + { + return (bool) $this->deprecationReason; + } + + /** + * @return callable|callable + */ + public function getComplexityFn() + { + return $this->complexityFn; + } + + /** + * @throws InvariantViolation + */ + public function assertValid(Type $parentType) + { + try { + Utils::assertValidName($this->name); + } catch (Error $e) { + throw new InvariantViolation(sprintf('%s.%s: %s', $parentType->name, $this->name, $e->getMessage())); + } + Utils::invariant( + ! isset($this->config['isDeprecated']), + sprintf( + '%s.%s should provide "deprecationReason" instead of "isDeprecated".', + $parentType->name, + $this->name + ) + ); + + $type = $this->type; + if ($type instanceof WrappingType) { + $type = $type->getWrappedType(true); + } + Utils::invariant( + $type instanceof OutputType, + sprintf( + '%s.%s field type must be Output Type but got: %s', + $parentType->name, + $this->name, + Utils::printSafe($this->type) + ) + ); + Utils::invariant( + $this->resolveFn === null || is_callable($this->resolveFn), + sprintf( + '%s.%s field resolver must be a function if provided, but got: %s', + $parentType->name, + $this->name, + Utils::printSafe($this->resolveFn) + ) + ); + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/FloatType.php b/vendor/webonyx/graphql-php/src/Type/Definition/FloatType.php new file mode 100644 index 0000000..e8923ca --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/FloatType.php @@ -0,0 +1,85 @@ +coerceFloat($value); + } + + private function coerceFloat($value) + { + if ($value === '') { + throw new Error( + 'Float cannot represent non numeric value: (empty string)' + ); + } + + if (! is_numeric($value) && $value !== true && $value !== false) { + throw new Error( + 'Float cannot represent non numeric value: ' . + Utils::printSafe($value) + ); + } + + return (float) $value; + } + + /** + * @param mixed $value + * + * @return float|null + * + * @throws Error + */ + public function parseValue($value) + { + return $this->coerceFloat($value); + } + + /** + * @param Node $valueNode + * @param mixed[]|null $variables + * + * @return float|null + * + * @throws Exception + */ + public function parseLiteral($valueNode, ?array $variables = null) + { + if ($valueNode instanceof FloatValueNode || $valueNode instanceof IntValueNode) { + return (float) $valueNode->value; + } + + // Intentionally without message, as all information already in wrapped Exception + throw new Exception(); + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/IDType.php b/vendor/webonyx/graphql-php/src/Type/Definition/IDType.php new file mode 100644 index 0000000..8077393 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/IDType.php @@ -0,0 +1,90 @@ +value; + } + + // Intentionally without message, as all information already in wrapped Exception + throw new Exception(); + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/InputObjectField.php b/vendor/webonyx/graphql-php/src/Type/Definition/InputObjectField.php new file mode 100644 index 0000000..82fa570 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/InputObjectField.php @@ -0,0 +1,108 @@ + $v) { + switch ($k) { + case 'defaultValue': + $this->defaultValue = $v; + $this->defaultValueExists = true; + break; + case 'defaultValueExists': + break; + default: + $this->{$k} = $v; + } + } + $this->config = $opts; + } + + /** + * @return mixed + */ + public function getType() + { + return $this->type; + } + + /** + * @return bool + */ + public function defaultValueExists() + { + return $this->defaultValueExists; + } + + /** + * @throws InvariantViolation + */ + public function assertValid(Type $parentType) + { + try { + Utils::assertValidName($this->name); + } catch (Error $e) { + throw new InvariantViolation(sprintf('%s.%s: %s', $parentType->name, $this->name, $e->getMessage())); + } + $type = $this->type; + if ($type instanceof WrappingType) { + $type = $type->getWrappedType(true); + } + Utils::invariant( + $type instanceof InputType, + sprintf( + '%s.%s field type must be Input Type but got: %s', + $parentType->name, + $this->name, + Utils::printSafe($this->type) + ) + ); + Utils::invariant( + empty($this->config['resolve']), + sprintf( + '%s.%s field type has a resolve property, but Input Types cannot define resolvers.', + $parentType->name, + $this->name + ) + ); + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/InputObjectType.php b/vendor/webonyx/graphql-php/src/Type/Definition/InputObjectType.php new file mode 100644 index 0000000..c921dda --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/InputObjectType.php @@ -0,0 +1,114 @@ +tryInferName(); + } + + Utils::invariant(is_string($config['name']), 'Must provide name.'); + + $this->config = $config; + $this->name = $config['name']; + $this->astNode = $config['astNode'] ?? null; + $this->description = $config['description'] ?? null; + $this->extensionASTNodes = $config['extensionASTNodes'] ?? null; + } + + /** + * @param string $name + * + * @return InputObjectField + * + * @throws Exception + */ + public function getField($name) + { + if ($this->fields === null) { + $this->getFields(); + } + Utils::invariant(isset($this->fields[$name]), "Field '%s' is not defined for type '%s'", $name, $this->name); + + return $this->fields[$name]; + } + + /** + * @return InputObjectField[] + */ + public function getFields() + { + if ($this->fields === null) { + $this->fields = []; + $fields = $this->config['fields'] ?? []; + $fields = is_callable($fields) ? call_user_func($fields) : $fields; + + if (! is_array($fields)) { + throw new InvariantViolation( + sprintf('%s fields must be an array or a callable which returns such an array.', $this->name) + ); + } + + foreach ($fields as $name => $field) { + if ($field instanceof Type) { + $field = ['type' => $field]; + } + $field = new InputObjectField($field + ['name' => $name]); + $this->fields[$field->name] = $field; + } + } + + return $this->fields; + } + + /** + * Validates type config and throws if one of type options is invalid. + * Note: this method is shallow, it won't validate object fields and their arguments. + * + * @throws InvariantViolation + */ + public function assertValid() + { + parent::assertValid(); + + Utils::invariant( + ! empty($this->getFields()), + sprintf( + '%s fields must be an associative array with field names as keys or a callable which returns such an array.', + $this->name + ) + ); + + foreach ($this->getFields() as $field) { + $field->assertValid($this); + } + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/InputType.php b/vendor/webonyx/graphql-php/src/Type/Definition/InputType.php new file mode 100644 index 0000000..0437657 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/InputType.php @@ -0,0 +1,23 @@ + + | GraphQLNonNull< + | GraphQLScalarType + | GraphQLEnumType + | GraphQLInputObjectType + | GraphQLList, + >; + */ + +interface InputType +{ +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/IntType.php b/vendor/webonyx/graphql-php/src/Type/Definition/IntType.php new file mode 100644 index 0000000..e6176c3 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/IntType.php @@ -0,0 +1,112 @@ +coerceInt($value); + } + + /** + * @param mixed $value + * + * @return int + */ + private function coerceInt($value) + { + if ($value === '') { + throw new Error( + 'Int cannot represent non 32-bit signed integer value: (empty string)' + ); + } + + $num = floatval($value); + if ((! is_numeric($value) && ! is_bool($value)) || $num > self::MAX_INT || $num < self::MIN_INT) { + throw new Error( + 'Int cannot represent non 32-bit signed integer value: ' . + Utils::printSafe($value) + ); + } + $int = intval($num); + // int cast with == used for performance reasons + // phpcs:ignore + if ($int != $num) { + throw new Error( + 'Int cannot represent non-integer value: ' . + Utils::printSafe($value) + ); + } + + return $int; + } + + /** + * @param mixed $value + * + * @return int|null + * + * @throws Error + */ + public function parseValue($value) + { + return $this->coerceInt($value); + } + + /** + * @param Node $valueNode + * @param mixed[]|null $variables + * + * @return int|null + * + * @throws Exception + */ + public function parseLiteral($valueNode, ?array $variables = null) + { + if ($valueNode instanceof IntValueNode) { + $val = (int) $valueNode->value; + if ($valueNode->value === (string) $val && self::MIN_INT <= $val && $val <= self::MAX_INT) { + return $val; + } + } + + // Intentionally without message, as all information already in wrapped Exception + throw new Exception(); + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/InterfaceType.php b/vendor/webonyx/graphql-php/src/Type/Definition/InterfaceType.php new file mode 100644 index 0000000..c13d7fb --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/InterfaceType.php @@ -0,0 +1,138 @@ +tryInferName(); + } + + Utils::invariant(is_string($config['name']), 'Must provide name.'); + + $this->name = $config['name']; + $this->description = $config['description'] ?? null; + $this->astNode = $config['astNode'] ?? null; + $this->extensionASTNodes = $config['extensionASTNodes'] ?? null; + $this->config = $config; + } + + /** + * @param mixed $type + * + * @return self + */ + public static function assertInterfaceType($type) + { + Utils::invariant( + $type instanceof self, + 'Expected ' . Utils::printSafe($type) . ' to be a GraphQL Interface type.' + ); + + return $type; + } + + /** + * @param string $name + * + * @return FieldDefinition + */ + public function getField($name) + { + if ($this->fields === null) { + $this->getFields(); + } + Utils::invariant(isset($this->fields[$name]), 'Field "%s" is not defined for type "%s"', $name, $this->name); + + return $this->fields[$name]; + } + + /** + * @param string $name + * + * @return bool + */ + public function hasField($name) + { + if ($this->fields === null) { + $this->getFields(); + } + + return isset($this->fields[$name]); + } + + /** + * @return FieldDefinition[] + */ + public function getFields() + { + if ($this->fields === null) { + $fields = $this->config['fields'] ?? []; + $this->fields = FieldDefinition::defineFieldMap($this, $fields); + } + + return $this->fields; + } + + /** + * Resolves concrete ObjectType for given object value + * + * @param object $objectValue + * @param mixed[] $context + * + * @return Type|null + */ + public function resolveType($objectValue, $context, ResolveInfo $info) + { + if (isset($this->config['resolveType'])) { + $fn = $this->config['resolveType']; + + return $fn($objectValue, $context, $info); + } + + return null; + } + + /** + * @throws InvariantViolation + */ + public function assertValid() + { + parent::assertValid(); + + $resolveType = $this->config['resolveType'] ?? null; + + Utils::invariant( + ! isset($resolveType) || is_callable($resolveType), + sprintf( + '%s must provide "resolveType" as a function, but got: %s', + $this->name, + Utils::printSafe($resolveType) + ) + ); + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/LeafType.php b/vendor/webonyx/graphql-php/src/Type/Definition/LeafType.php new file mode 100644 index 0000000..ece7355 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/LeafType.php @@ -0,0 +1,56 @@ +ofType = Type::assertType($type); + } + + public function toString() : string + { + return '[' . $this->ofType->toString() . ']'; + } + + /** + * @param bool $recurse + * + * @return ObjectType|InterfaceType|UnionType|ScalarType|InputObjectType|EnumType + */ + public function getWrappedType($recurse = false) + { + $type = $this->ofType; + + return $recurse && $type instanceof WrappingType ? $type->getWrappedType($recurse) : $type; + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/NamedType.php b/vendor/webonyx/graphql-php/src/Type/Definition/NamedType.php new file mode 100644 index 0000000..372bcc5 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/NamedType.php @@ -0,0 +1,19 @@ +ofType = self::assertNullableType($type); + } + + /** + * @param mixed $type + * + * @return NullableType + */ + public static function assertNullableType($type) + { + Utils::invariant( + Type::isType($type) && ! $type instanceof self, + 'Expected ' . Utils::printSafe($type) . ' to be a GraphQL nullable type.' + ); + + return $type; + } + + /** + * @param mixed $type + * + * @return self + */ + public static function assertNullType($type) + { + Utils::invariant( + $type instanceof self, + 'Expected ' . Utils::printSafe($type) . ' to be a GraphQL Non-Null type.' + ); + + return $type; + } + + /** + * @return string + */ + public function toString() + { + return $this->getWrappedType()->toString() . '!'; + } + + /** + * @param bool $recurse + * + * @return Type + */ + public function getWrappedType($recurse = false) + { + $type = $this->ofType; + + return $recurse && $type instanceof WrappingType ? $type->getWrappedType($recurse) : $type; + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/NullableType.php b/vendor/webonyx/graphql-php/src/Type/Definition/NullableType.php new file mode 100644 index 0000000..7ff70b2 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/NullableType.php @@ -0,0 +1,20 @@ +; + */ + +interface NullableType +{ +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/ObjectType.php b/vendor/webonyx/graphql-php/src/Type/Definition/ObjectType.php new file mode 100644 index 0000000..f509293 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/ObjectType.php @@ -0,0 +1,248 @@ + 'Address', + * 'fields' => [ + * 'street' => [ 'type' => GraphQL\Type\Definition\Type::string() ], + * 'number' => [ 'type' => GraphQL\Type\Definition\Type::int() ], + * 'formatted' => [ + * 'type' => GraphQL\Type\Definition\Type::string(), + * 'resolve' => function($obj) { + * return $obj->number . ' ' . $obj->street; + * } + * ] + * ] + * ]); + * + * When two types need to refer to each other, or a type needs to refer to + * itself in a field, you can use a function expression (aka a closure or a + * thunk) to supply the fields lazily. + * + * Example: + * + * $PersonType = null; + * $PersonType = new ObjectType([ + * 'name' => 'Person', + * 'fields' => function() use (&$PersonType) { + * return [ + * 'name' => ['type' => GraphQL\Type\Definition\Type::string() ], + * 'bestFriend' => [ 'type' => $PersonType ], + * ]; + * } + * ]); + */ +class ObjectType extends Type implements OutputType, CompositeType, NullableType, NamedType +{ + /** @var ObjectTypeDefinitionNode|null */ + public $astNode; + + /** @var ObjectTypeExtensionNode[] */ + public $extensionASTNodes; + + /** @var callable */ + public $resolveFieldFn; + + /** @var FieldDefinition[] */ + private $fields; + + /** @var InterfaceType[] */ + private $interfaces; + + /** @var InterfaceType[]|null */ + private $interfaceMap; + + /** + * @param mixed[] $config + */ + public function __construct(array $config) + { + if (! isset($config['name'])) { + $config['name'] = $this->tryInferName(); + } + + Utils::invariant(is_string($config['name']), 'Must provide name.'); + + $this->name = $config['name']; + $this->description = $config['description'] ?? null; + $this->resolveFieldFn = $config['resolveField'] ?? null; + $this->astNode = $config['astNode'] ?? null; + $this->extensionASTNodes = $config['extensionASTNodes'] ?? []; + $this->config = $config; + } + + /** + * @param mixed $type + * + * @return self + */ + public static function assertObjectType($type) + { + Utils::invariant( + $type instanceof self, + 'Expected ' . Utils::printSafe($type) . ' to be a GraphQL Object type.' + ); + + return $type; + } + + /** + * @param string $name + * + * @return FieldDefinition + * + * @throws Exception + */ + public function getField($name) + { + if ($this->fields === null) { + $this->getFields(); + } + Utils::invariant(isset($this->fields[$name]), 'Field "%s" is not defined for type "%s"', $name, $this->name); + + return $this->fields[$name]; + } + + /** + * @param string $name + * + * @return bool + */ + public function hasField($name) + { + if ($this->fields === null) { + $this->getFields(); + } + + return isset($this->fields[$name]); + } + + /** + * @return FieldDefinition[] + * + * @throws InvariantViolation + */ + public function getFields() + { + if ($this->fields === null) { + $fields = $this->config['fields'] ?? []; + $this->fields = FieldDefinition::defineFieldMap($this, $fields); + } + + return $this->fields; + } + + /** + * @param InterfaceType $iface + * + * @return bool + */ + public function implementsInterface($iface) + { + $map = $this->getInterfaceMap(); + + return isset($map[$iface->name]); + } + + private function getInterfaceMap() + { + if (! $this->interfaceMap) { + $this->interfaceMap = []; + foreach ($this->getInterfaces() as $interface) { + $this->interfaceMap[$interface->name] = $interface; + } + } + + return $this->interfaceMap; + } + + /** + * @return InterfaceType[] + */ + public function getInterfaces() + { + if ($this->interfaces === null) { + $interfaces = $this->config['interfaces'] ?? []; + $interfaces = is_callable($interfaces) ? call_user_func($interfaces) : $interfaces; + + if ($interfaces !== null && ! is_array($interfaces)) { + throw new InvariantViolation( + sprintf('%s interfaces must be an Array or a callable which returns an Array.', $this->name) + ); + } + + $this->interfaces = $interfaces ?: []; + } + + return $this->interfaces; + } + + /** + * @param mixed[] $value + * @param mixed[]|null $context + * + * @return bool|null + */ + public function isTypeOf($value, $context, ResolveInfo $info) + { + return isset($this->config['isTypeOf']) ? call_user_func( + $this->config['isTypeOf'], + $value, + $context, + $info + ) : null; + } + + /** + * Validates type config and throws if one of type options is invalid. + * Note: this method is shallow, it won't validate object fields and their arguments. + * + * @throws InvariantViolation + */ + public function assertValid() + { + parent::assertValid(); + + Utils::invariant( + $this->description === null || is_string($this->description), + sprintf( + '%s description must be string if set, but it is: %s', + $this->name, + Utils::printSafe($this->description) + ) + ); + + $isTypeOf = $this->config['isTypeOf'] ?? null; + + Utils::invariant( + $isTypeOf === null || is_callable($isTypeOf), + sprintf('%s must provide "isTypeOf" as a function, but got: %s', $this->name, Utils::printSafe($isTypeOf)) + ); + + foreach ($this->getFields() as $field) { + $field->assertValid($this); + } + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/OutputType.php b/vendor/webonyx/graphql-php/src/Type/Definition/OutputType.php new file mode 100644 index 0000000..7565a25 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/OutputType.php @@ -0,0 +1,19 @@ +schema = $schema; + $this->variableValues = $variableValues; + $this->fragments = $fragments; + $this->analyzeQueryPlan($parentType, $fieldNodes); + } + + /** + * @return mixed[] + */ + public function queryPlan() : array + { + return $this->queryPlan; + } + + /** + * @return string[] + */ + public function getReferencedTypes() : array + { + return array_keys($this->types); + } + + public function hasType(string $type) : bool + { + return count(array_filter($this->getReferencedTypes(), static function (string $referencedType) use ($type) { + return $type === $referencedType; + })) > 0; + } + + /** + * @return string[] + */ + public function getReferencedFields() : array + { + return array_values(array_unique(array_merge(...array_values($this->types)))); + } + + public function hasField(string $field) : bool + { + return count(array_filter($this->getReferencedFields(), static function (string $referencedField) use ($field) { + return $field === $referencedField; + })) > 0; + } + + /** + * @return string[] + */ + public function subFields(string $typename) : array + { + if (! array_key_exists($typename, $this->types)) { + return []; + } + + return $this->types[$typename]; + } + + /** + * @param FieldNode[] $fieldNodes + */ + private function analyzeQueryPlan(ObjectType $parentType, iterable $fieldNodes) : void + { + $queryPlan = []; + /** @var FieldNode $fieldNode */ + foreach ($fieldNodes as $fieldNode) { + if (! $fieldNode->selectionSet) { + continue; + } + + $type = $parentType->getField($fieldNode->name->value)->getType(); + if ($type instanceof WrappingType) { + $type = $type->getWrappedType(); + } + + $subfields = $this->analyzeSelectionSet($fieldNode->selectionSet, $type); + + $this->types[$type->name] = array_unique(array_merge( + array_key_exists($type->name, $this->types) ? $this->types[$type->name] : [], + array_keys($subfields) + )); + + $queryPlan = array_merge_recursive( + $queryPlan, + $subfields + ); + } + + $this->queryPlan = $queryPlan; + } + + /** + * @return mixed[] + * + * $parentType InterfaceType|ObjectType. + * + * @throws Error + */ + private function analyzeSelectionSet(SelectionSetNode $selectionSet, Type $parentType) : array + { + $fields = []; + foreach ($selectionSet->selections as $selectionNode) { + if ($selectionNode instanceof FieldNode) { + $fieldName = $selectionNode->name->value; + $type = $parentType->getField($fieldName); + $selectionType = $type->getType(); + + $subfields = []; + if ($selectionNode->selectionSet) { + $subfields = $this->analyzeSubFields($selectionType, $selectionNode->selectionSet); + } + + $fields[$fieldName] = [ + 'type' => $selectionType, + 'fields' => $subfields ?? [], + 'args' => Values::getArgumentValues($type, $selectionNode, $this->variableValues), + ]; + } elseif ($selectionNode instanceof FragmentSpreadNode) { + $spreadName = $selectionNode->name->value; + if (isset($this->fragments[$spreadName])) { + $fragment = $this->fragments[$spreadName]; + $type = $this->schema->getType($fragment->typeCondition->name->value); + $subfields = $this->analyzeSubFields($type, $fragment->selectionSet); + + $fields = $this->arrayMergeDeep( + $subfields, + $fields + ); + } + } elseif ($selectionNode instanceof InlineFragmentNode) { + $type = $this->schema->getType($selectionNode->typeCondition->name->value); + $subfields = $this->analyzeSubFields($type, $selectionNode->selectionSet); + + $fields = $this->arrayMergeDeep( + $subfields, + $fields + ); + } + } + + return $fields; + } + + /** + * @return mixed[] + */ + private function analyzeSubFields(Type $type, SelectionSetNode $selectionSet) : array + { + if ($type instanceof WrappingType) { + $type = $type->getWrappedType(); + } + + $subfields = []; + if ($type instanceof ObjectType) { + $subfields = $this->analyzeSelectionSet($selectionSet, $type); + $this->types[$type->name] = array_unique(array_merge( + array_key_exists($type->name, $this->types) ? $this->types[$type->name] : [], + array_keys($subfields) + )); + } + + return $subfields; + } + + /** + * similar to array_merge_recursive this merges nested arrays, but handles non array values differently + * while array_merge_recursive tries to merge non array values, in this implementation they will be overwritten + * + * @see https://stackoverflow.com/a/25712428 + * + * @param mixed[] $array1 + * @param mixed[] $array2 + * + * @return mixed[] + */ + private function arrayMergeDeep(array $array1, array $array2) : array + { + $merged = $array1; + + foreach ($array2 as $key => & $value) { + if (is_numeric($key)) { + if (! in_array($value, $merged, true)) { + $merged[] = $value; + } + } elseif (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) { + $merged[$key] = $this->arrayMergeDeep($merged[$key], $value); + } else { + $merged[$key] = $value; + } + } + + return $merged; + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/ResolveInfo.php b/vendor/webonyx/graphql-php/src/Type/Definition/ResolveInfo.php new file mode 100644 index 0000000..822a0fa --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/ResolveInfo.php @@ -0,0 +1,240 @@ +fieldName = $fieldName; + $this->fieldNodes = $fieldNodes; + $this->returnType = $returnType; + $this->parentType = $parentType; + $this->path = $path; + $this->schema = $schema; + $this->fragments = $fragments; + $this->rootValue = $rootValue; + $this->operation = $operation; + $this->variableValues = $variableValues; + } + + /** + * Helper method that returns names of all fields selected in query for + * $this->fieldName up to $depth levels. + * + * Example: + * query MyQuery{ + * { + * root { + * id, + * nested { + * nested1 + * nested2 { + * nested3 + * } + * } + * } + * } + * + * Given this ResolveInfo instance is a part of "root" field resolution, and $depth === 1, + * method will return: + * [ + * 'id' => true, + * 'nested' => [ + * nested1 => true, + * nested2 => true + * ] + * ] + * + * Warning: this method it is a naive implementation which does not take into account + * conditional typed fragments. So use it with care for fields of interface and union types. + * + * @param int $depth How many levels to include in output + * + * @return bool[] + * + * @api + */ + public function getFieldSelection($depth = 0) + { + $fields = []; + + /** @var FieldNode $fieldNode */ + foreach ($this->fieldNodes as $fieldNode) { + if ($fieldNode->selectionSet === null) { + continue; + } + + $fields = array_merge_recursive( + $fields, + $this->foldSelectionSet($fieldNode->selectionSet, $depth) + ); + } + + return $fields; + } + + public function lookAhead() : QueryPlan + { + if ($this->queryPlan === null) { + $this->queryPlan = new QueryPlan( + $this->parentType, + $this->schema, + $this->fieldNodes, + $this->variableValues, + $this->fragments + ); + } + + return $this->queryPlan; + } + + /** + * @return bool[] + */ + private function foldSelectionSet(SelectionSetNode $selectionSet, int $descend) : array + { + $fields = []; + foreach ($selectionSet->selections as $selectionNode) { + if ($selectionNode instanceof FieldNode) { + $fields[$selectionNode->name->value] = $descend > 0 && ! empty($selectionNode->selectionSet) + ? $this->foldSelectionSet($selectionNode->selectionSet, $descend - 1) + : true; + } elseif ($selectionNode instanceof FragmentSpreadNode) { + $spreadName = $selectionNode->name->value; + if (isset($this->fragments[$spreadName])) { + /** @var FragmentDefinitionNode $fragment */ + $fragment = $this->fragments[$spreadName]; + $fields = array_merge_recursive( + $this->foldSelectionSet($fragment->selectionSet, $descend), + $fields + ); + } + } elseif ($selectionNode instanceof InlineFragmentNode) { + $fields = array_merge_recursive( + $this->foldSelectionSet($selectionNode->selectionSet, $descend), + $fields + ); + } + } + + return $fields; + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/ScalarType.php b/vendor/webonyx/graphql-php/src/Type/Definition/ScalarType.php new file mode 100644 index 0000000..17bf6e7 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/ScalarType.php @@ -0,0 +1,51 @@ +name = $config['name'] ?? $this->tryInferName(); + $this->description = $config['description'] ?? $this->description; + $this->astNode = $config['astNode'] ?? null; + $this->extensionASTNodes = $config['extensionASTNodes'] ?? null; + $this->config = $config; + + Utils::invariant(is_string($this->name), 'Must provide name.'); + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/StringType.php b/vendor/webonyx/graphql-php/src/Type/Definition/StringType.php new file mode 100644 index 0000000..533298f --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/StringType.php @@ -0,0 +1,97 @@ +coerceString($value); + } + + private function coerceString($value) + { + if (is_array($value)) { + throw new Error( + 'String cannot represent an array value: ' . + Utils::printSafe($value) + ); + } + + return (string) $value; + } + + /** + * @param mixed $value + * + * @return string + * + * @throws Error + */ + public function parseValue($value) + { + return $this->coerceString($value); + } + + /** + * @param Node $valueNode + * @param mixed[]|null $variables + * + * @return string|null + * + * @throws Exception + */ + public function parseLiteral($valueNode, ?array $variables = null) + { + if ($valueNode instanceof StringValueNode) { + return $valueNode->value; + } + + // Intentionally without message, as all information already in wrapped Exception + throw new Exception(); + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/Type.php b/vendor/webonyx/graphql-php/src/Type/Definition/Type.php new file mode 100644 index 0000000..69faa1c --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/Type.php @@ -0,0 +1,410 @@ + new IDType(), + self::STRING => new StringType(), + self::FLOAT => new FloatType(), + self::INT => new IntType(), + self::BOOLEAN => new BooleanType(), + ]; + } + + return $name ? self::$standardTypes[$name] : self::$standardTypes; + } + + /** + * @return StringType + * + * @api + */ + public static function string() + { + return self::getStandardType(self::STRING); + } + + /** + * @return BooleanType + * + * @api + */ + public static function boolean() + { + return self::getStandardType(self::BOOLEAN); + } + + /** + * @return IntType + * + * @api + */ + public static function int() + { + return self::getStandardType(self::INT); + } + + /** + * @return FloatType + * + * @api + */ + public static function float() + { + return self::getStandardType(self::FLOAT); + } + + /** + * @param Type|ObjectType|InterfaceType|UnionType|ScalarType|InputObjectType|EnumType|ListOfType|NonNull $wrappedType + * + * @return ListOfType + * + * @api + */ + public static function listOf($wrappedType) + { + return new ListOfType($wrappedType); + } + + /** + * @param NullableType $wrappedType + * + * @return NonNull + * + * @api + */ + public static function nonNull($wrappedType) + { + return new NonNull($wrappedType); + } + + /** + * Checks if the type is a builtin type + * + * @return bool + */ + public static function isBuiltInType(Type $type) + { + return in_array($type->name, array_keys(self::getAllBuiltInTypes()), true); + } + + /** + * Returns all builtin in types including base scalar and + * introspection types + * + * @return Type[] + */ + public static function getAllBuiltInTypes() + { + if (self::$builtInTypes === null) { + self::$builtInTypes = array_merge( + Introspection::getTypes(), + self::getStandardTypes() + ); + } + + return self::$builtInTypes; + } + + /** + * Returns all builtin scalar types + * + * @return Type[] + */ + public static function getStandardTypes() + { + return self::getStandardType(); + } + + /** + * @deprecated Use method getStandardTypes() instead + * + * @return Type[] + */ + public static function getInternalTypes() + { + trigger_error(__METHOD__ . ' is deprecated. Use Type::getStandardTypes() instead', E_USER_DEPRECATED); + + return self::getStandardTypes(); + } + + /** + * @param Type[] $types + */ + public static function overrideStandardTypes(array $types) + { + $standardTypes = self::getStandardTypes(); + foreach ($types as $type) { + Utils::invariant( + $type instanceof Type, + 'Expecting instance of %s, got %s', + self::class, + Utils::printSafe($type) + ); + Utils::invariant( + isset($type->name, $standardTypes[$type->name]), + 'Expecting one of the following names for a standard type: %s, got %s', + implode(', ', array_keys($standardTypes)), + Utils::printSafe($type->name ?? null) + ); + $standardTypes[$type->name] = $type; + } + self::$standardTypes = $standardTypes; + } + + /** + * @param Type $type + * + * @return bool + * + * @api + */ + public static function isInputType($type) + { + return $type instanceof InputType && + ( + ! $type instanceof WrappingType || + self::getNamedType($type) instanceof InputType + ); + } + + /** + * @param Type $type + * + * @return ObjectType|InterfaceType|UnionType|ScalarType|InputObjectType|EnumType + * + * @api + */ + public static function getNamedType($type) + { + if ($type === null) { + return null; + } + while ($type instanceof WrappingType) { + $type = $type->getWrappedType(); + } + + return $type; + } + + /** + * @param Type $type + * + * @return bool + * + * @api + */ + public static function isOutputType($type) + { + return $type instanceof OutputType && + ( + ! $type instanceof WrappingType || + self::getNamedType($type) instanceof OutputType + ); + } + + /** + * @param Type $type + * + * @return bool + * + * @api + */ + public static function isLeafType($type) + { + return $type instanceof LeafType; + } + + /** + * @param Type $type + * + * @return bool + * + * @api + */ + public static function isCompositeType($type) + { + return $type instanceof CompositeType; + } + + /** + * @param Type $type + * + * @return bool + * + * @api + */ + public static function isAbstractType($type) + { + return $type instanceof AbstractType; + } + + /** + * @param mixed $type + * + * @return mixed + */ + public static function assertType($type) + { + Utils::invariant( + self::isType($type), + 'Expected ' . Utils::printSafe($type) . ' to be a GraphQL type.' + ); + + return $type; + } + + /** + * @param Type $type + * + * @return bool + * + * @api + */ + public static function isType($type) + { + return $type instanceof Type; + } + + /** + * @param Type $type + * + * @return NullableType + * + * @api + */ + public static function getNullableType($type) + { + return $type instanceof NonNull ? $type->getWrappedType() : $type; + } + + /** + * @throws InvariantViolation + */ + public function assertValid() + { + Utils::assertValidName($this->name); + } + + /** + * @return string + */ + public function jsonSerialize() + { + return $this->toString(); + } + + /** + * @return string + */ + public function toString() + { + return $this->name; + } + + /** + * @return string + */ + public function __toString() + { + try { + return $this->toString(); + } catch (Exception $e) { + echo $e; + } catch (Throwable $e) { + echo $e; + } + } + + /** + * @return string|null + */ + protected function tryInferName() + { + if ($this->name) { + return $this->name; + } + + // If class is extended - infer name from className + // QueryType -> Type + // SomeOtherType -> SomeOther + $tmp = new ReflectionClass($this); + $name = $tmp->getShortName(); + + if ($tmp->getNamespaceName() !== __NAMESPACE__) { + return preg_replace('~Type$~', '', $name); + } + + return null; + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/UnionType.php b/vendor/webonyx/graphql-php/src/Type/Definition/UnionType.php new file mode 100644 index 0000000..3229df4 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/UnionType.php @@ -0,0 +1,135 @@ +tryInferName(); + } + + Utils::invariant(is_string($config['name']), 'Must provide name.'); + + /** + * Optionally provide a custom type resolver function. If one is not provided, + * the default implemenation will call `isTypeOf` on each implementing + * Object type. + */ + $this->name = $config['name']; + $this->description = $config['description'] ?? null; + $this->astNode = $config['astNode'] ?? null; + $this->extensionASTNodes = $config['extensionASTNodes'] ?? null; + $this->config = $config; + } + + public function isPossibleType(Type $type) : bool + { + if (! $type instanceof ObjectType) { + return false; + } + + if ($this->possibleTypeNames === null) { + $this->possibleTypeNames = []; + foreach ($this->getTypes() as $possibleType) { + $this->possibleTypeNames[$possibleType->name] = true; + } + } + + return isset($this->possibleTypeNames[$type->name]); + } + + /** + * @return ObjectType[] + */ + public function getTypes() + { + if ($this->types === null) { + if (! isset($this->config['types'])) { + $types = null; + } elseif (is_callable($this->config['types'])) { + $types = call_user_func($this->config['types']); + } else { + $types = $this->config['types']; + } + + if (! is_array($types)) { + throw new InvariantViolation( + sprintf( + 'Must provide Array of types or a callable which returns such an array for Union %s', + $this->name + ) + ); + } + + $this->types = $types; + } + + return $this->types; + } + + /** + * Resolves concrete ObjectType for given object value + * + * @param object $objectValue + * @param mixed $context + * + * @return callable|null + */ + public function resolveType($objectValue, $context, ResolveInfo $info) + { + if (isset($this->config['resolveType'])) { + $fn = $this->config['resolveType']; + + return $fn($objectValue, $context, $info); + } + + return null; + } + + /** + * @throws InvariantViolation + */ + public function assertValid() + { + parent::assertValid(); + + if (! isset($this->config['resolveType'])) { + return; + } + + Utils::invariant( + is_callable($this->config['resolveType']), + sprintf( + '%s must provide "resolveType" as a function, but got: %s', + $this->name, + Utils::printSafe($this->config['resolveType']) + ) + ); + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Definition/UnmodifiedType.php b/vendor/webonyx/graphql-php/src/Type/Definition/UnmodifiedType.php new file mode 100644 index 0000000..7a31c47 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Definition/UnmodifiedType.php @@ -0,0 +1,19 @@ + boolean]).', + E_USER_DEPRECATED + ); + $descriptions = $options; + } else { + $descriptions = ! array_key_exists('descriptions', $options) || $options['descriptions'] === true; + } + $descriptionField = $descriptions ? 'description' : ''; + + return <<name, self::getTypes()); + } + + public static function getTypes() + { + return [ + '__Schema' => self::_schema(), + '__Type' => self::_type(), + '__Directive' => self::_directive(), + '__Field' => self::_field(), + '__InputValue' => self::_inputValue(), + '__EnumValue' => self::_enumValue(), + '__TypeKind' => self::_typeKind(), + '__DirectiveLocation' => self::_directiveLocation(), + ]; + } + + public static function _schema() + { + if (! isset(self::$map['__Schema'])) { + self::$map['__Schema'] = new ObjectType([ + 'name' => '__Schema', + 'isIntrospection' => true, + 'description' => + 'A GraphQL Schema defines the capabilities of a GraphQL ' . + 'server. It exposes all available types and directives on ' . + 'the server, as well as the entry points for query, mutation, and ' . + 'subscription operations.', + 'fields' => [ + 'types' => [ + 'description' => 'A list of all types supported by this server.', + 'type' => new NonNull(new ListOfType(new NonNull(self::_type()))), + 'resolve' => static function (Schema $schema) { + return array_values($schema->getTypeMap()); + }, + ], + 'queryType' => [ + 'description' => 'The type that query operations will be rooted at.', + 'type' => new NonNull(self::_type()), + 'resolve' => static function (Schema $schema) { + return $schema->getQueryType(); + }, + ], + 'mutationType' => [ + 'description' => + 'If this server supports mutation, the type that ' . + 'mutation operations will be rooted at.', + 'type' => self::_type(), + 'resolve' => static function (Schema $schema) { + return $schema->getMutationType(); + }, + ], + 'subscriptionType' => [ + 'description' => 'If this server support subscription, the type that subscription operations will be rooted at.', + 'type' => self::_type(), + 'resolve' => static function (Schema $schema) { + return $schema->getSubscriptionType(); + }, + ], + 'directives' => [ + 'description' => 'A list of all directives supported by this server.', + 'type' => Type::nonNull(Type::listOf(Type::nonNull(self::_directive()))), + 'resolve' => static function (Schema $schema) { + return $schema->getDirectives(); + }, + ], + ], + ]); + } + + return self::$map['__Schema']; + } + + public static function _type() + { + if (! isset(self::$map['__Type'])) { + self::$map['__Type'] = new ObjectType([ + 'name' => '__Type', + 'isIntrospection' => true, + 'description' => + 'The fundamental unit of any GraphQL Schema is the type. There are ' . + 'many kinds of types in GraphQL as represented by the `__TypeKind` enum.' . + "\n\n" . + 'Depending on the kind of a type, certain fields describe ' . + 'information about that type. Scalar types provide no information ' . + 'beyond a name and description, while Enum types provide their values. ' . + 'Object and Interface types provide the fields they describe. Abstract ' . + 'types, Union and Interface, provide the Object types possible ' . + 'at runtime. List and NonNull types compose other types.', + 'fields' => static function () { + return [ + 'kind' => [ + 'type' => Type::nonNull(self::_typeKind()), + 'resolve' => static function (Type $type) { + switch (true) { + case $type instanceof ListOfType: + return TypeKind::LIST_KIND; + case $type instanceof NonNull: + return TypeKind::NON_NULL; + case $type instanceof ScalarType: + return TypeKind::SCALAR; + case $type instanceof ObjectType: + return TypeKind::OBJECT; + case $type instanceof EnumType: + return TypeKind::ENUM; + case $type instanceof InputObjectType: + return TypeKind::INPUT_OBJECT; + case $type instanceof InterfaceType: + return TypeKind::INTERFACE_KIND; + case $type instanceof UnionType: + return TypeKind::UNION; + default: + throw new Exception('Unknown kind of type: ' . Utils::printSafe($type)); + } + }, + ], + 'name' => [ + 'type' => Type::string(), + 'resolve' => static function ($obj) { + return $obj->name; + }, + ], + 'description' => [ + 'type' => Type::string(), + 'resolve' => static function ($obj) { + return $obj->description; + }, + ], + 'fields' => [ + 'type' => Type::listOf(Type::nonNull(self::_field())), + 'args' => [ + 'includeDeprecated' => ['type' => Type::boolean(), 'defaultValue' => false], + ], + 'resolve' => static function (Type $type, $args) { + if ($type instanceof ObjectType || $type instanceof InterfaceType) { + $fields = $type->getFields(); + + if (empty($args['includeDeprecated'])) { + $fields = array_filter( + $fields, + static function (FieldDefinition $field) { + return ! $field->deprecationReason; + } + ); + } + + return array_values($fields); + } + + return null; + }, + ], + 'interfaces' => [ + 'type' => Type::listOf(Type::nonNull(self::_type())), + 'resolve' => static function ($type) { + if ($type instanceof ObjectType) { + return $type->getInterfaces(); + } + + return null; + }, + ], + 'possibleTypes' => [ + 'type' => Type::listOf(Type::nonNull(self::_type())), + 'resolve' => static function ($type, $args, $context, ResolveInfo $info) { + if ($type instanceof InterfaceType || $type instanceof UnionType) { + return $info->schema->getPossibleTypes($type); + } + + return null; + }, + ], + 'enumValues' => [ + 'type' => Type::listOf(Type::nonNull(self::_enumValue())), + 'args' => [ + 'includeDeprecated' => ['type' => Type::boolean(), 'defaultValue' => false], + ], + 'resolve' => static function ($type, $args) { + if ($type instanceof EnumType) { + $values = array_values($type->getValues()); + + if (empty($args['includeDeprecated'])) { + $values = array_filter( + $values, + static function ($value) { + return ! $value->deprecationReason; + } + ); + } + + return $values; + } + + return null; + }, + ], + 'inputFields' => [ + 'type' => Type::listOf(Type::nonNull(self::_inputValue())), + 'resolve' => static function ($type) { + if ($type instanceof InputObjectType) { + return array_values($type->getFields()); + } + + return null; + }, + ], + 'ofType' => [ + 'type' => self::_type(), + 'resolve' => static function ($type) { + if ($type instanceof WrappingType) { + return $type->getWrappedType(); + } + + return null; + }, + ], + ]; + }, + ]); + } + + return self::$map['__Type']; + } + + public static function _typeKind() + { + if (! isset(self::$map['__TypeKind'])) { + self::$map['__TypeKind'] = new EnumType([ + 'name' => '__TypeKind', + 'isIntrospection' => true, + 'description' => 'An enum describing what kind of type a given `__Type` is.', + 'values' => [ + 'SCALAR' => [ + 'value' => TypeKind::SCALAR, + 'description' => 'Indicates this type is a scalar.', + ], + 'OBJECT' => [ + 'value' => TypeKind::OBJECT, + 'description' => 'Indicates this type is an object. `fields` and `interfaces` are valid fields.', + ], + 'INTERFACE' => [ + 'value' => TypeKind::INTERFACE_KIND, + 'description' => 'Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.', + ], + 'UNION' => [ + 'value' => TypeKind::UNION, + 'description' => 'Indicates this type is a union. `possibleTypes` is a valid field.', + ], + 'ENUM' => [ + 'value' => TypeKind::ENUM, + 'description' => 'Indicates this type is an enum. `enumValues` is a valid field.', + ], + 'INPUT_OBJECT' => [ + 'value' => TypeKind::INPUT_OBJECT, + 'description' => 'Indicates this type is an input object. `inputFields` is a valid field.', + ], + 'LIST' => [ + 'value' => TypeKind::LIST_KIND, + 'description' => 'Indicates this type is a list. `ofType` is a valid field.', + ], + 'NON_NULL' => [ + 'value' => TypeKind::NON_NULL, + 'description' => 'Indicates this type is a non-null. `ofType` is a valid field.', + ], + ], + ]); + } + + return self::$map['__TypeKind']; + } + + public static function _field() + { + if (! isset(self::$map['__Field'])) { + self::$map['__Field'] = new ObjectType([ + 'name' => '__Field', + 'isIntrospection' => true, + 'description' => + 'Object and Interface types are described by a list of Fields, each of ' . + 'which has a name, potentially a list of arguments, and a return type.', + 'fields' => static function () { + return [ + 'name' => [ + 'type' => Type::nonNull(Type::string()), + 'resolve' => static function (FieldDefinition $field) { + return $field->name; + }, + ], + 'description' => [ + 'type' => Type::string(), + 'resolve' => static function (FieldDefinition $field) { + return $field->description; + }, + ], + 'args' => [ + 'type' => Type::nonNull(Type::listOf(Type::nonNull(self::_inputValue()))), + 'resolve' => static function (FieldDefinition $field) { + return empty($field->args) ? [] : $field->args; + }, + ], + 'type' => [ + 'type' => Type::nonNull(self::_type()), + 'resolve' => static function (FieldDefinition $field) { + return $field->getType(); + }, + ], + 'isDeprecated' => [ + 'type' => Type::nonNull(Type::boolean()), + 'resolve' => static function (FieldDefinition $field) { + return (bool) $field->deprecationReason; + }, + ], + 'deprecationReason' => [ + 'type' => Type::string(), + 'resolve' => static function (FieldDefinition $field) { + return $field->deprecationReason; + }, + ], + ]; + }, + ]); + } + + return self::$map['__Field']; + } + + public static function _inputValue() + { + if (! isset(self::$map['__InputValue'])) { + self::$map['__InputValue'] = new ObjectType([ + 'name' => '__InputValue', + 'isIntrospection' => true, + 'description' => + 'Arguments provided to Fields or Directives and the input fields of an ' . + 'InputObject are represented as Input Values which describe their type ' . + 'and optionally a default value.', + 'fields' => static function () { + return [ + 'name' => [ + 'type' => Type::nonNull(Type::string()), + 'resolve' => static function ($inputValue) { + /** @var FieldArgument|InputObjectField $inputValue */ + return $inputValue->name; + }, + ], + 'description' => [ + 'type' => Type::string(), + 'resolve' => static function ($inputValue) { + /** @var FieldArgument|InputObjectField $inputValue */ + return $inputValue->description; + }, + ], + 'type' => [ + 'type' => Type::nonNull(self::_type()), + 'resolve' => static function ($value) { + return method_exists($value, 'getType') ? $value->getType() : $value->type; + }, + ], + 'defaultValue' => [ + 'type' => Type::string(), + 'description' => + 'A GraphQL-formatted string representing the default value for this input value.', + 'resolve' => static function ($inputValue) { + /** @var FieldArgument|InputObjectField $inputValue */ + return ! $inputValue->defaultValueExists() + ? null + : Printer::doPrint(AST::astFromValue( + $inputValue->defaultValue, + $inputValue->getType() + )); + }, + ], + ]; + }, + ]); + } + + return self::$map['__InputValue']; + } + + public static function _enumValue() + { + if (! isset(self::$map['__EnumValue'])) { + self::$map['__EnumValue'] = new ObjectType([ + 'name' => '__EnumValue', + 'isIntrospection' => true, + 'description' => + 'One possible value for a given Enum. Enum values are unique values, not ' . + 'a placeholder for a string or numeric value. However an Enum value is ' . + 'returned in a JSON response as a string.', + 'fields' => [ + 'name' => [ + 'type' => Type::nonNull(Type::string()), + 'resolve' => static function ($enumValue) { + return $enumValue->name; + }, + ], + 'description' => [ + 'type' => Type::string(), + 'resolve' => static function ($enumValue) { + return $enumValue->description; + }, + ], + 'isDeprecated' => [ + 'type' => Type::nonNull(Type::boolean()), + 'resolve' => static function ($enumValue) { + return (bool) $enumValue->deprecationReason; + }, + ], + 'deprecationReason' => [ + 'type' => Type::string(), + 'resolve' => static function ($enumValue) { + return $enumValue->deprecationReason; + }, + ], + ], + ]); + } + + return self::$map['__EnumValue']; + } + + public static function _directive() + { + if (! isset(self::$map['__Directive'])) { + self::$map['__Directive'] = new ObjectType([ + 'name' => '__Directive', + 'isIntrospection' => true, + 'description' => 'A Directive provides a way to describe alternate runtime execution and ' . + 'type validation behavior in a GraphQL document.' . + "\n\nIn some cases, you need to provide options to alter GraphQL's " . + 'execution behavior in ways field arguments will not suffice, such as ' . + 'conditionally including or skipping a field. Directives provide this by ' . + 'describing additional information to the executor.', + 'fields' => [ + 'name' => [ + 'type' => Type::nonNull(Type::string()), + 'resolve' => static function ($obj) { + return $obj->name; + }, + ], + 'description' => [ + 'type' => Type::string(), + 'resolve' => static function ($obj) { + return $obj->description; + }, + ], + 'locations' => [ + 'type' => Type::nonNull(Type::listOf(Type::nonNull( + self::_directiveLocation() + ))), + 'resolve' => static function ($obj) { + return $obj->locations; + }, + ], + 'args' => [ + 'type' => Type::nonNull(Type::listOf(Type::nonNull(self::_inputValue()))), + 'resolve' => static function (Directive $directive) { + return $directive->args ?: []; + }, + ], + + // NOTE: the following three fields are deprecated and are no longer part + // of the GraphQL specification. + 'onOperation' => [ + 'deprecationReason' => 'Use `locations`.', + 'type' => Type::nonNull(Type::boolean()), + 'resolve' => static function ($d) { + return in_array(DirectiveLocation::QUERY, $d->locations, true) || + in_array(DirectiveLocation::MUTATION, $d->locations, true) || + in_array(DirectiveLocation::SUBSCRIPTION, $d->locations, true); + }, + ], + 'onFragment' => [ + 'deprecationReason' => 'Use `locations`.', + 'type' => Type::nonNull(Type::boolean()), + 'resolve' => static function ($d) { + return in_array(DirectiveLocation::FRAGMENT_SPREAD, $d->locations, true) || + in_array(DirectiveLocation::INLINE_FRAGMENT, $d->locations, true) || + in_array(DirectiveLocation::FRAGMENT_DEFINITION, $d->locations, true); + }, + ], + 'onField' => [ + 'deprecationReason' => 'Use `locations`.', + 'type' => Type::nonNull(Type::boolean()), + 'resolve' => static function ($d) { + return in_array(DirectiveLocation::FIELD, $d->locations, true); + }, + ], + ], + ]); + } + + return self::$map['__Directive']; + } + + public static function _directiveLocation() + { + if (! isset(self::$map['__DirectiveLocation'])) { + self::$map['__DirectiveLocation'] = new EnumType([ + 'name' => '__DirectiveLocation', + 'isIntrospection' => true, + 'description' => + 'A Directive can be adjacent to many parts of the GraphQL language, a ' . + '__DirectiveLocation describes one such possible adjacencies.', + 'values' => [ + 'QUERY' => [ + 'value' => DirectiveLocation::QUERY, + 'description' => 'Location adjacent to a query operation.', + ], + 'MUTATION' => [ + 'value' => DirectiveLocation::MUTATION, + 'description' => 'Location adjacent to a mutation operation.', + ], + 'SUBSCRIPTION' => [ + 'value' => DirectiveLocation::SUBSCRIPTION, + 'description' => 'Location adjacent to a subscription operation.', + ], + 'FIELD' => [ + 'value' => DirectiveLocation::FIELD, + 'description' => 'Location adjacent to a field.', + ], + 'FRAGMENT_DEFINITION' => [ + 'value' => DirectiveLocation::FRAGMENT_DEFINITION, + 'description' => 'Location adjacent to a fragment definition.', + ], + 'FRAGMENT_SPREAD' => [ + 'value' => DirectiveLocation::FRAGMENT_SPREAD, + 'description' => 'Location adjacent to a fragment spread.', + ], + 'INLINE_FRAGMENT' => [ + 'value' => DirectiveLocation::INLINE_FRAGMENT, + 'description' => 'Location adjacent to an inline fragment.', + ], + 'SCHEMA' => [ + 'value' => DirectiveLocation::SCHEMA, + 'description' => 'Location adjacent to a schema definition.', + ], + 'SCALAR' => [ + 'value' => DirectiveLocation::SCALAR, + 'description' => 'Location adjacent to a scalar definition.', + ], + 'OBJECT' => [ + 'value' => DirectiveLocation::OBJECT, + 'description' => 'Location adjacent to an object type definition.', + ], + 'FIELD_DEFINITION' => [ + 'value' => DirectiveLocation::FIELD_DEFINITION, + 'description' => 'Location adjacent to a field definition.', + ], + 'ARGUMENT_DEFINITION' => [ + 'value' => DirectiveLocation::ARGUMENT_DEFINITION, + 'description' => 'Location adjacent to an argument definition.', + ], + 'INTERFACE' => [ + 'value' => DirectiveLocation::IFACE, + 'description' => 'Location adjacent to an interface definition.', + ], + 'UNION' => [ + 'value' => DirectiveLocation::UNION, + 'description' => 'Location adjacent to a union definition.', + ], + 'ENUM' => [ + 'value' => DirectiveLocation::ENUM, + 'description' => 'Location adjacent to an enum definition.', + ], + 'ENUM_VALUE' => [ + 'value' => DirectiveLocation::ENUM_VALUE, + 'description' => 'Location adjacent to an enum value definition.', + ], + 'INPUT_OBJECT' => [ + 'value' => DirectiveLocation::INPUT_OBJECT, + 'description' => 'Location adjacent to an input object type definition.', + ], + 'INPUT_FIELD_DEFINITION' => [ + 'value' => DirectiveLocation::INPUT_FIELD_DEFINITION, + 'description' => 'Location adjacent to an input object field definition.', + ], + + ], + ]); + } + + return self::$map['__DirectiveLocation']; + } + + public static function schemaMetaFieldDef() + { + if (! isset(self::$map[self::SCHEMA_FIELD_NAME])) { + self::$map[self::SCHEMA_FIELD_NAME] = FieldDefinition::create([ + 'name' => self::SCHEMA_FIELD_NAME, + 'type' => Type::nonNull(self::_schema()), + 'description' => 'Access the current type schema of this server.', + 'args' => [], + 'resolve' => static function ( + $source, + $args, + $context, + ResolveInfo $info + ) { + return $info->schema; + }, + ]); + } + + return self::$map[self::SCHEMA_FIELD_NAME]; + } + + public static function typeMetaFieldDef() + { + if (! isset(self::$map[self::TYPE_FIELD_NAME])) { + self::$map[self::TYPE_FIELD_NAME] = FieldDefinition::create([ + 'name' => self::TYPE_FIELD_NAME, + 'type' => self::_type(), + 'description' => 'Request the type information of a single type.', + 'args' => [ + ['name' => 'name', 'type' => Type::nonNull(Type::string())], + ], + 'resolve' => static function ($source, $args, $context, ResolveInfo $info) { + return $info->schema->getType($args['name']); + }, + ]); + } + + return self::$map[self::TYPE_FIELD_NAME]; + } + + public static function typeNameMetaFieldDef() + { + if (! isset(self::$map[self::TYPE_NAME_FIELD_NAME])) { + self::$map[self::TYPE_NAME_FIELD_NAME] = FieldDefinition::create([ + 'name' => self::TYPE_NAME_FIELD_NAME, + 'type' => Type::nonNull(Type::string()), + 'description' => 'The name of the current Object type at runtime.', + 'args' => [], + 'resolve' => static function ( + $source, + $args, + $context, + ResolveInfo $info + ) { + return $info->parentType->name; + }, + ]); + } + + return self::$map[self::TYPE_NAME_FIELD_NAME]; + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/Schema.php b/vendor/webonyx/graphql-php/src/Type/Schema.php new file mode 100644 index 0000000..7e480e8 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/Schema.php @@ -0,0 +1,525 @@ + $MyAppQueryRootType, + * 'mutation' => $MyAppMutationRootType, + * ]); + * + * Or using Schema Config instance: + * + * $config = GraphQL\Type\SchemaConfig::create() + * ->setQuery($MyAppQueryRootType) + * ->setMutation($MyAppMutationRootType); + * + * $schema = new GraphQL\Type\Schema($config); + */ +class Schema +{ + /** @var SchemaConfig */ + private $config; + + /** + * Contains currently resolved schema types + * + * @var Type[] + */ + private $resolvedTypes = []; + + /** @var Type[][]|null */ + private $possibleTypeMap; + + /** + * True when $resolvedTypes contain all possible schema types + * + * @var bool + */ + private $fullyLoaded = false; + + /** @var InvariantViolation[]|null */ + private $validationErrors; + + /** @var SchemaTypeExtensionNode[] */ + public $extensionASTNodes; + + /** + * @param mixed[]|SchemaConfig $config + * + * @api + */ + public function __construct($config) + { + if (is_array($config)) { + $config = SchemaConfig::create($config); + } + + // If this schema was built from a source known to be valid, then it may be + // marked with assumeValid to avoid an additional type system validation. + if ($config->getAssumeValid()) { + $this->validationErrors = []; + } else { + // Otherwise check for common mistakes during construction to produce + // clear and early error messages. + Utils::invariant( + $config instanceof SchemaConfig, + 'Schema constructor expects instance of GraphQL\Type\SchemaConfig or an array with keys: %s; but got: %s', + implode( + ', ', + [ + 'query', + 'mutation', + 'subscription', + 'types', + 'directives', + 'typeLoader', + ] + ), + Utils::getVariableType($config) + ); + Utils::invariant( + ! $config->types || is_array($config->types) || is_callable($config->types), + '"types" must be array or callable if provided but got: ' . Utils::getVariableType($config->types) + ); + Utils::invariant( + ! $config->directives || is_array($config->directives), + '"directives" must be Array if provided but got: ' . Utils::getVariableType($config->directives) + ); + } + + $this->config = $config; + $this->extensionASTNodes = $config->extensionASTNodes; + + if ($config->query) { + $this->resolvedTypes[$config->query->name] = $config->query; + } + if ($config->mutation) { + $this->resolvedTypes[$config->mutation->name] = $config->mutation; + } + if ($config->subscription) { + $this->resolvedTypes[$config->subscription->name] = $config->subscription; + } + if (is_array($this->config->types)) { + foreach ($this->resolveAdditionalTypes() as $type) { + if (isset($this->resolvedTypes[$type->name])) { + Utils::invariant( + $type === $this->resolvedTypes[$type->name], + sprintf( + 'Schema must contain unique named types but contains multiple types named "%s" (see http://webonyx.github.io/graphql-php/type-system/#type-registry).', + $type + ) + ); + } + $this->resolvedTypes[$type->name] = $type; + } + } + $this->resolvedTypes += Type::getStandardTypes() + Introspection::getTypes(); + + if ($this->config->typeLoader) { + return; + } + + // Perform full scan of the schema + $this->getTypeMap(); + } + + /** + * @return Generator + */ + private function resolveAdditionalTypes() + { + $types = $this->config->types ?: []; + + if (is_callable($types)) { + $types = $types(); + } + + if (! is_array($types) && ! $types instanceof Traversable) { + throw new InvariantViolation(sprintf( + 'Schema types callable must return array or instance of Traversable but got: %s', + Utils::getVariableType($types) + )); + } + + foreach ($types as $index => $type) { + if (! $type instanceof Type) { + throw new InvariantViolation(sprintf( + 'Each entry of schema types must be instance of GraphQL\Type\Definition\Type but entry at %s is %s', + $index, + Utils::printSafe($type) + )); + } + yield $type; + } + } + + /** + * Returns array of all types in this schema. Keys of this array represent type names, values are instances + * of corresponding type definitions + * + * This operation requires full schema scan. Do not use in production environment. + * + * @return Type[] + * + * @api + */ + public function getTypeMap() + { + if (! $this->fullyLoaded) { + $this->resolvedTypes = $this->collectAllTypes(); + $this->fullyLoaded = true; + } + + return $this->resolvedTypes; + } + + /** + * @return Type[] + */ + private function collectAllTypes() + { + $typeMap = []; + foreach ($this->resolvedTypes as $type) { + $typeMap = TypeInfo::extractTypes($type, $typeMap); + } + foreach ($this->getDirectives() as $directive) { + if (! ($directive instanceof Directive)) { + continue; + } + + $typeMap = TypeInfo::extractTypesFromDirectives($directive, $typeMap); + } + // When types are set as array they are resolved in constructor + if (is_callable($this->config->types)) { + foreach ($this->resolveAdditionalTypes() as $type) { + $typeMap = TypeInfo::extractTypes($type, $typeMap); + } + } + + return $typeMap; + } + + /** + * Returns a list of directives supported by this schema + * + * @return Directive[] + * + * @api + */ + public function getDirectives() + { + return $this->config->directives ?: GraphQL::getStandardDirectives(); + } + + /** + * Returns schema query type + * + * @return ObjectType + * + * @api + */ + public function getQueryType() + { + return $this->config->query; + } + + /** + * Returns schema mutation type + * + * @return ObjectType|null + * + * @api + */ + public function getMutationType() + { + return $this->config->mutation; + } + + /** + * Returns schema subscription + * + * @return ObjectType|null + * + * @api + */ + public function getSubscriptionType() + { + return $this->config->subscription; + } + + /** + * @return SchemaConfig + * + * @api + */ + public function getConfig() + { + return $this->config; + } + + /** + * Returns type by it's name + * + * @param string $name + * + * @return Type|null + * + * @api + */ + public function getType($name) + { + if (! isset($this->resolvedTypes[$name])) { + $type = $this->loadType($name); + if (! $type) { + return null; + } + $this->resolvedTypes[$name] = $type; + } + + return $this->resolvedTypes[$name]; + } + + /** + * @param string $name + * + * @return bool + */ + public function hasType($name) + { + return $this->getType($name) !== null; + } + + /** + * @param string $typeName + * + * @return Type + */ + private function loadType($typeName) + { + $typeLoader = $this->config->typeLoader; + + if (! $typeLoader) { + return $this->defaultTypeLoader($typeName); + } + + $type = $typeLoader($typeName); + + if (! $type instanceof Type) { + throw new InvariantViolation( + sprintf( + 'Type loader is expected to return valid type "%s", but it returned %s', + $typeName, + Utils::printSafe($type) + ) + ); + } + if ($type->name !== $typeName) { + throw new InvariantViolation( + sprintf('Type loader is expected to return type "%s", but it returned "%s"', $typeName, $type->name) + ); + } + + return $type; + } + + /** + * @param string $typeName + * + * @return Type + */ + private function defaultTypeLoader($typeName) + { + // Default type loader simply fallbacks to collecting all types + $typeMap = $this->getTypeMap(); + + return $typeMap[$typeName] ?? null; + } + + /** + * Returns all possible concrete types for given abstract type + * (implementations for interfaces and members of union type for unions) + * + * This operation requires full schema scan. Do not use in production environment. + * + * @return ObjectType[] + * + * @api + */ + public function getPossibleTypes(AbstractType $abstractType) + { + $possibleTypeMap = $this->getPossibleTypeMap(); + + return isset($possibleTypeMap[$abstractType->name]) ? array_values($possibleTypeMap[$abstractType->name]) : []; + } + + /** + * @return Type[][] + */ + private function getPossibleTypeMap() + { + if ($this->possibleTypeMap === null) { + $this->possibleTypeMap = []; + foreach ($this->getTypeMap() as $type) { + if ($type instanceof ObjectType) { + foreach ($type->getInterfaces() as $interface) { + if (! ($interface instanceof InterfaceType)) { + continue; + } + + $this->possibleTypeMap[$interface->name][$type->name] = $type; + } + } elseif ($type instanceof UnionType) { + foreach ($type->getTypes() as $innerType) { + $this->possibleTypeMap[$type->name][$innerType->name] = $innerType; + } + } + } + } + + return $this->possibleTypeMap; + } + + /** + * Returns true if object type is concrete type of given abstract type + * (implementation for interfaces and members of union type for unions) + * + * @return bool + * + * @api + */ + public function isPossibleType(AbstractType $abstractType, ObjectType $possibleType) + { + if ($abstractType instanceof InterfaceType) { + return $possibleType->implementsInterface($abstractType); + } + + /** @var UnionType $abstractType */ + return $abstractType->isPossibleType($possibleType); + } + + /** + * Returns instance of directive by name + * + * @param string $name + * + * @return Directive + * + * @api + */ + public function getDirective($name) + { + foreach ($this->getDirectives() as $directive) { + if ($directive->name === $name) { + return $directive; + } + } + + return null; + } + + /** + * @return SchemaDefinitionNode + */ + public function getAstNode() + { + return $this->config->getAstNode(); + } + + /** + * Validates schema. + * + * This operation requires full schema scan. Do not use in production environment. + * + * @throws InvariantViolation + * + * @api + */ + public function assertValid() + { + $errors = $this->validate(); + + if ($errors) { + throw new InvariantViolation(implode("\n\n", $this->validationErrors)); + } + + $internalTypes = Type::getStandardTypes() + Introspection::getTypes(); + foreach ($this->getTypeMap() as $name => $type) { + if (isset($internalTypes[$name])) { + continue; + } + + $type->assertValid(); + + // Make sure type loader returns the same instance as registered in other places of schema + if (! $this->config->typeLoader) { + continue; + } + + Utils::invariant( + $this->loadType($name) === $type, + sprintf( + 'Type loader returns different instance for %s than field/argument definitions. Make sure you always return the same instance for the same type name.', + $name + ) + ); + } + } + + /** + * Validates schema. + * + * This operation requires full schema scan. Do not use in production environment. + * + * @return InvariantViolation[]|Error[] + * + * @api + */ + public function validate() + { + // If this Schema has already been validated, return the previous results. + if ($this->validationErrors !== null) { + return $this->validationErrors; + } + // Validate the schema, producing a list of errors. + $context = new SchemaValidationContext($this); + $context->validateRootTypes(); + $context->validateDirectives(); + $context->validateTypes(); + + // Persist the results of validation before returning to ensure validation + // does not run multiple times for this schema. + $this->validationErrors = $context->getErrors(); + + return $this->validationErrors; + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/SchemaConfig.php b/vendor/webonyx/graphql-php/src/Type/SchemaConfig.php new file mode 100644 index 0000000..9f33626 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/SchemaConfig.php @@ -0,0 +1,312 @@ +setQuery($myQueryType) + * ->setTypeLoader($myTypeLoader); + * + * $schema = new Schema($config); + */ +class SchemaConfig +{ + /** @var ObjectType */ + public $query; + + /** @var ObjectType */ + public $mutation; + + /** @var ObjectType */ + public $subscription; + + /** @var Type[]|callable */ + public $types; + + /** @var Directive[] */ + public $directives; + + /** @var callable */ + public $typeLoader; + + /** @var SchemaDefinitionNode */ + public $astNode; + + /** @var bool */ + public $assumeValid; + + /** @var SchemaTypeExtensionNode[] */ + public $extensionASTNodes; + + /** + * Converts an array of options to instance of SchemaConfig + * (or just returns empty config when array is not passed). + * + * @param mixed[] $options + * + * @return SchemaConfig + * + * @api + */ + public static function create(array $options = []) + { + $config = new static(); + + if (! empty($options)) { + if (isset($options['query'])) { + $config->setQuery($options['query']); + } + + if (isset($options['mutation'])) { + $config->setMutation($options['mutation']); + } + + if (isset($options['subscription'])) { + $config->setSubscription($options['subscription']); + } + + if (isset($options['types'])) { + $config->setTypes($options['types']); + } + + if (isset($options['directives'])) { + $config->setDirectives($options['directives']); + } + + if (isset($options['typeLoader'])) { + Utils::invariant( + is_callable($options['typeLoader']), + 'Schema type loader must be callable if provided but got: %s', + Utils::printSafe($options['typeLoader']) + ); + $config->setTypeLoader($options['typeLoader']); + } + + if (isset($options['astNode'])) { + $config->setAstNode($options['astNode']); + } + + if (isset($options['assumeValid'])) { + $config->setAssumeValid((bool) $options['assumeValid']); + } + + if (isset($options['extensionASTNodes'])) { + $config->setExtensionASTNodes($options['extensionASTNodes']); + } + } + + return $config; + } + + /** + * @return SchemaDefinitionNode + */ + public function getAstNode() + { + return $this->astNode; + } + + /** + * @return SchemaConfig + */ + public function setAstNode(SchemaDefinitionNode $astNode) + { + $this->astNode = $astNode; + + return $this; + } + + /** + * @return ObjectType + * + * @api + */ + public function getQuery() + { + return $this->query; + } + + /** + * @param ObjectType $query + * + * @return SchemaConfig + * + * @api + */ + public function setQuery($query) + { + $this->query = $query; + + return $this; + } + + /** + * @return ObjectType + * + * @api + */ + public function getMutation() + { + return $this->mutation; + } + + /** + * @param ObjectType $mutation + * + * @return SchemaConfig + * + * @api + */ + public function setMutation($mutation) + { + $this->mutation = $mutation; + + return $this; + } + + /** + * @return ObjectType + * + * @api + */ + public function getSubscription() + { + return $this->subscription; + } + + /** + * @param ObjectType $subscription + * + * @return SchemaConfig + * + * @api + */ + public function setSubscription($subscription) + { + $this->subscription = $subscription; + + return $this; + } + + /** + * @return Type[] + * + * @api + */ + public function getTypes() + { + return $this->types ?: []; + } + + /** + * @param Type[]|callable $types + * + * @return SchemaConfig + * + * @api + */ + public function setTypes($types) + { + $this->types = $types; + + return $this; + } + + /** + * @return Directive[] + * + * @api + */ + public function getDirectives() + { + return $this->directives ?: []; + } + + /** + * @param Directive[] $directives + * + * @return SchemaConfig + * + * @api + */ + public function setDirectives(array $directives) + { + $this->directives = $directives; + + return $this; + } + + /** + * @return callable + * + * @api + */ + public function getTypeLoader() + { + return $this->typeLoader; + } + + /** + * @return SchemaConfig + * + * @api + */ + public function setTypeLoader(callable $typeLoader) + { + $this->typeLoader = $typeLoader; + + return $this; + } + + /** + * @return bool + */ + public function getAssumeValid() + { + return $this->assumeValid; + } + + /** + * @param bool $assumeValid + * + * @return SchemaConfig + */ + public function setAssumeValid($assumeValid) + { + $this->assumeValid = $assumeValid; + + return $this; + } + + /** + * @return SchemaTypeExtensionNode[] + */ + public function getExtensionASTNodes() + { + return $this->extensionASTNodes; + } + + /** + * @param SchemaTypeExtensionNode[] $extensionASTNodes + */ + public function setExtensionASTNodes(array $extensionASTNodes) + { + $this->extensionASTNodes = $extensionASTNodes; + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/SchemaValidationContext.php b/vendor/webonyx/graphql-php/src/Type/SchemaValidationContext.php new file mode 100644 index 0000000..63f54dd --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/SchemaValidationContext.php @@ -0,0 +1,857 @@ +schema = $schema; + } + + /** + * @return Error[] + */ + public function getErrors() + { + return $this->errors; + } + + public function validateRootTypes() + { + $queryType = $this->schema->getQueryType(); + if (! $queryType) { + $this->reportError( + 'Query root type must be provided.', + $this->schema->getAstNode() + ); + } elseif (! $queryType instanceof ObjectType) { + $this->reportError( + 'Query root type must be Object type, it cannot be ' . Utils::printSafe($queryType) . '.', + $this->getOperationTypeNode($queryType, 'query') + ); + } + + $mutationType = $this->schema->getMutationType(); + if ($mutationType && ! $mutationType instanceof ObjectType) { + $this->reportError( + 'Mutation root type must be Object type if provided, it cannot be ' . Utils::printSafe($mutationType) . '.', + $this->getOperationTypeNode($mutationType, 'mutation') + ); + } + + $subscriptionType = $this->schema->getSubscriptionType(); + if (! $subscriptionType || $subscriptionType instanceof ObjectType) { + return; + } + + $this->reportError( + 'Subscription root type must be Object type if provided, it cannot be ' . Utils::printSafe($subscriptionType) . '.', + $this->getOperationTypeNode($subscriptionType, 'subscription') + ); + } + + /** + * @param string $message + * @param Node[]|Node|TypeNode|TypeDefinitionNode|null $nodes + */ + private function reportError($message, $nodes = null) + { + $nodes = array_filter($nodes && is_array($nodes) ? $nodes : [$nodes]); + $this->addError(new Error($message, $nodes)); + } + + /** + * @param Error $error + */ + private function addError($error) + { + $this->errors[] = $error; + } + + /** + * @param Type $type + * @param string $operation + * + * @return TypeNode|TypeDefinitionNode + */ + private function getOperationTypeNode($type, $operation) + { + $astNode = $this->schema->getAstNode(); + + $operationTypeNode = null; + if ($astNode instanceof SchemaDefinitionNode) { + $operationTypeNode = null; + + foreach ($astNode->operationTypes as $operationType) { + if ($operationType->operation === $operation) { + $operationTypeNode = $operationType; + break; + } + } + } + + return $operationTypeNode ? $operationTypeNode->type : ($type ? $type->astNode : null); + } + + public function validateDirectives() + { + $directives = $this->schema->getDirectives(); + foreach ($directives as $directive) { + // Ensure all directives are in fact GraphQL directives. + if (! $directive instanceof Directive) { + $this->reportError( + 'Expected directive but got: ' . Utils::printSafe($directive) . '.', + is_object($directive) ? $directive->astNode : null + ); + continue; + } + + // Ensure they are named correctly. + $this->validateName($directive); + + // TODO: Ensure proper locations. + + $argNames = []; + foreach ($directive->args as $arg) { + $argName = $arg->name; + + // Ensure they are named correctly. + $this->validateName($directive); + + if (isset($argNames[$argName])) { + $this->reportError( + sprintf('Argument @%s(%s:) can only be defined once.', $directive->name, $argName), + $this->getAllDirectiveArgNodes($directive, $argName) + ); + continue; + } + + $argNames[$argName] = true; + + // Ensure the type is an input type. + if (Type::isInputType($arg->getType())) { + continue; + } + + $this->reportError( + sprintf( + 'The type of @%s(%s:) must be Input Type but got: %s.', + $directive->name, + $argName, + Utils::printSafe($arg->getType()) + ), + $this->getDirectiveArgTypeNode($directive, $argName) + ); + } + } + } + + /** + * @param Type|Directive|FieldDefinition|EnumValueDefinition|InputObjectField $node + */ + private function validateName($node) + { + // Ensure names are valid, however introspection types opt out. + $error = Utils::isValidNameError($node->name, $node->astNode); + if (! $error || Introspection::isIntrospectionType($node)) { + return; + } + + $this->addError($error); + } + + /** + * @param string $argName + * + * @return InputValueDefinitionNode[] + */ + private function getAllDirectiveArgNodes(Directive $directive, $argName) + { + $argNodes = []; + $directiveNode = $directive->astNode; + if ($directiveNode && $directiveNode->arguments) { + foreach ($directiveNode->arguments as $node) { + if ($node->name->value !== $argName) { + continue; + } + + $argNodes[] = $node; + } + } + + return $argNodes; + } + + /** + * @param string $argName + * + * @return TypeNode|null + */ + private function getDirectiveArgTypeNode(Directive $directive, $argName) + { + $argNode = $this->getAllDirectiveArgNodes($directive, $argName)[0]; + + return $argNode ? $argNode->type : null; + } + + public function validateTypes() + { + $typeMap = $this->schema->getTypeMap(); + foreach ($typeMap as $typeName => $type) { + // Ensure all provided types are in fact GraphQL type. + if (! $type instanceof NamedType) { + $this->reportError( + 'Expected GraphQL named type but got: ' . Utils::printSafe($type) . '.', + is_object($type) ? $type->astNode : null + ); + continue; + } + + $this->validateName($type); + + if ($type instanceof ObjectType) { + // Ensure fields are valid + $this->validateFields($type); + + // Ensure objects implement the interfaces they claim to. + $this->validateObjectInterfaces($type); + } elseif ($type instanceof InterfaceType) { + // Ensure fields are valid. + $this->validateFields($type); + + // Ensure Interfaces include at least 1 Object type. + $this->validateInterfaces($type); + } elseif ($type instanceof UnionType) { + // Ensure Unions include valid member types. + $this->validateUnionMembers($type); + } elseif ($type instanceof EnumType) { + // Ensure Enums have valid values. + $this->validateEnumValues($type); + } elseif ($type instanceof InputObjectType) { + // Ensure Input Object fields are valid. + $this->validateInputFields($type); + } + } + } + + /** + * @param ObjectType|InterfaceType $type + */ + private function validateFields($type) + { + $fieldMap = $type->getFields(); + + // Objects and Interfaces both must define one or more fields. + if (! $fieldMap) { + $this->reportError( + sprintf('Type %s must define one or more fields.', $type->name), + $this->getAllObjectOrInterfaceNodes($type) + ); + } + + foreach ($fieldMap as $fieldName => $field) { + // Ensure they are named correctly. + $this->validateName($field); + + // Ensure they were defined at most once. + $fieldNodes = $this->getAllFieldNodes($type, $fieldName); + if ($fieldNodes && count($fieldNodes) > 1) { + $this->reportError( + sprintf('Field %s.%s can only be defined once.', $type->name, $fieldName), + $fieldNodes + ); + continue; + } + + // Ensure the type is an output type + if (! Type::isOutputType($field->getType())) { + $this->reportError( + sprintf( + 'The type of %s.%s must be Output Type but got: %s.', + $type->name, + $fieldName, + Utils::printSafe($field->getType()) + ), + $this->getFieldTypeNode($type, $fieldName) + ); + } + + // Ensure the arguments are valid + $argNames = []; + foreach ($field->args as $arg) { + $argName = $arg->name; + + // Ensure they are named correctly. + $this->validateName($arg); + + if (isset($argNames[$argName])) { + $this->reportError( + sprintf( + 'Field argument %s.%s(%s:) can only be defined once.', + $type->name, + $fieldName, + $argName + ), + $this->getAllFieldArgNodes($type, $fieldName, $argName) + ); + } + $argNames[$argName] = true; + + // Ensure the type is an input type + if (Type::isInputType($arg->getType())) { + continue; + } + + $this->reportError( + sprintf( + 'The type of %s.%s(%s:) must be Input Type but got: %s.', + $type->name, + $fieldName, + $argName, + Utils::printSafe($arg->getType()) + ), + $this->getFieldArgTypeNode($type, $fieldName, $argName) + ); + } + } + } + + /** + * @param ObjectType|InterfaceType $type + * + * @return ObjectTypeDefinitionNode[]|ObjectTypeExtensionNode[]|InterfaceTypeDefinitionNode[]|InterfaceTypeExtensionNode[] + */ + private function getAllObjectOrInterfaceNodes($type) + { + return $type->astNode + ? ($type->extensionASTNodes + ? array_merge([$type->astNode], $type->extensionASTNodes) + : [$type->astNode]) + : ($type->extensionASTNodes ?: []); + } + + /** + * @param ObjectType|InterfaceType $type + * @param string $fieldName + * + * @return FieldDefinitionNode[] + */ + private function getAllFieldNodes($type, $fieldName) + { + $fieldNodes = []; + $astNodes = $this->getAllObjectOrInterfaceNodes($type); + foreach ($astNodes as $astNode) { + if (! $astNode || ! $astNode->fields) { + continue; + } + + foreach ($astNode->fields as $node) { + if ($node->name->value !== $fieldName) { + continue; + } + + $fieldNodes[] = $node; + } + } + + return $fieldNodes; + } + + /** + * @param ObjectType|InterfaceType $type + * @param string $fieldName + * + * @return TypeNode|null + */ + private function getFieldTypeNode($type, $fieldName) + { + $fieldNode = $this->getFieldNode($type, $fieldName); + + return $fieldNode ? $fieldNode->type : null; + } + + /** + * @param ObjectType|InterfaceType $type + * @param string $fieldName + * + * @return FieldDefinitionNode|null + */ + private function getFieldNode($type, $fieldName) + { + $nodes = $this->getAllFieldNodes($type, $fieldName); + + return $nodes[0] ?? null; + } + + /** + * @param ObjectType|InterfaceType $type + * @param string $fieldName + * @param string $argName + * + * @return InputValueDefinitionNode[] + */ + private function getAllFieldArgNodes($type, $fieldName, $argName) + { + $argNodes = []; + $fieldNode = $this->getFieldNode($type, $fieldName); + if ($fieldNode && $fieldNode->arguments) { + foreach ($fieldNode->arguments as $node) { + if ($node->name->value !== $argName) { + continue; + } + + $argNodes[] = $node; + } + } + + return $argNodes; + } + + /** + * @param ObjectType|InterfaceType $type + * @param string $fieldName + * @param string $argName + * + * @return TypeNode|null + */ + private function getFieldArgTypeNode($type, $fieldName, $argName) + { + $fieldArgNode = $this->getFieldArgNode($type, $fieldName, $argName); + + return $fieldArgNode ? $fieldArgNode->type : null; + } + + /** + * @param ObjectType|InterfaceType $type + * @param string $fieldName + * @param string $argName + * + * @return InputValueDefinitionNode|null + */ + private function getFieldArgNode($type, $fieldName, $argName) + { + $nodes = $this->getAllFieldArgNodes($type, $fieldName, $argName); + + return $nodes[0] ?? null; + } + + private function validateObjectInterfaces(ObjectType $object) + { + $implementedTypeNames = []; + foreach ($object->getInterfaces() as $iface) { + if (! $iface instanceof InterfaceType) { + $this->reportError( + sprintf( + 'Type %s must only implement Interface types, it cannot implement %s.', + $object->name, + Utils::printSafe($iface) + ), + $this->getImplementsInterfaceNode($object, $iface) + ); + continue; + } + if (isset($implementedTypeNames[$iface->name])) { + $this->reportError( + sprintf('Type %s can only implement %s once.', $object->name, $iface->name), + $this->getAllImplementsInterfaceNodes($object, $iface) + ); + continue; + } + $implementedTypeNames[$iface->name] = true; + $this->validateObjectImplementsInterface($object, $iface); + } + } + + private function validateInterfaces(InterfaceType $iface) + { + $possibleTypes = $this->schema->getPossibleTypes($iface); + + if (count($possibleTypes) !== 0) { + return; + } + + $this->reportError( + sprintf( + 'Interface %s must be implemented by at least one Object type.', + $iface->name + ), + $iface->astNode + ); + } + + /** + * @param InterfaceType $iface + * + * @return NamedTypeNode|null + */ + private function getImplementsInterfaceNode(ObjectType $type, $iface) + { + $nodes = $this->getAllImplementsInterfaceNodes($type, $iface); + + return $nodes[0] ?? null; + } + + /** + * @param InterfaceType $iface + * + * @return NamedTypeNode[] + */ + private function getAllImplementsInterfaceNodes(ObjectType $type, $iface) + { + $implementsNodes = []; + $astNodes = $this->getAllObjectOrInterfaceNodes($type); + + foreach ($astNodes as $astNode) { + if (! $astNode || ! $astNode->interfaces) { + continue; + } + + foreach ($astNode->interfaces as $node) { + if ($node->name->value !== $iface->name) { + continue; + } + + $implementsNodes[] = $node; + } + } + + return $implementsNodes; + } + + /** + * @param InterfaceType $iface + */ + private function validateObjectImplementsInterface(ObjectType $object, $iface) + { + $objectFieldMap = $object->getFields(); + $ifaceFieldMap = $iface->getFields(); + + // Assert each interface field is implemented. + foreach ($ifaceFieldMap as $fieldName => $ifaceField) { + $objectField = array_key_exists($fieldName, $objectFieldMap) + ? $objectFieldMap[$fieldName] + : null; + + // Assert interface field exists on object. + if (! $objectField) { + $this->reportError( + sprintf( + 'Interface field %s.%s expected but %s does not provide it.', + $iface->name, + $fieldName, + $object->name + ), + [$this->getFieldNode($iface, $fieldName), $object->astNode] + ); + continue; + } + + // Assert interface field type is satisfied by object field type, by being + // a valid subtype. (covariant) + if (! TypeComparators::isTypeSubTypeOf( + $this->schema, + $objectField->getType(), + $ifaceField->getType() + ) + ) { + $this->reportError( + sprintf( + 'Interface field %s.%s expects type %s but %s.%s is type %s.', + $iface->name, + $fieldName, + $ifaceField->getType(), + $object->name, + $fieldName, + Utils::printSafe($objectField->getType()) + ), + [ + $this->getFieldTypeNode($iface, $fieldName), + $this->getFieldTypeNode($object, $fieldName), + ] + ); + } + + // Assert each interface field arg is implemented. + foreach ($ifaceField->args as $ifaceArg) { + $argName = $ifaceArg->name; + $objectArg = null; + + foreach ($objectField->args as $arg) { + if ($arg->name === $argName) { + $objectArg = $arg; + break; + } + } + + // Assert interface field arg exists on object field. + if (! $objectArg) { + $this->reportError( + sprintf( + 'Interface field argument %s.%s(%s:) expected but %s.%s does not provide it.', + $iface->name, + $fieldName, + $argName, + $object->name, + $fieldName + ), + [ + $this->getFieldArgNode($iface, $fieldName, $argName), + $this->getFieldNode($object, $fieldName), + ] + ); + continue; + } + + // Assert interface field arg type matches object field arg type. + // (invariant) + // TODO: change to contravariant? + if (! TypeComparators::isEqualType($ifaceArg->getType(), $objectArg->getType())) { + $this->reportError( + sprintf( + 'Interface field argument %s.%s(%s:) expects type %s but %s.%s(%s:) is type %s.', + $iface->name, + $fieldName, + $argName, + Utils::printSafe($ifaceArg->getType()), + $object->name, + $fieldName, + $argName, + Utils::printSafe($objectArg->getType()) + ), + [ + $this->getFieldArgTypeNode($iface, $fieldName, $argName), + $this->getFieldArgTypeNode($object, $fieldName, $argName), + ] + ); + } + // TODO: validate default values? + } + + // Assert additional arguments must not be required. + foreach ($objectField->args as $objectArg) { + $argName = $objectArg->name; + $ifaceArg = null; + + foreach ($ifaceField->args as $arg) { + if ($arg->name === $argName) { + $ifaceArg = $arg; + break; + } + } + + if ($ifaceArg || ! ($objectArg->getType() instanceof NonNull)) { + continue; + } + + $this->reportError( + sprintf( + 'Object field argument %s.%s(%s:) is of required type %s but is not also provided by the Interface field %s.%s.', + $object->name, + $fieldName, + $argName, + Utils::printSafe($objectArg->getType()), + $iface->name, + $fieldName + ), + [ + $this->getFieldArgTypeNode($object, $fieldName, $argName), + $this->getFieldNode($iface, $fieldName), + ] + ); + } + } + } + + private function validateUnionMembers(UnionType $union) + { + $memberTypes = $union->getTypes(); + + if (! $memberTypes) { + $this->reportError( + sprintf('Union type %s must define one or more member types.', $union->name), + $union->astNode + ); + } + + $includedTypeNames = []; + + foreach ($memberTypes as $memberType) { + if (isset($includedTypeNames[$memberType->name])) { + $this->reportError( + sprintf('Union type %s can only include type %s once.', $union->name, $memberType->name), + $this->getUnionMemberTypeNodes($union, $memberType->name) + ); + continue; + } + $includedTypeNames[$memberType->name] = true; + if ($memberType instanceof ObjectType) { + continue; + } + + $this->reportError( + sprintf( + 'Union type %s can only include Object types, it cannot include %s.', + $union->name, + Utils::printSafe($memberType) + ), + $this->getUnionMemberTypeNodes($union, Utils::printSafe($memberType)) + ); + } + } + + /** + * @param string $typeName + * + * @return NamedTypeNode[] + */ + private function getUnionMemberTypeNodes(UnionType $union, $typeName) + { + if ($union->astNode && $union->astNode->types) { + return array_filter( + $union->astNode->types, + static function (NamedTypeNode $value) use ($typeName) { + return $value->name->value === $typeName; + } + ); + } + + return $union->astNode ? + $union->astNode->types : null; + } + + private function validateEnumValues(EnumType $enumType) + { + $enumValues = $enumType->getValues(); + + if (! $enumValues) { + $this->reportError( + sprintf('Enum type %s must define one or more values.', $enumType->name), + $enumType->astNode + ); + } + + foreach ($enumValues as $enumValue) { + $valueName = $enumValue->name; + + // Ensure no duplicates + $allNodes = $this->getEnumValueNodes($enumType, $valueName); + if ($allNodes && count($allNodes) > 1) { + $this->reportError( + sprintf('Enum type %s can include value %s only once.', $enumType->name, $valueName), + $allNodes + ); + } + + // Ensure valid name. + $this->validateName($enumValue); + if ($valueName !== 'true' && $valueName !== 'false' && $valueName !== 'null') { + continue; + } + + $this->reportError( + sprintf('Enum type %s cannot include value: %s.', $enumType->name, $valueName), + $enumValue->astNode + ); + } + } + + /** + * @param string $valueName + * + * @return EnumValueDefinitionNode[] + */ + private function getEnumValueNodes(EnumType $enum, $valueName) + { + if ($enum->astNode && $enum->astNode->values) { + return array_filter( + iterator_to_array($enum->astNode->values), + static function (EnumValueDefinitionNode $value) use ($valueName) { + return $value->name->value === $valueName; + } + ); + } + + return $enum->astNode ? + $enum->astNode->values : null; + } + + private function validateInputFields(InputObjectType $inputObj) + { + $fieldMap = $inputObj->getFields(); + + if (! $fieldMap) { + $this->reportError( + sprintf('Input Object type %s must define one or more fields.', $inputObj->name), + $inputObj->astNode + ); + } + + // Ensure the arguments are valid + foreach ($fieldMap as $fieldName => $field) { + // Ensure they are named correctly. + $this->validateName($field); + + // TODO: Ensure they are unique per field. + + // Ensure the type is an input type + if (Type::isInputType($field->getType())) { + continue; + } + + $this->reportError( + sprintf( + 'The type of %s.%s must be Input Type but got: %s.', + $inputObj->name, + $fieldName, + Utils::printSafe($field->getType()) + ), + $field->astNode ? $field->astNode->type : null + ); + } + } +} diff --git a/vendor/webonyx/graphql-php/src/Type/TypeKind.php b/vendor/webonyx/graphql-php/src/Type/TypeKind.php new file mode 100644 index 0000000..7cd38ff --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Type/TypeKind.php @@ -0,0 +1,17 @@ + 'ListValue', + * 'values' => [ + * ['kind' => 'StringValue', 'value' => 'my str'], + * ['kind' => 'StringValue', 'value' => 'my other str'] + * ], + * 'loc' => ['start' => 21, 'end' => 25] + * ]); + * ``` + * + * Will produce instance of `ListValueNode` where `values` prop is a lazily-evaluated `NodeList` + * returning instances of `StringValueNode` on access. + * + * This is a reverse operation for AST::toArray($node) + * + * @param mixed[] $node + * + * @api + */ + public static function fromArray(array $node) : Node + { + if (! isset($node['kind']) || ! isset(NodeKind::$classMap[$node['kind']])) { + throw new InvariantViolation('Unexpected node structure: ' . Utils::printSafeJson($node)); + } + + $kind = $node['kind'] ?? null; + $class = NodeKind::$classMap[$kind]; + $instance = new $class([]); + + if (isset($node['loc'], $node['loc']['start'], $node['loc']['end'])) { + $instance->loc = Location::create($node['loc']['start'], $node['loc']['end']); + } + + foreach ($node as $key => $value) { + if ($key === 'loc' || $key === 'kind') { + continue; + } + if (is_array($value)) { + if (isset($value[0]) || empty($value)) { + $value = new NodeList($value); + } else { + $value = self::fromArray($value); + } + } + $instance->{$key} = $value; + } + + return $instance; + } + + /** + * Convert AST node to serializable array + * + * @return mixed[] + * + * @api + */ + public static function toArray(Node $node) + { + return $node->toArray(true); + } + + /** + * Produces a GraphQL Value AST given a PHP value. + * + * Optionally, a GraphQL type may be provided, which will be used to + * disambiguate between value primitives. + * + * | PHP Value | GraphQL Value | + * | ------------- | -------------------- | + * | Object | Input Object | + * | Assoc Array | Input Object | + * | Array | List | + * | Boolean | Boolean | + * | String | String / Enum Value | + * | Int | Int | + * | Float | Int / Float | + * | Mixed | Enum Value | + * | null | NullValue | + * + * @param Type|mixed|null $value + * + * @return ObjectValueNode|ListValueNode|BooleanValueNode|IntValueNode|FloatValueNode|EnumValueNode|StringValueNode|NullValueNode + * + * @api + */ + public static function astFromValue($value, InputType $type) + { + if ($type instanceof NonNull) { + $astValue = self::astFromValue($value, $type->getWrappedType()); + if ($astValue instanceof NullValueNode) { + return null; + } + + return $astValue; + } + + if ($value === null) { + return new NullValueNode([]); + } + + // Convert PHP array to GraphQL list. If the GraphQLType is a list, but + // the value is not an array, convert the value using the list's item type. + if ($type instanceof ListOfType) { + $itemType = $type->getWrappedType(); + if (is_array($value) || ($value instanceof Traversable)) { + $valuesNodes = []; + foreach ($value as $item) { + $itemNode = self::astFromValue($item, $itemType); + if (! $itemNode) { + continue; + } + + $valuesNodes[] = $itemNode; + } + + return new ListValueNode(['values' => $valuesNodes]); + } + + return self::astFromValue($value, $itemType); + } + + // Populate the fields of the input object by creating ASTs from each value + // in the PHP object according to the fields in the input type. + if ($type instanceof InputObjectType) { + $isArray = is_array($value); + $isArrayLike = $isArray || $value instanceof ArrayAccess; + if ($value === null || (! $isArrayLike && ! is_object($value))) { + return null; + } + $fields = $type->getFields(); + $fieldNodes = []; + foreach ($fields as $fieldName => $field) { + if ($isArrayLike) { + $fieldValue = $value[$fieldName] ?? null; + } else { + $fieldValue = $value->{$fieldName} ?? null; + } + + // Have to check additionally if key exists, since we differentiate between + // "no key" and "value is null": + if ($fieldValue !== null) { + $fieldExists = true; + } elseif ($isArray) { + $fieldExists = array_key_exists($fieldName, $value); + } elseif ($isArrayLike) { + /** @var ArrayAccess $value */ + $fieldExists = $value->offsetExists($fieldName); + } else { + $fieldExists = property_exists($value, $fieldName); + } + + if (! $fieldExists) { + continue; + } + + $fieldNode = self::astFromValue($fieldValue, $field->getType()); + + if (! $fieldNode) { + continue; + } + + $fieldNodes[] = new ObjectFieldNode([ + 'name' => new NameNode(['value' => $fieldName]), + 'value' => $fieldNode, + ]); + } + + return new ObjectValueNode(['fields' => $fieldNodes]); + } + + if ($type instanceof ScalarType || $type instanceof EnumType) { + // Since value is an internally represented value, it must be serialized + // to an externally represented value before converting into an AST. + try { + $serialized = $type->serialize($value); + } catch (Exception $error) { + if ($error instanceof Error && $type instanceof EnumType) { + return null; + } + throw $error; + } catch (Throwable $error) { + if ($error instanceof Error && $type instanceof EnumType) { + return null; + } + throw $error; + } + + // Others serialize based on their corresponding PHP scalar types. + if (is_bool($serialized)) { + return new BooleanValueNode(['value' => $serialized]); + } + if (is_int($serialized)) { + return new IntValueNode(['value' => $serialized]); + } + if (is_float($serialized)) { + // int cast with == used for performance reasons + // phpcs:ignore + if ((int) $serialized == $serialized) { + return new IntValueNode(['value' => $serialized]); + } + + return new FloatValueNode(['value' => $serialized]); + } + if (is_string($serialized)) { + // Enum types use Enum literals. + if ($type instanceof EnumType) { + return new EnumValueNode(['value' => $serialized]); + } + + // ID types can use Int literals. + $asInt = (int) $serialized; + if ($type instanceof IDType && (string) $asInt === $serialized) { + return new IntValueNode(['value' => $serialized]); + } + + // Use json_encode, which uses the same string encoding as GraphQL, + // then remove the quotes. + return new StringValueNode(['value' => $serialized]); + } + + throw new InvariantViolation('Cannot convert value to AST: ' . Utils::printSafe($serialized)); + } + + throw new Error('Unknown type: ' . Utils::printSafe($type) . '.'); + } + + /** + * Produces a PHP value given a GraphQL Value AST. + * + * A GraphQL type must be provided, which will be used to interpret different + * GraphQL Value literals. + * + * Returns `null` when the value could not be validly coerced according to + * the provided type. + * + * | GraphQL Value | PHP Value | + * | -------------------- | ------------- | + * | Input Object | Assoc Array | + * | List | Array | + * | Boolean | Boolean | + * | String | String | + * | Int / Float | Int / Float | + * | Enum Value | Mixed | + * | Null Value | null | + * + * @param ValueNode|null $valueNode + * @param mixed[]|null $variables + * + * @return mixed[]|stdClass|null + * + * @throws Exception + * + * @api + */ + public static function valueFromAST($valueNode, InputType $type, ?array $variables = null) + { + $undefined = Utils::undefined(); + + if ($valueNode === null) { + // When there is no AST, then there is also no value. + // Importantly, this is different from returning the GraphQL null value. + return $undefined; + } + + if ($type instanceof NonNull) { + if ($valueNode instanceof NullValueNode) { + // Invalid: intentionally return no value. + return $undefined; + } + + return self::valueFromAST($valueNode, $type->getWrappedType(), $variables); + } + + if ($valueNode instanceof NullValueNode) { + // This is explicitly returning the value null. + return null; + } + + if ($valueNode instanceof VariableNode) { + $variableName = $valueNode->name->value; + + if (! $variables || ! array_key_exists($variableName, $variables)) { + // No valid return value. + return $undefined; + } + + // Note: we're not doing any checking that this variable is correct. We're + // assuming that this query has been validated and the variable usage here + // is of the correct type. + return $variables[$variableName]; + } + + if ($type instanceof ListOfType) { + $itemType = $type->getWrappedType(); + + if ($valueNode instanceof ListValueNode) { + $coercedValues = []; + $itemNodes = $valueNode->values; + foreach ($itemNodes as $itemNode) { + if (self::isMissingVariable($itemNode, $variables)) { + // If an array contains a missing variable, it is either coerced to + // null or if the item type is non-null, it considered invalid. + if ($itemType instanceof NonNull) { + // Invalid: intentionally return no value. + return $undefined; + } + $coercedValues[] = null; + } else { + $itemValue = self::valueFromAST($itemNode, $itemType, $variables); + if ($undefined === $itemValue) { + // Invalid: intentionally return no value. + return $undefined; + } + $coercedValues[] = $itemValue; + } + } + + return $coercedValues; + } + $coercedValue = self::valueFromAST($valueNode, $itemType, $variables); + if ($undefined === $coercedValue) { + // Invalid: intentionally return no value. + return $undefined; + } + + return [$coercedValue]; + } + + if ($type instanceof InputObjectType) { + if (! $valueNode instanceof ObjectValueNode) { + // Invalid: intentionally return no value. + return $undefined; + } + + $coercedObj = []; + $fields = $type->getFields(); + $fieldNodes = Utils::keyMap( + $valueNode->fields, + static function ($field) { + return $field->name->value; + } + ); + foreach ($fields as $field) { + /** @var ValueNode $fieldNode */ + $fieldName = $field->name; + $fieldNode = $fieldNodes[$fieldName] ?? null; + + if ($fieldNode === null || self::isMissingVariable($fieldNode->value, $variables)) { + if ($field->defaultValueExists()) { + $coercedObj[$fieldName] = $field->defaultValue; + } elseif ($field->getType() instanceof NonNull) { + // Invalid: intentionally return no value. + return $undefined; + } + continue; + } + + $fieldValue = self::valueFromAST( + $fieldNode !== null ? $fieldNode->value : null, + $field->getType(), + $variables + ); + + if ($undefined === $fieldValue) { + // Invalid: intentionally return no value. + return $undefined; + } + $coercedObj[$fieldName] = $fieldValue; + } + + return $coercedObj; + } + + if ($type instanceof EnumType) { + if (! $valueNode instanceof EnumValueNode) { + return $undefined; + } + $enumValue = $type->getValue($valueNode->value); + if (! $enumValue) { + return $undefined; + } + + return $enumValue->value; + } + + if ($type instanceof ScalarType) { + // Scalars fulfill parsing a literal value via parseLiteral(). + // Invalid values represent a failure to parse correctly, in which case + // no value is returned. + try { + return $type->parseLiteral($valueNode, $variables); + } catch (Exception $error) { + return $undefined; + } catch (Throwable $error) { + return $undefined; + } + } + + throw new Error('Unknown type: ' . Utils::printSafe($type) . '.'); + } + + /** + * Returns true if the provided valueNode is a variable which is not defined + * in the set of variables. + * + * @param ValueNode $valueNode + * @param mixed[] $variables + * + * @return bool + */ + private static function isMissingVariable($valueNode, $variables) + { + return $valueNode instanceof VariableNode && + (count($variables) === 0 || ! array_key_exists($valueNode->name->value, $variables)); + } + + /** + * Produces a PHP value given a GraphQL Value AST. + * + * Unlike `valueFromAST()`, no type is provided. The resulting PHP value + * will reflect the provided GraphQL value AST. + * + * | GraphQL Value | PHP Value | + * | -------------------- | ------------- | + * | Input Object | Assoc Array | + * | List | Array | + * | Boolean | Boolean | + * | String | String | + * | Int / Float | Int / Float | + * | Enum | Mixed | + * | Null | null | + * + * @param Node $valueNode + * @param mixed[]|null $variables + * + * @return mixed + * + * @throws Exception + * + * @api + */ + public static function valueFromASTUntyped($valueNode, ?array $variables = null) + { + switch (true) { + case $valueNode instanceof NullValueNode: + return null; + case $valueNode instanceof IntValueNode: + return intval($valueNode->value, 10); + case $valueNode instanceof FloatValueNode: + return floatval($valueNode->value); + case $valueNode instanceof StringValueNode: + case $valueNode instanceof EnumValueNode: + case $valueNode instanceof BooleanValueNode: + return $valueNode->value; + case $valueNode instanceof ListValueNode: + return array_map( + static function ($node) use ($variables) { + return self::valueFromASTUntyped($node, $variables); + }, + iterator_to_array($valueNode->values) + ); + case $valueNode instanceof ObjectValueNode: + return array_combine( + array_map( + static function ($field) { + return $field->name->value; + }, + iterator_to_array($valueNode->fields) + ), + array_map( + static function ($field) use ($variables) { + return self::valueFromASTUntyped($field->value, $variables); + }, + iterator_to_array($valueNode->fields) + ) + ); + case $valueNode instanceof VariableNode: + $variableName = $valueNode->name->value; + + return $variables && isset($variables[$variableName]) + ? $variables[$variableName] + : null; + } + + throw new Error('Unexpected value kind: ' . $valueNode->kind . '.'); + } + + /** + * Returns type definition for given AST Type node + * + * @param NamedTypeNode|ListTypeNode|NonNullTypeNode $inputTypeNode + * + * @return Type|null + * + * @throws Exception + * + * @api + */ + public static function typeFromAST(Schema $schema, $inputTypeNode) + { + if ($inputTypeNode instanceof ListTypeNode) { + $innerType = self::typeFromAST($schema, $inputTypeNode->type); + + return $innerType ? new ListOfType($innerType) : null; + } + if ($inputTypeNode instanceof NonNullTypeNode) { + $innerType = self::typeFromAST($schema, $inputTypeNode->type); + + return $innerType ? new NonNull($innerType) : null; + } + if ($inputTypeNode instanceof NamedTypeNode) { + return $schema->getType($inputTypeNode->name->value); + } + + throw new Error('Unexpected type kind: ' . $inputTypeNode->kind . '.'); + } + + /** + * Returns operation type ("query", "mutation" or "subscription") given a document and operation name + * + * @param string $operationName + * + * @return bool + * + * @api + */ + public static function getOperation(DocumentNode $document, $operationName = null) + { + if ($document->definitions) { + foreach ($document->definitions as $def) { + if (! ($def instanceof OperationDefinitionNode)) { + continue; + } + + if (! $operationName || (isset($def->name->value) && $def->name->value === $operationName)) { + return $def->operation; + } + } + } + + return false; + } +} diff --git a/vendor/webonyx/graphql-php/src/Utils/ASTDefinitionBuilder.php b/vendor/webonyx/graphql-php/src/Utils/ASTDefinitionBuilder.php new file mode 100644 index 0000000..95f8d5a --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Utils/ASTDefinitionBuilder.php @@ -0,0 +1,530 @@ +typeDefinitionsMap = $typeDefinitionsMap; + $this->typeConfigDecorator = $typeConfigDecorator; + $this->options = $options; + $this->resolveType = $resolveType; + + $this->cache = Type::getAllBuiltInTypes(); + } + + public function buildDirective(DirectiveDefinitionNode $directiveNode) + { + return new Directive([ + 'name' => $directiveNode->name->value, + 'description' => $this->getDescription($directiveNode), + 'locations' => Utils::map( + $directiveNode->locations, + static function ($node) { + return $node->value; + } + ), + 'args' => $directiveNode->arguments ? FieldArgument::createMap($this->makeInputValues($directiveNode->arguments)) : null, + 'astNode' => $directiveNode, + ]); + } + + /** + * Given an ast node, returns its string description. + */ + private function getDescription($node) + { + if ($node->description) { + return $node->description->value; + } + if (isset($this->options['commentDescriptions'])) { + $rawValue = $this->getLeadingCommentBlock($node); + if ($rawValue !== null) { + return BlockString::value("\n" . $rawValue); + } + } + + return null; + } + + private function getLeadingCommentBlock($node) + { + $loc = $node->loc; + if (! $loc || ! $loc->startToken) { + return null; + } + $comments = []; + $token = $loc->startToken->prev; + while ($token && + $token->kind === Token::COMMENT && + $token->next && $token->prev && + $token->line + 1 === $token->next->line && + $token->line !== $token->prev->line + ) { + $value = $token->value; + $comments[] = $value; + $token = $token->prev; + } + + return implode("\n", array_reverse($comments)); + } + + private function makeInputValues($values) + { + return Utils::keyValMap( + $values, + static function ($value) { + return $value->name->value; + }, + function ($value) { + // Note: While this could make assertions to get the correctly typed + // value, that would throw immediately while type system validation + // with validateSchema() will produce more actionable results. + $type = $this->internalBuildWrappedType($value->type); + + $config = [ + 'name' => $value->name->value, + 'type' => $type, + 'description' => $this->getDescription($value), + 'astNode' => $value, + ]; + if (isset($value->defaultValue)) { + $config['defaultValue'] = AST::valueFromAST($value->defaultValue, $type); + } + + return $config; + } + ); + } + + /** + * @return Type|InputType + * + * @throws Error + */ + private function internalBuildWrappedType(TypeNode $typeNode) + { + $typeDef = $this->buildType($this->getNamedTypeNode($typeNode)); + + return $this->buildWrappedType($typeDef, $typeNode); + } + + /** + * @param string|NamedTypeNode $ref + * + * @return Type + * + * @throws Error + */ + public function buildType($ref) + { + if (is_string($ref)) { + return $this->internalBuildType($ref); + } + + return $this->internalBuildType($ref->name->value, $ref); + } + + /** + * @param string $typeName + * @param NamedTypeNode|null $typeNode + * + * @return Type + * + * @throws Error + */ + private function internalBuildType($typeName, $typeNode = null) + { + if (! isset($this->cache[$typeName])) { + if (isset($this->typeDefinitionsMap[$typeName])) { + $type = $this->makeSchemaDef($this->typeDefinitionsMap[$typeName]); + if ($this->typeConfigDecorator) { + $fn = $this->typeConfigDecorator; + try { + $config = $fn($type->config, $this->typeDefinitionsMap[$typeName], $this->typeDefinitionsMap); + } catch (Throwable $e) { + throw new Error( + sprintf('Type config decorator passed to %s threw an error ', static::class) . + sprintf('when building %s type: %s', $typeName, $e->getMessage()), + null, + null, + null, + null, + $e + ); + } + if (! is_array($config) || isset($config[0])) { + throw new Error( + sprintf( + 'Type config decorator passed to %s is expected to return an array, but got %s', + static::class, + Utils::getVariableType($config) + ) + ); + } + $type = $this->makeSchemaDefFromConfig($this->typeDefinitionsMap[$typeName], $config); + } + $this->cache[$typeName] = $type; + } else { + $fn = $this->resolveType; + $this->cache[$typeName] = $fn($typeName, $typeNode); + } + } + + return $this->cache[$typeName]; + } + + /** + * @param ObjectTypeDefinitionNode|InterfaceTypeDefinitionNode|EnumTypeDefinitionNode|ScalarTypeDefinitionNode|InputObjectTypeDefinitionNode|UnionTypeDefinitionNode $def + * + * @return CustomScalarType|EnumType|InputObjectType|InterfaceType|ObjectType|UnionType + * + * @throws Error + */ + private function makeSchemaDef($def) + { + if (! $def) { + throw new Error('def must be defined.'); + } + switch ($def->kind) { + case NodeKind::OBJECT_TYPE_DEFINITION: + return $this->makeTypeDef($def); + case NodeKind::INTERFACE_TYPE_DEFINITION: + return $this->makeInterfaceDef($def); + case NodeKind::ENUM_TYPE_DEFINITION: + return $this->makeEnumDef($def); + case NodeKind::UNION_TYPE_DEFINITION: + return $this->makeUnionDef($def); + case NodeKind::SCALAR_TYPE_DEFINITION: + return $this->makeScalarDef($def); + case NodeKind::INPUT_OBJECT_TYPE_DEFINITION: + return $this->makeInputObjectDef($def); + default: + throw new Error(sprintf('Type kind of %s not supported.', $def->kind)); + } + } + + private function makeTypeDef(ObjectTypeDefinitionNode $def) + { + $typeName = $def->name->value; + + return new ObjectType([ + 'name' => $typeName, + 'description' => $this->getDescription($def), + 'fields' => function () use ($def) { + return $this->makeFieldDefMap($def); + }, + 'interfaces' => function () use ($def) { + return $this->makeImplementedInterfaces($def); + }, + 'astNode' => $def, + ]); + } + + private function makeFieldDefMap($def) + { + return $def->fields + ? Utils::keyValMap( + $def->fields, + static function ($field) { + return $field->name->value; + }, + function ($field) { + return $this->buildField($field); + } + ) + : []; + } + + public function buildField(FieldDefinitionNode $field) + { + return [ + // Note: While this could make assertions to get the correctly typed + // value, that would throw immediately while type system validation + // with validateSchema() will produce more actionable results. + 'type' => $this->internalBuildWrappedType($field->type), + 'description' => $this->getDescription($field), + 'args' => $field->arguments ? $this->makeInputValues($field->arguments) : null, + 'deprecationReason' => $this->getDeprecationReason($field), + 'astNode' => $field, + ]; + } + + /** + * Given a collection of directives, returns the string value for the + * deprecation reason. + * + * @param EnumValueDefinitionNode | FieldDefinitionNode $node + * + * @return string + */ + private function getDeprecationReason($node) + { + $deprecated = Values::getDirectiveValues(Directive::deprecatedDirective(), $node); + + return $deprecated['reason'] ?? null; + } + + private function makeImplementedInterfaces(ObjectTypeDefinitionNode $def) + { + if ($def->interfaces) { + // Note: While this could make early assertions to get the correctly + // typed values, that would throw immediately while type system + // validation with validateSchema() will produce more actionable results. + return Utils::map( + $def->interfaces, + function ($iface) { + return $this->buildType($iface); + } + ); + } + + return null; + } + + private function makeInterfaceDef(InterfaceTypeDefinitionNode $def) + { + $typeName = $def->name->value; + + return new InterfaceType([ + 'name' => $typeName, + 'description' => $this->getDescription($def), + 'fields' => function () use ($def) { + return $this->makeFieldDefMap($def); + }, + 'astNode' => $def, + ]); + } + + private function makeEnumDef(EnumTypeDefinitionNode $def) + { + return new EnumType([ + 'name' => $def->name->value, + 'description' => $this->getDescription($def), + 'values' => $def->values + ? Utils::keyValMap( + $def->values, + static function ($enumValue) { + return $enumValue->name->value; + }, + function ($enumValue) { + return [ + 'description' => $this->getDescription($enumValue), + 'deprecationReason' => $this->getDeprecationReason($enumValue), + 'astNode' => $enumValue, + ]; + } + ) + : [], + 'astNode' => $def, + ]); + } + + private function makeUnionDef(UnionTypeDefinitionNode $def) + { + return new UnionType([ + 'name' => $def->name->value, + 'description' => $this->getDescription($def), + // Note: While this could make assertions to get the correctly typed + // values below, that would throw immediately while type system + // validation with validateSchema() will produce more actionable results. + 'types' => $def->types + ? Utils::map( + $def->types, + function ($typeNode) { + return $this->buildType($typeNode); + } + ) : + [], + 'astNode' => $def, + ]); + } + + private function makeScalarDef(ScalarTypeDefinitionNode $def) + { + return new CustomScalarType([ + 'name' => $def->name->value, + 'description' => $this->getDescription($def), + 'astNode' => $def, + 'serialize' => static function ($value) { + return $value; + }, + ]); + } + + private function makeInputObjectDef(InputObjectTypeDefinitionNode $def) + { + return new InputObjectType([ + 'name' => $def->name->value, + 'description' => $this->getDescription($def), + 'fields' => function () use ($def) { + return $def->fields + ? $this->makeInputValues($def->fields) + : []; + }, + 'astNode' => $def, + ]); + } + + /** + * @param ObjectTypeDefinitionNode|InterfaceTypeDefinitionNode|EnumTypeExtensionNode|ScalarTypeDefinitionNode|InputObjectTypeDefinitionNode $def + * @param mixed[] $config + * + * @return CustomScalarType|EnumType|InputObjectType|InterfaceType|ObjectType|UnionType + * + * @throws Error + */ + private function makeSchemaDefFromConfig($def, array $config) + { + if (! $def) { + throw new Error('def must be defined.'); + } + switch ($def->kind) { + case NodeKind::OBJECT_TYPE_DEFINITION: + return new ObjectType($config); + case NodeKind::INTERFACE_TYPE_DEFINITION: + return new InterfaceType($config); + case NodeKind::ENUM_TYPE_DEFINITION: + return new EnumType($config); + case NodeKind::UNION_TYPE_DEFINITION: + return new UnionType($config); + case NodeKind::SCALAR_TYPE_DEFINITION: + return new CustomScalarType($config); + case NodeKind::INPUT_OBJECT_TYPE_DEFINITION: + return new InputObjectType($config); + default: + throw new Error(sprintf('Type kind of %s not supported.', $def->kind)); + } + } + + /** + * @param TypeNode|ListTypeNode|NonNullTypeNode $typeNode + * + * @return TypeNode + */ + private function getNamedTypeNode(TypeNode $typeNode) + { + $namedType = $typeNode; + while ($namedType->kind === NodeKind::LIST_TYPE || $namedType->kind === NodeKind::NON_NULL_TYPE) { + $namedType = $namedType->type; + } + + return $namedType; + } + + /** + * @param TypeNode|ListTypeNode|NonNullTypeNode $inputTypeNode + * + * @return Type + */ + private function buildWrappedType(Type $innerType, TypeNode $inputTypeNode) + { + if ($inputTypeNode->kind === NodeKind::LIST_TYPE) { + return Type::listOf($this->buildWrappedType($innerType, $inputTypeNode->type)); + } + if ($inputTypeNode->kind === NodeKind::NON_NULL_TYPE) { + $wrappedType = $this->buildWrappedType($innerType, $inputTypeNode->type); + + return Type::nonNull(NonNull::assertNullableType($wrappedType)); + } + + return $innerType; + } + + /** + * @return mixed[] + */ + public function buildInputField(InputValueDefinitionNode $value) : array + { + $type = $this->internalBuildWrappedType($value->type); + + $config = [ + 'name' => $value->name->value, + 'type' => $type, + 'description' => $this->getDescription($value), + 'astNode' => $value, + ]; + + if ($value->defaultValue) { + $config['defaultValue'] = $value->defaultValue; + } + + return $config; + } + + /** + * @return mixed[] + */ + public function buildEnumValue(EnumValueDefinitionNode $value) : array + { + return [ + 'description' => $this->getDescription($value), + 'deprecationReason' => $this->getDeprecationReason($value), + 'astNode' => $value, + ]; + } +} diff --git a/vendor/webonyx/graphql-php/src/Utils/BlockString.php b/vendor/webonyx/graphql-php/src/Utils/BlockString.php new file mode 100644 index 0000000..a81760c --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Utils/BlockString.php @@ -0,0 +1,77 @@ += mb_strlen($line) || + ($commonIndent !== null && $indent >= $commonIndent) + ) { + continue; + } + + $commonIndent = $indent; + if ($commonIndent === 0) { + break; + } + } + + if ($commonIndent) { + for ($i = 1; $i < $linesLength; $i++) { + $line = $lines[$i]; + $lines[$i] = mb_substr($line, $commonIndent); + } + } + + // Remove leading and trailing blank lines. + while (count($lines) > 0 && trim($lines[0], " \t") === '') { + array_shift($lines); + } + while (count($lines) > 0 && trim($lines[count($lines) - 1], " \t") === '') { + array_pop($lines); + } + + // Return a string of the lines joined with U+000A. + return implode("\n", $lines); + } + + private static function leadingWhitespace($str) + { + $i = 0; + while ($i < mb_strlen($str) && ($str[$i] === ' ' || $str[$i] === '\t')) { + $i++; + } + + return $i; + } +} diff --git a/vendor/webonyx/graphql-php/src/Utils/BreakingChangesFinder.php b/vendor/webonyx/graphql-php/src/Utils/BreakingChangesFinder.php new file mode 100644 index 0000000..533abf6 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Utils/BreakingChangesFinder.php @@ -0,0 +1,923 @@ +getTypeMap(); + $newTypeMap = $newSchema->getTypeMap(); + + $breakingChanges = []; + foreach (array_keys($oldTypeMap) as $typeName) { + if (isset($newTypeMap[$typeName])) { + continue; + } + + $breakingChanges[] = [ + 'type' => self::BREAKING_CHANGE_TYPE_REMOVED, + 'description' => "${typeName} was removed.", + ]; + } + + return $breakingChanges; + } + + /** + * Given two schemas, returns an Array containing descriptions of any breaking + * changes in the newSchema related to changing the type of a type. + * + * @return string[][] + */ + public static function findTypesThatChangedKind( + Schema $schemaA, + Schema $schemaB + ) : iterable { + $schemaATypeMap = $schemaA->getTypeMap(); + $schemaBTypeMap = $schemaB->getTypeMap(); + + $breakingChanges = []; + foreach ($schemaATypeMap as $typeName => $schemaAType) { + if (! isset($schemaBTypeMap[$typeName])) { + continue; + } + $schemaBType = $schemaBTypeMap[$typeName]; + if ($schemaAType instanceof $schemaBType) { + continue; + } + + if ($schemaBType instanceof $schemaAType) { + continue; + } + + $schemaATypeKindName = self::typeKindName($schemaAType); + $schemaBTypeKindName = self::typeKindName($schemaBType); + $breakingChanges[] = [ + 'type' => self::BREAKING_CHANGE_TYPE_CHANGED_KIND, + 'description' => "${typeName} changed from ${schemaATypeKindName} to ${schemaBTypeKindName}.", + ]; + } + + return $breakingChanges; + } + + /** + * @return string + * + * @throws TypeError + */ + private static function typeKindName(Type $type) + { + if ($type instanceof ScalarType) { + return 'a Scalar type'; + } + + if ($type instanceof ObjectType) { + return 'an Object type'; + } + + if ($type instanceof InterfaceType) { + return 'an Interface type'; + } + + if ($type instanceof UnionType) { + return 'a Union type'; + } + + if ($type instanceof EnumType) { + return 'an Enum type'; + } + + if ($type instanceof InputObjectType) { + return 'an Input type'; + } + + throw new TypeError('unknown type ' . $type->name); + } + + /** + * @return string[][] + */ + public static function findFieldsThatChangedTypeOnObjectOrInterfaceTypes( + Schema $oldSchema, + Schema $newSchema + ) { + $oldTypeMap = $oldSchema->getTypeMap(); + $newTypeMap = $newSchema->getTypeMap(); + + $breakingChanges = []; + foreach ($oldTypeMap as $typeName => $oldType) { + $newType = $newTypeMap[$typeName] ?? null; + if (! ($oldType instanceof ObjectType || $oldType instanceof InterfaceType) || + ! ($newType instanceof ObjectType || $newType instanceof InterfaceType) || + ! ($newType instanceof $oldType) + ) { + continue; + } + + $oldTypeFieldsDef = $oldType->getFields(); + $newTypeFieldsDef = $newType->getFields(); + foreach ($oldTypeFieldsDef as $fieldName => $fieldDefinition) { + // Check if the field is missing on the type in the new schema. + if (! isset($newTypeFieldsDef[$fieldName])) { + $breakingChanges[] = [ + 'type' => self::BREAKING_CHANGE_FIELD_REMOVED, + 'description' => "${typeName}.${fieldName} was removed.", + ]; + } else { + $oldFieldType = $oldTypeFieldsDef[$fieldName]->getType(); + $newFieldType = $newTypeFieldsDef[$fieldName]->getType(); + $isSafe = self::isChangeSafeForObjectOrInterfaceField( + $oldFieldType, + $newFieldType + ); + if (! $isSafe) { + $oldFieldTypeString = $oldFieldType instanceof NamedType + ? $oldFieldType->name + : $oldFieldType; + $newFieldTypeString = $newFieldType instanceof NamedType + ? $newFieldType->name + : $newFieldType; + $breakingChanges[] = [ + 'type' => self::BREAKING_CHANGE_FIELD_CHANGED_KIND, + 'description' => "${typeName}.${fieldName} changed type from ${oldFieldTypeString} to ${newFieldTypeString}.", + ]; + } + } + } + } + + return $breakingChanges; + } + + /** + * @return bool + */ + private static function isChangeSafeForObjectOrInterfaceField( + Type $oldType, + Type $newType + ) { + if ($oldType instanceof NamedType) { + return // if they're both named types, see if their names are equivalent + ($newType instanceof NamedType && $oldType->name === $newType->name) || + // moving from nullable to non-null of the same underlying type is safe + ($newType instanceof NonNull && + self::isChangeSafeForObjectOrInterfaceField($oldType, $newType->getWrappedType()) + ); + } + + if ($oldType instanceof ListOfType) { + return // if they're both lists, make sure the underlying types are compatible + ($newType instanceof ListOfType && + self::isChangeSafeForObjectOrInterfaceField( + $oldType->getWrappedType(), + $newType->getWrappedType() + )) || + // moving from nullable to non-null of the same underlying type is safe + ($newType instanceof NonNull && + self::isChangeSafeForObjectOrInterfaceField($oldType, $newType->getWrappedType())); + } + + if ($oldType instanceof NonNull) { + // if they're both non-null, make sure the underlying types are compatible + return $newType instanceof NonNull && + self::isChangeSafeForObjectOrInterfaceField($oldType->getWrappedType(), $newType->getWrappedType()); + } + + return false; + } + + /** + * @return string[][] + */ + public static function findFieldsThatChangedTypeOnInputObjectTypes( + Schema $oldSchema, + Schema $newSchema + ) { + $oldTypeMap = $oldSchema->getTypeMap(); + $newTypeMap = $newSchema->getTypeMap(); + + $breakingChanges = []; + $dangerousChanges = []; + foreach ($oldTypeMap as $typeName => $oldType) { + $newType = $newTypeMap[$typeName] ?? null; + if (! ($oldType instanceof InputObjectType) || ! ($newType instanceof InputObjectType)) { + continue; + } + + $oldTypeFieldsDef = $oldType->getFields(); + $newTypeFieldsDef = $newType->getFields(); + foreach (array_keys($oldTypeFieldsDef) as $fieldName) { + if (! isset($newTypeFieldsDef[$fieldName])) { + $breakingChanges[] = [ + 'type' => self::BREAKING_CHANGE_FIELD_REMOVED, + 'description' => "${typeName}.${fieldName} was removed.", + ]; + } else { + $oldFieldType = $oldTypeFieldsDef[$fieldName]->getType(); + $newFieldType = $newTypeFieldsDef[$fieldName]->getType(); + + $isSafe = self::isChangeSafeForInputObjectFieldOrFieldArg( + $oldFieldType, + $newFieldType + ); + if (! $isSafe) { + $oldFieldTypeString = $oldFieldType instanceof NamedType + ? $oldFieldType->name + : $oldFieldType; + $newFieldTypeString = $newFieldType instanceof NamedType + ? $newFieldType->name + : $newFieldType; + $breakingChanges[] = [ + 'type' => self::BREAKING_CHANGE_FIELD_CHANGED_KIND, + 'description' => "${typeName}.${fieldName} changed type from ${oldFieldTypeString} to ${newFieldTypeString}.", + ]; + } + } + } + // Check if a field was added to the input object type + foreach ($newTypeFieldsDef as $fieldName => $fieldDef) { + if (isset($oldTypeFieldsDef[$fieldName])) { + continue; + } + + $newTypeName = $newType->name; + if ($fieldDef->getType() instanceof NonNull) { + $breakingChanges[] = [ + 'type' => self::BREAKING_CHANGE_NON_NULL_INPUT_FIELD_ADDED, + 'description' => "A non-null field ${fieldName} on input type ${newTypeName} was added.", + ]; + } else { + $dangerousChanges[] = [ + 'type' => self::DANGEROUS_CHANGE_NULLABLE_INPUT_FIELD_ADDED, + 'description' => "A nullable field ${fieldName} on input type ${newTypeName} was added.", + ]; + } + } + } + + return [ + 'breakingChanges' => $breakingChanges, + 'dangerousChanges' => $dangerousChanges, + ]; + } + + /** + * @return bool + */ + private static function isChangeSafeForInputObjectFieldOrFieldArg( + Type $oldType, + Type $newType + ) { + if ($oldType instanceof NamedType) { + // if they're both named types, see if their names are equivalent + return $newType instanceof NamedType && $oldType->name === $newType->name; + } + + if ($oldType instanceof ListOfType) { + // if they're both lists, make sure the underlying types are compatible + return $newType instanceof ListOfType && + self::isChangeSafeForInputObjectFieldOrFieldArg( + $oldType->getWrappedType(), + $newType->getWrappedType() + ); + } + + if ($oldType instanceof NonNull) { + return // if they're both non-null, make sure the underlying types are + // compatible + ($newType instanceof NonNull && + self::isChangeSafeForInputObjectFieldOrFieldArg( + $oldType->getWrappedType(), + $newType->getWrappedType() + )) || + // moving from non-null to nullable of the same underlying type is safe + ! ($newType instanceof NonNull) && + self::isChangeSafeForInputObjectFieldOrFieldArg($oldType->getWrappedType(), $newType); + } + + return false; + } + + /** + * Given two schemas, returns an Array containing descriptions of any breaking + * changes in the newSchema related to removing types from a union type. + * + * @return string[][] + */ + public static function findTypesRemovedFromUnions( + Schema $oldSchema, + Schema $newSchema + ) { + $oldTypeMap = $oldSchema->getTypeMap(); + $newTypeMap = $newSchema->getTypeMap(); + + $typesRemovedFromUnion = []; + foreach ($oldTypeMap as $typeName => $oldType) { + $newType = $newTypeMap[$typeName] ?? null; + if (! ($oldType instanceof UnionType) || ! ($newType instanceof UnionType)) { + continue; + } + $typeNamesInNewUnion = []; + foreach ($newType->getTypes() as $type) { + $typeNamesInNewUnion[$type->name] = true; + } + foreach ($oldType->getTypes() as $type) { + if (isset($typeNamesInNewUnion[$type->name])) { + continue; + } + + $typesRemovedFromUnion[] = [ + 'type' => self::BREAKING_CHANGE_TYPE_REMOVED_FROM_UNION, + 'description' => sprintf('%s was removed from union type %s.', $type->name, $typeName), + ]; + } + } + + return $typesRemovedFromUnion; + } + + /** + * Given two schemas, returns an Array containing descriptions of any breaking + * changes in the newSchema related to removing values from an enum type. + * + * @return string[][] + */ + public static function findValuesRemovedFromEnums( + Schema $oldSchema, + Schema $newSchema + ) { + $oldTypeMap = $oldSchema->getTypeMap(); + $newTypeMap = $newSchema->getTypeMap(); + + $valuesRemovedFromEnums = []; + foreach ($oldTypeMap as $typeName => $oldType) { + $newType = $newTypeMap[$typeName] ?? null; + if (! ($oldType instanceof EnumType) || ! ($newType instanceof EnumType)) { + continue; + } + $valuesInNewEnum = []; + foreach ($newType->getValues() as $value) { + $valuesInNewEnum[$value->name] = true; + } + foreach ($oldType->getValues() as $value) { + if (isset($valuesInNewEnum[$value->name])) { + continue; + } + + $valuesRemovedFromEnums[] = [ + 'type' => self::BREAKING_CHANGE_VALUE_REMOVED_FROM_ENUM, + 'description' => sprintf('%s was removed from enum type %s.', $value->name, $typeName), + ]; + } + } + + return $valuesRemovedFromEnums; + } + + /** + * Given two schemas, returns an Array containing descriptions of any + * breaking or dangerous changes in the newSchema related to arguments + * (such as removal or change of type of an argument, or a change in an + * argument's default value). + * + * @return string[][] + */ + public static function findArgChanges( + Schema $oldSchema, + Schema $newSchema + ) { + $oldTypeMap = $oldSchema->getTypeMap(); + $newTypeMap = $newSchema->getTypeMap(); + + $breakingChanges = []; + $dangerousChanges = []; + + foreach ($oldTypeMap as $typeName => $oldType) { + $newType = $newTypeMap[$typeName] ?? null; + if (! ($oldType instanceof ObjectType || $oldType instanceof InterfaceType) || + ! ($newType instanceof ObjectType || $newType instanceof InterfaceType) || + ! ($newType instanceof $oldType) + ) { + continue; + } + + $oldTypeFields = $oldType->getFields(); + $newTypeFields = $newType->getFields(); + + foreach ($oldTypeFields as $fieldName => $oldField) { + if (! isset($newTypeFields[$fieldName])) { + continue; + } + + foreach ($oldField->args as $oldArgDef) { + $newArgs = $newTypeFields[$fieldName]->args; + $newArgDef = Utils::find( + $newArgs, + static function ($arg) use ($oldArgDef) { + return $arg->name === $oldArgDef->name; + } + ); + if ($newArgDef !== null) { + $isSafe = self::isChangeSafeForInputObjectFieldOrFieldArg( + $oldArgDef->getType(), + $newArgDef->getType() + ); + $oldArgType = $oldArgDef->getType(); + $oldArgName = $oldArgDef->name; + if (! $isSafe) { + $newArgType = $newArgDef->getType(); + $breakingChanges[] = [ + 'type' => self::BREAKING_CHANGE_ARG_CHANGED_KIND, + 'description' => "${typeName}.${fieldName} arg ${oldArgName} has changed type from ${oldArgType} to ${newArgType}", + ]; + } elseif ($oldArgDef->defaultValueExists() && $oldArgDef->defaultValue !== $newArgDef->defaultValue) { + $dangerousChanges[] = [ + 'type' => self::DANGEROUS_CHANGE_ARG_DEFAULT_VALUE_CHANGED, + 'description' => "${typeName}.${fieldName} arg ${oldArgName} has changed defaultValue", + ]; + } + } else { + $breakingChanges[] = [ + 'type' => self::BREAKING_CHANGE_ARG_REMOVED, + 'description' => sprintf( + '%s.%s arg %s was removed', + $typeName, + $fieldName, + $oldArgDef->name + ), + ]; + } + // Check if a non-null arg was added to the field + foreach ($newTypeFields[$fieldName]->args as $newTypeFieldArgDef) { + $oldArgs = $oldTypeFields[$fieldName]->args; + $oldArgDef = Utils::find( + $oldArgs, + static function ($arg) use ($newTypeFieldArgDef) { + return $arg->name === $newTypeFieldArgDef->name; + } + ); + + if ($oldArgDef !== null) { + continue; + } + + $newTypeName = $newType->name; + $newArgName = $newTypeFieldArgDef->name; + if ($newTypeFieldArgDef->getType() instanceof NonNull) { + $breakingChanges[] = [ + 'type' => self::BREAKING_CHANGE_NON_NULL_ARG_ADDED, + 'description' => "A non-null arg ${newArgName} on ${newTypeName}.${fieldName} was added", + ]; + } else { + $dangerousChanges[] = [ + 'type' => self::DANGEROUS_CHANGE_NULLABLE_ARG_ADDED, + 'description' => "A nullable arg ${newArgName} on ${newTypeName}.${fieldName} was added", + ]; + } + } + } + } + } + + return [ + 'breakingChanges' => $breakingChanges, + 'dangerousChanges' => $dangerousChanges, + ]; + } + + /** + * @return string[][] + */ + public static function findInterfacesRemovedFromObjectTypes( + Schema $oldSchema, + Schema $newSchema + ) { + $oldTypeMap = $oldSchema->getTypeMap(); + $newTypeMap = $newSchema->getTypeMap(); + $breakingChanges = []; + + foreach ($oldTypeMap as $typeName => $oldType) { + $newType = $newTypeMap[$typeName] ?? null; + if (! ($oldType instanceof ObjectType) || ! ($newType instanceof ObjectType)) { + continue; + } + + $oldInterfaces = $oldType->getInterfaces(); + $newInterfaces = $newType->getInterfaces(); + foreach ($oldInterfaces as $oldInterface) { + $interface = Utils::find( + $newInterfaces, + static function (InterfaceType $interface) use ($oldInterface) : bool { + return $interface->name === $oldInterface->name; + } + ); + if ($interface !== null) { + continue; + } + + $breakingChanges[] = [ + 'type' => self::BREAKING_CHANGE_INTERFACE_REMOVED_FROM_OBJECT, + 'description' => sprintf('%s no longer implements interface %s.', $typeName, $oldInterface->name), + ]; + } + } + + return $breakingChanges; + } + + /** + * @return string[][] + */ + public static function findRemovedDirectives(Schema $oldSchema, Schema $newSchema) + { + $removedDirectives = []; + + $newSchemaDirectiveMap = self::getDirectiveMapForSchema($newSchema); + foreach ($oldSchema->getDirectives() as $directive) { + if (isset($newSchemaDirectiveMap[$directive->name])) { + continue; + } + + $removedDirectives[] = [ + 'type' => self::BREAKING_CHANGE_DIRECTIVE_REMOVED, + 'description' => sprintf('%s was removed', $directive->name), + ]; + } + + return $removedDirectives; + } + + private static function getDirectiveMapForSchema(Schema $schema) + { + return Utils::keyMap( + $schema->getDirectives(), + static function ($dir) { + return $dir->name; + } + ); + } + + public static function findRemovedDirectiveArgs(Schema $oldSchema, Schema $newSchema) + { + $removedDirectiveArgs = []; + $oldSchemaDirectiveMap = self::getDirectiveMapForSchema($oldSchema); + + foreach ($newSchema->getDirectives() as $newDirective) { + if (! isset($oldSchemaDirectiveMap[$newDirective->name])) { + continue; + } + + foreach (self::findRemovedArgsForDirectives( + $oldSchemaDirectiveMap[$newDirective->name], + $newDirective + ) as $arg) { + $removedDirectiveArgs[] = [ + 'type' => self::BREAKING_CHANGE_DIRECTIVE_ARG_REMOVED, + 'description' => sprintf('%s was removed from %s', $arg->name, $newDirective->name), + ]; + } + } + + return $removedDirectiveArgs; + } + + public static function findRemovedArgsForDirectives(Directive $oldDirective, Directive $newDirective) + { + $removedArgs = []; + $newArgMap = self::getArgumentMapForDirective($newDirective); + foreach ($oldDirective->args as $arg) { + if (isset($newArgMap[$arg->name])) { + continue; + } + + $removedArgs[] = $arg; + } + + return $removedArgs; + } + + private static function getArgumentMapForDirective(Directive $directive) + { + return Utils::keyMap( + $directive->args ?: [], + static function ($arg) { + return $arg->name; + } + ); + } + + public static function findAddedNonNullDirectiveArgs(Schema $oldSchema, Schema $newSchema) + { + $addedNonNullableArgs = []; + $oldSchemaDirectiveMap = self::getDirectiveMapForSchema($oldSchema); + + foreach ($newSchema->getDirectives() as $newDirective) { + if (! isset($oldSchemaDirectiveMap[$newDirective->name])) { + continue; + } + + foreach (self::findAddedArgsForDirective( + $oldSchemaDirectiveMap[$newDirective->name], + $newDirective + ) as $arg) { + if (! $arg->getType() instanceof NonNull) { + continue; + } + $addedNonNullableArgs[] = [ + 'type' => self::BREAKING_CHANGE_NON_NULL_DIRECTIVE_ARG_ADDED, + 'description' => sprintf( + 'A non-null arg %s on directive %s was added', + $arg->name, + $newDirective->name + ), + ]; + } + } + + return $addedNonNullableArgs; + } + + /** + * @return FieldArgument[] + */ + public static function findAddedArgsForDirective(Directive $oldDirective, Directive $newDirective) + { + $addedArgs = []; + $oldArgMap = self::getArgumentMapForDirective($oldDirective); + foreach ($newDirective->args as $arg) { + if (isset($oldArgMap[$arg->name])) { + continue; + } + + $addedArgs[] = $arg; + } + + return $addedArgs; + } + + /** + * @return string[][] + */ + public static function findRemovedDirectiveLocations(Schema $oldSchema, Schema $newSchema) + { + $removedLocations = []; + $oldSchemaDirectiveMap = self::getDirectiveMapForSchema($oldSchema); + + foreach ($newSchema->getDirectives() as $newDirective) { + if (! isset($oldSchemaDirectiveMap[$newDirective->name])) { + continue; + } + + foreach (self::findRemovedLocationsForDirective( + $oldSchemaDirectiveMap[$newDirective->name], + $newDirective + ) as $location) { + $removedLocations[] = [ + 'type' => self::BREAKING_CHANGE_DIRECTIVE_LOCATION_REMOVED, + 'description' => sprintf('%s was removed from %s', $location, $newDirective->name), + ]; + } + } + + return $removedLocations; + } + + public static function findRemovedLocationsForDirective(Directive $oldDirective, Directive $newDirective) + { + $removedLocations = []; + $newLocationSet = array_flip($newDirective->locations); + foreach ($oldDirective->locations as $oldLocation) { + if (array_key_exists($oldLocation, $newLocationSet)) { + continue; + } + + $removedLocations[] = $oldLocation; + } + + return $removedLocations; + } + + /** + * Given two schemas, returns an Array containing descriptions of all the types + * of potentially dangerous changes covered by the other functions down below. + * + * @return string[][] + */ + public static function findDangerousChanges(Schema $oldSchema, Schema $newSchema) + { + return array_merge( + self::findArgChanges($oldSchema, $newSchema)['dangerousChanges'], + self::findValuesAddedToEnums($oldSchema, $newSchema), + self::findInterfacesAddedToObjectTypes($oldSchema, $newSchema), + self::findTypesAddedToUnions($oldSchema, $newSchema), + self::findFieldsThatChangedTypeOnInputObjectTypes($oldSchema, $newSchema)['dangerousChanges'] + ); + } + + /** + * Given two schemas, returns an Array containing descriptions of any dangerous + * changes in the newSchema related to adding values to an enum type. + * + * @return string[][] + */ + public static function findValuesAddedToEnums( + Schema $oldSchema, + Schema $newSchema + ) { + $oldTypeMap = $oldSchema->getTypeMap(); + $newTypeMap = $newSchema->getTypeMap(); + + $valuesAddedToEnums = []; + foreach ($oldTypeMap as $typeName => $oldType) { + $newType = $newTypeMap[$typeName] ?? null; + if (! ($oldType instanceof EnumType) || ! ($newType instanceof EnumType)) { + continue; + } + $valuesInOldEnum = []; + foreach ($oldType->getValues() as $value) { + $valuesInOldEnum[$value->name] = true; + } + foreach ($newType->getValues() as $value) { + if (isset($valuesInOldEnum[$value->name])) { + continue; + } + + $valuesAddedToEnums[] = [ + 'type' => self::DANGEROUS_CHANGE_VALUE_ADDED_TO_ENUM, + 'description' => sprintf('%s was added to enum type %s.', $value->name, $typeName), + ]; + } + } + + return $valuesAddedToEnums; + } + + /** + * @return string[][] + */ + public static function findInterfacesAddedToObjectTypes( + Schema $oldSchema, + Schema $newSchema + ) { + $oldTypeMap = $oldSchema->getTypeMap(); + $newTypeMap = $newSchema->getTypeMap(); + $interfacesAddedToObjectTypes = []; + + foreach ($newTypeMap as $typeName => $newType) { + $oldType = $oldTypeMap[$typeName] ?? null; + if (! ($oldType instanceof ObjectType) || ! ($newType instanceof ObjectType)) { + continue; + } + + $oldInterfaces = $oldType->getInterfaces(); + $newInterfaces = $newType->getInterfaces(); + foreach ($newInterfaces as $newInterface) { + $interface = Utils::find( + $oldInterfaces, + static function (InterfaceType $interface) use ($newInterface) : bool { + return $interface->name === $newInterface->name; + } + ); + + if ($interface !== null) { + continue; + } + + $interfacesAddedToObjectTypes[] = [ + 'type' => self::DANGEROUS_CHANGE_INTERFACE_ADDED_TO_OBJECT, + 'description' => sprintf( + '%s added to interfaces implemented by %s.', + $newInterface->name, + $typeName + ), + ]; + } + } + + return $interfacesAddedToObjectTypes; + } + + /** + * Given two schemas, returns an Array containing descriptions of any dangerous + * changes in the newSchema related to adding types to a union type. + * + * @return string[][] + */ + public static function findTypesAddedToUnions( + Schema $oldSchema, + Schema $newSchema + ) { + $oldTypeMap = $oldSchema->getTypeMap(); + $newTypeMap = $newSchema->getTypeMap(); + + $typesAddedToUnion = []; + foreach ($newTypeMap as $typeName => $newType) { + $oldType = $oldTypeMap[$typeName] ?? null; + if (! ($oldType instanceof UnionType) || ! ($newType instanceof UnionType)) { + continue; + } + + $typeNamesInOldUnion = []; + foreach ($oldType->getTypes() as $type) { + $typeNamesInOldUnion[$type->name] = true; + } + foreach ($newType->getTypes() as $type) { + if (isset($typeNamesInOldUnion[$type->name])) { + continue; + } + + $typesAddedToUnion[] = [ + 'type' => self::DANGEROUS_CHANGE_TYPE_ADDED_TO_UNION, + 'description' => sprintf('%s was added to union type %s.', $type->name, $typeName), + ]; + } + } + + return $typesAddedToUnion; + } +} + +class_alias(BreakingChangesFinder::class, 'GraphQL\Utils\FindBreakingChanges'); diff --git a/vendor/webonyx/graphql-php/src/Utils/BuildSchema.php b/vendor/webonyx/graphql-php/src/Utils/BuildSchema.php new file mode 100644 index 0000000..8b5a654 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Utils/BuildSchema.php @@ -0,0 +1,243 @@ +ast = $ast; + $this->typeConfigDecorator = $typeConfigDecorator; + $this->options = $options; + } + + /** + * A helper function to build a GraphQLSchema directly from a source + * document. + * + * @param DocumentNode|Source|string $source + * @param bool[] $options + * + * @return Schema + * + * @api + */ + public static function build($source, ?callable $typeConfigDecorator = null, array $options = []) + { + $doc = $source instanceof DocumentNode ? $source : Parser::parse($source); + + return self::buildAST($doc, $typeConfigDecorator, $options); + } + + /** + * This takes the ast of a schema document produced by the parse function in + * GraphQL\Language\Parser. + * + * If no schema definition is provided, then it will look for types named Query + * and Mutation. + * + * Given that AST it constructs a GraphQL\Type\Schema. The resulting schema + * has no resolve methods, so execution will use default resolvers. + * + * Accepts options as a third argument: + * + * - commentDescriptions: + * Provide true to use preceding comments as the description. + * + * @param bool[] $options + * + * @return Schema + * + * @throws Error + * + * @api + */ + public static function buildAST(DocumentNode $ast, ?callable $typeConfigDecorator = null, array $options = []) + { + $builder = new self($ast, $typeConfigDecorator, $options); + + return $builder->buildSchema(); + } + + public function buildSchema() + { + /** @var SchemaDefinitionNode $schemaDef */ + $schemaDef = null; + $typeDefs = []; + $this->nodeMap = []; + $directiveDefs = []; + foreach ($this->ast->definitions as $d) { + switch ($d->kind) { + case NodeKind::SCHEMA_DEFINITION: + if ($schemaDef) { + throw new Error('Must provide only one schema definition.'); + } + $schemaDef = $d; + break; + case NodeKind::SCALAR_TYPE_DEFINITION: + case NodeKind::OBJECT_TYPE_DEFINITION: + case NodeKind::INTERFACE_TYPE_DEFINITION: + case NodeKind::ENUM_TYPE_DEFINITION: + case NodeKind::UNION_TYPE_DEFINITION: + case NodeKind::INPUT_OBJECT_TYPE_DEFINITION: + $typeName = $d->name->value; + if (! empty($this->nodeMap[$typeName])) { + throw new Error(sprintf('Type "%s" was defined more than once.', $typeName)); + } + $typeDefs[] = $d; + $this->nodeMap[$typeName] = $d; + break; + case NodeKind::DIRECTIVE_DEFINITION: + $directiveDefs[] = $d; + break; + } + } + + $operationTypes = $schemaDef + ? $this->getOperationTypes($schemaDef) + : [ + 'query' => isset($this->nodeMap['Query']) ? 'Query' : null, + 'mutation' => isset($this->nodeMap['Mutation']) ? 'Mutation' : null, + 'subscription' => isset($this->nodeMap['Subscription']) ? 'Subscription' : null, + ]; + + $DefinitionBuilder = new ASTDefinitionBuilder( + $this->nodeMap, + $this->options, + static function ($typeName) { + throw new Error('Type "' . $typeName . '" not found in document.'); + }, + $this->typeConfigDecorator + ); + + $directives = array_map( + static function ($def) use ($DefinitionBuilder) { + return $DefinitionBuilder->buildDirective($def); + }, + $directiveDefs + ); + + // If specified directives were not explicitly declared, add them. + $skip = array_reduce( + $directives, + static function ($hasSkip, $directive) { + return (bool) $hasSkip || $directive->name === 'skip'; + } + ); + if (! $skip) { + $directives[] = Directive::skipDirective(); + } + + $include = array_reduce( + $directives, + static function ($hasInclude, $directive) { + return (bool) $hasInclude || $directive->name === 'include'; + } + ); + if (! $include) { + $directives[] = Directive::includeDirective(); + } + + $deprecated = array_reduce( + $directives, + static function ($hasDeprecated, $directive) { + return (bool) $hasDeprecated || $directive->name === 'deprecated'; + } + ); + if (! $deprecated) { + $directives[] = Directive::deprecatedDirective(); + } + + // Note: While this could make early assertions to get the correctly + // typed values below, that would throw immediately while type system + // validation with validateSchema() will produce more actionable results. + + return new Schema([ + 'query' => isset($operationTypes['query']) + ? $DefinitionBuilder->buildType($operationTypes['query']) + : null, + 'mutation' => isset($operationTypes['mutation']) + ? $DefinitionBuilder->buildType($operationTypes['mutation']) + : null, + 'subscription' => isset($operationTypes['subscription']) + ? $DefinitionBuilder->buildType($operationTypes['subscription']) + : null, + 'typeLoader' => static function ($name) use ($DefinitionBuilder) { + return $DefinitionBuilder->buildType($name); + }, + 'directives' => $directives, + 'astNode' => $schemaDef, + 'types' => function () use ($DefinitionBuilder) { + $types = []; + foreach ($this->nodeMap as $name => $def) { + $types[] = $DefinitionBuilder->buildType($def->name->value); + } + + return $types; + }, + ]); + } + + /** + * @param SchemaDefinitionNode $schemaDef + * + * @return string[] + * + * @throws Error + */ + private function getOperationTypes($schemaDef) + { + $opTypes = []; + + foreach ($schemaDef->operationTypes as $operationType) { + $typeName = $operationType->type->name->value; + $operation = $operationType->operation; + + if (isset($opTypes[$operation])) { + throw new Error(sprintf('Must provide only one %s type in schema.', $operation)); + } + + if (! isset($this->nodeMap[$typeName])) { + throw new Error(sprintf('Specified %s type "%s" not found in document.', $operation, $typeName)); + } + + $opTypes[$operation] = $typeName; + } + + return $opTypes; + } +} diff --git a/vendor/webonyx/graphql-php/src/Utils/MixedStore.php b/vendor/webonyx/graphql-php/src/Utils/MixedStore.php new file mode 100644 index 0000000..469abaa --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Utils/MixedStore.php @@ -0,0 +1,249 @@ +standardStore = []; + $this->floatStore = []; + $this->objectStore = new SplObjectStorage(); + $this->arrayKeys = []; + $this->arrayValues = []; + $this->nullValueIsSet = false; + $this->trueValueIsSet = false; + $this->falseValueIsSet = false; + } + + /** + * Whether a offset exists + * + * @link http://php.net/manual/en/arrayaccess.offsetexists.php + * + * @param mixed $offset

+ * An offset to check for. + *

+ * + * @return bool true on success or false on failure. + *

+ *

+ * The return value will be casted to boolean if non-boolean was returned. + */ + public function offsetExists($offset) + { + if ($offset === false) { + return $this->falseValueIsSet; + } + if ($offset === true) { + return $this->trueValueIsSet; + } + if (is_int($offset) || is_string($offset)) { + return array_key_exists($offset, $this->standardStore); + } + if (is_float($offset)) { + return array_key_exists((string) $offset, $this->floatStore); + } + if (is_object($offset)) { + return $this->objectStore->offsetExists($offset); + } + if (is_array($offset)) { + foreach ($this->arrayKeys as $index => $entry) { + if ($entry === $offset) { + $this->lastArrayKey = $offset; + $this->lastArrayValue = $this->arrayValues[$index]; + + return true; + } + } + } + if ($offset === null) { + return $this->nullValueIsSet; + } + + return false; + } + + /** + * Offset to retrieve + * + * @link http://php.net/manual/en/arrayaccess.offsetget.php + * + * @param mixed $offset

+ * The offset to retrieve. + *

+ * + * @return mixed Can return all value types. + */ + public function offsetGet($offset) + { + if ($offset === true) { + return $this->trueValue; + } + if ($offset === false) { + return $this->falseValue; + } + if (is_int($offset) || is_string($offset)) { + return $this->standardStore[$offset]; + } + if (is_float($offset)) { + return $this->floatStore[(string) $offset]; + } + if (is_object($offset)) { + return $this->objectStore->offsetGet($offset); + } + if (is_array($offset)) { + // offsetGet is often called directly after offsetExists, so optimize to avoid second loop: + if ($this->lastArrayKey === $offset) { + return $this->lastArrayValue; + } + foreach ($this->arrayKeys as $index => $entry) { + if ($entry === $offset) { + return $this->arrayValues[$index]; + } + } + } + if ($offset === null) { + return $this->nullValue; + } + + return null; + } + + /** + * Offset to set + * + * @link http://php.net/manual/en/arrayaccess.offsetset.php + * + * @param mixed $offset

+ * The offset to assign the value to. + *

+ * @param mixed $value

+ * The value to set. + *

+ * + * @return void + */ + public function offsetSet($offset, $value) + { + if ($offset === false) { + $this->falseValue = $value; + $this->falseValueIsSet = true; + } elseif ($offset === true) { + $this->trueValue = $value; + $this->trueValueIsSet = true; + } elseif (is_int($offset) || is_string($offset)) { + $this->standardStore[$offset] = $value; + } elseif (is_float($offset)) { + $this->floatStore[(string) $offset] = $value; + } elseif (is_object($offset)) { + $this->objectStore[$offset] = $value; + } elseif (is_array($offset)) { + $this->arrayKeys[] = $offset; + $this->arrayValues[] = $value; + } elseif ($offset === null) { + $this->nullValue = $value; + $this->nullValueIsSet = true; + } else { + throw new InvalidArgumentException('Unexpected offset type: ' . Utils::printSafe($offset)); + } + } + + /** + * Offset to unset + * + * @link http://php.net/manual/en/arrayaccess.offsetunset.php + * + * @param mixed $offset

+ * The offset to unset. + *

+ * + * @return void + */ + public function offsetUnset($offset) + { + if ($offset === true) { + $this->trueValue = null; + $this->trueValueIsSet = false; + } elseif ($offset === false) { + $this->falseValue = null; + $this->falseValueIsSet = false; + } elseif (is_int($offset) || is_string($offset)) { + unset($this->standardStore[$offset]); + } elseif (is_float($offset)) { + unset($this->floatStore[(string) $offset]); + } elseif (is_object($offset)) { + $this->objectStore->offsetUnset($offset); + } elseif (is_array($offset)) { + $index = array_search($offset, $this->arrayKeys, true); + + if ($index !== false) { + array_splice($this->arrayKeys, $index, 1); + array_splice($this->arrayValues, $index, 1); + } + } elseif ($offset === null) { + $this->nullValue = null; + $this->nullValueIsSet = false; + } + } +} diff --git a/vendor/webonyx/graphql-php/src/Utils/PairSet.php b/vendor/webonyx/graphql-php/src/Utils/PairSet.php new file mode 100644 index 0000000..fe3a514 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Utils/PairSet.php @@ -0,0 +1,66 @@ +data = []; + } + + /** + * @param string $a + * @param string $b + * @param bool $areMutuallyExclusive + * + * @return bool + */ + public function has($a, $b, $areMutuallyExclusive) + { + $first = $this->data[$a] ?? null; + $result = $first && isset($first[$b]) ? $first[$b] : null; + if ($result === null) { + return false; + } + // areMutuallyExclusive being false is a superset of being true, + // hence if we want to know if this PairSet "has" these two with no + // exclusivity, we have to ensure it was added as such. + if ($areMutuallyExclusive === false) { + return $result === false; + } + + return true; + } + + /** + * @param string $a + * @param string $b + * @param bool $areMutuallyExclusive + */ + public function add($a, $b, $areMutuallyExclusive) + { + $this->pairSetAdd($a, $b, $areMutuallyExclusive); + $this->pairSetAdd($b, $a, $areMutuallyExclusive); + } + + /** + * @param string $a + * @param string $b + * @param bool $areMutuallyExclusive + */ + private function pairSetAdd($a, $b, $areMutuallyExclusive) + { + $this->data[$a] = $this->data[$a] ?? []; + $this->data[$a][$b] = $areMutuallyExclusive; + } +} diff --git a/vendor/webonyx/graphql-php/src/Utils/SchemaExtender.php b/vendor/webonyx/graphql-php/src/Utils/SchemaExtender.php new file mode 100644 index 0000000..07a1447 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Utils/SchemaExtender.php @@ -0,0 +1,631 @@ +name; + if ($type->extensionASTNodes !== null) { + if (isset(static::$typeExtensionsMap[$name])) { + return array_merge($type->extensionASTNodes, static::$typeExtensionsMap[$name]); + } + + return $type->extensionASTNodes; + } + + return static::$typeExtensionsMap[$name] ?? null; + } + + /** + * @throws Error + */ + protected static function checkExtensionNode(Type $type, Node $node) : void + { + switch ($node->kind) { + case NodeKind::OBJECT_TYPE_EXTENSION: + if (! ($type instanceof ObjectType)) { + throw new Error( + 'Cannot extend non-object type "' . $type->name . '".', + [$node] + ); + } + break; + case NodeKind::INTERFACE_TYPE_EXTENSION: + if (! ($type instanceof InterfaceType)) { + throw new Error( + 'Cannot extend non-interface type "' . $type->name . '".', + [$node] + ); + } + break; + case NodeKind::ENUM_TYPE_EXTENSION: + if (! ($type instanceof EnumType)) { + throw new Error( + 'Cannot extend non-enum type "' . $type->name . '".', + [$node] + ); + } + break; + case NodeKind::UNION_TYPE_EXTENSION: + if (! ($type instanceof UnionType)) { + throw new Error( + 'Cannot extend non-union type "' . $type->name . '".', + [$node] + ); + } + break; + case NodeKind::INPUT_OBJECT_TYPE_EXTENSION: + if (! ($type instanceof InputObjectType)) { + throw new Error( + 'Cannot extend non-input object type "' . $type->name . '".', + [$node] + ); + } + break; + } + } + + protected static function extendCustomScalarType(CustomScalarType $type) : CustomScalarType + { + return new CustomScalarType([ + 'name' => $type->name, + 'description' => $type->description, + 'astNode' => $type->astNode, + 'serialize' => $type->config['serialize'] ?? null, + 'parseValue' => $type->config['parseValue'] ?? null, + 'parseLiteral' => $type->config['parseLiteral'] ?? null, + 'extensionASTNodes' => static::getExtensionASTNodes($type), + ]); + } + + protected static function extendUnionType(UnionType $type) : UnionType + { + return new UnionType([ + 'name' => $type->name, + 'description' => $type->description, + 'types' => static function () use ($type) { + return static::extendPossibleTypes($type); + }, + 'astNode' => $type->astNode, + 'resolveType' => $type->config['resolveType'] ?? null, + 'extensionASTNodes' => static::getExtensionASTNodes($type), + ]); + } + + protected static function extendEnumType(EnumType $type) : EnumType + { + return new EnumType([ + 'name' => $type->name, + 'description' => $type->description, + 'values' => static::extendValueMap($type), + 'astNode' => $type->astNode, + 'extensionASTNodes' => static::getExtensionASTNodes($type), + ]); + } + + protected static function extendInputObjectType(InputObjectType $type) : InputObjectType + { + return new InputObjectType([ + 'name' => $type->name, + 'description' => $type->description, + 'fields' => static function () use ($type) { + return static::extendInputFieldMap($type); + }, + 'astNode' => $type->astNode, + 'extensionASTNodes' => static::getExtensionASTNodes($type), + ]); + } + + /** + * @return mixed[] + */ + protected static function extendInputFieldMap(InputObjectType $type) : array + { + $newFieldMap = []; + $oldFieldMap = $type->getFields(); + foreach ($oldFieldMap as $fieldName => $field) { + $newFieldMap[$fieldName] = [ + 'description' => $field->description, + 'type' => static::extendType($field->type), + 'astNode' => $field->astNode, + ]; + + if (! $field->defaultValueExists()) { + continue; + } + + $newFieldMap[$fieldName]['defaultValue'] = $field->defaultValue; + } + + $extensions = static::$typeExtensionsMap[$type->name] ?? null; + if ($extensions !== null) { + foreach ($extensions as $extension) { + foreach ($extension->fields as $field) { + $fieldName = $field->name->value; + if (isset($oldFieldMap[$fieldName])) { + throw new Error('Field "' . $type->name . '.' . $fieldName . '" already exists in the schema. It cannot also be defined in this type extension.', [$field]); + } + + $newFieldMap[$fieldName] = static::$astBuilder->buildInputField($field); + } + } + } + + return $newFieldMap; + } + + /** + * @return mixed[] + */ + protected static function extendValueMap(EnumType $type) : array + { + $newValueMap = []; + /** @var EnumValueDefinition[] $oldValueMap */ + $oldValueMap = []; + foreach ($type->getValues() as $value) { + $oldValueMap[$value->name] = $value; + } + + foreach ($oldValueMap as $key => $value) { + $newValueMap[$key] = [ + 'name' => $value->name, + 'description' => $value->description, + 'value' => $value->value, + 'deprecationReason' => $value->deprecationReason, + 'astNode' => $value->astNode, + ]; + } + + $extensions = static::$typeExtensionsMap[$type->name] ?? null; + if ($extensions !== null) { + foreach ($extensions as $extension) { + foreach ($extension->values as $value) { + $valueName = $value->name->value; + if (isset($oldValueMap[$valueName])) { + throw new Error('Enum value "' . $type->name . '.' . $valueName . '" already exists in the schema. It cannot also be defined in this type extension.', [$value]); + } + $newValueMap[$valueName] = static::$astBuilder->buildEnumValue($value); + } + } + } + + return $newValueMap; + } + + /** + * @return ObjectType[] + */ + protected static function extendPossibleTypes(UnionType $type) : array + { + $possibleTypes = array_map(static function ($type) { + return static::extendNamedType($type); + }, $type->getTypes()); + + $extensions = static::$typeExtensionsMap[$type->name] ?? null; + if ($extensions !== null) { + foreach ($extensions as $extension) { + foreach ($extension->types as $namedType) { + $possibleTypes[] = static::$astBuilder->buildType($namedType); + } + } + } + + return $possibleTypes; + } + + /** + * @return InterfaceType[] + */ + protected static function extendImplementedInterfaces(ObjectType $type) : array + { + $interfaces = array_map(static function (InterfaceType $interfaceType) { + return static::extendNamedType($interfaceType); + }, $type->getInterfaces()); + + $extensions = static::$typeExtensionsMap[$type->name] ?? null; + if ($extensions !== null) { + /** @var ObjectTypeExtensionNode $extension */ + foreach ($extensions as $extension) { + foreach ($extension->interfaces as $namedType) { + $interfaces[] = static::$astBuilder->buildType($namedType); + } + } + } + + return $interfaces; + } + + protected static function extendType($typeDef) + { + if ($typeDef instanceof ListOfType) { + return Type::listOf(static::extendType($typeDef->ofType)); + } + + if ($typeDef instanceof NonNull) { + return Type::nonNull(static::extendType($typeDef->getWrappedType())); + } + + return static::extendNamedType($typeDef); + } + + /** + * @param FieldArgument[] $args + * + * @return mixed[] + */ + protected static function extendArgs(array $args) : array + { + return Utils::keyValMap( + $args, + static function (FieldArgument $arg) { + return $arg->name; + }, + static function (FieldArgument $arg) { + $def = [ + 'type' => static::extendType($arg->getType()), + 'description' => $arg->description, + 'astNode' => $arg->astNode, + ]; + + if ($arg->defaultValueExists()) { + $def['defaultValue'] = $arg->defaultValue; + } + + return $def; + } + ); + } + + /** + * @param InterfaceType|ObjectType $type + * + * @return mixed[] + * + * @throws Error + */ + protected static function extendFieldMap($type) : array + { + $newFieldMap = []; + $oldFieldMap = $type->getFields(); + + foreach (array_keys($oldFieldMap) as $fieldName) { + $field = $oldFieldMap[$fieldName]; + + $newFieldMap[$fieldName] = [ + 'name' => $fieldName, + 'description' => $field->description, + 'deprecationReason' => $field->deprecationReason, + 'type' => static::extendType($field->getType()), + 'args' => static::extendArgs($field->args), + 'astNode' => $field->astNode, + 'resolve' => $field->resolveFn, + ]; + } + + $extensions = static::$typeExtensionsMap[$type->name] ?? null; + if ($extensions !== null) { + foreach ($extensions as $extension) { + foreach ($extension->fields as $field) { + $fieldName = $field->name->value; + if (isset($oldFieldMap[$fieldName])) { + throw new Error('Field "' . $type->name . '.' . $fieldName . '" already exists in the schema. It cannot also be defined in this type extension.', [$field]); + } + + $newFieldMap[$fieldName] = static::$astBuilder->buildField($field); + } + } + } + + return $newFieldMap; + } + + protected static function extendObjectType(ObjectType $type) : ObjectType + { + return new ObjectType([ + 'name' => $type->name, + 'description' => $type->description, + 'interfaces' => static function () use ($type) { + return static::extendImplementedInterfaces($type); + }, + 'fields' => static function () use ($type) { + return static::extendFieldMap($type); + }, + 'astNode' => $type->astNode, + 'extensionASTNodes' => static::getExtensionASTNodes($type), + 'isTypeOf' => $type->config['isTypeOf'] ?? null, + ]); + } + + protected static function extendInterfaceType(InterfaceType $type) : InterfaceType + { + return new InterfaceType([ + 'name' => $type->name, + 'description' => $type->description, + 'fields' => static function () use ($type) { + return static::extendFieldMap($type); + }, + 'astNode' => $type->astNode, + 'extensionASTNodes' => static::getExtensionASTNodes($type), + 'resolveType' => $type->config['resolveType'] ?? null, + ]); + } + + protected static function isSpecifiedScalarType(Type $type) : bool + { + return $type instanceof NamedType && + ( + $type->name === Type::STRING || + $type->name === Type::INT || + $type->name === Type::FLOAT || + $type->name === Type::BOOLEAN || + $type->name === Type::ID + ); + } + + protected static function extendNamedType(Type $type) + { + if (Introspection::isIntrospectionType($type) || static::isSpecifiedScalarType($type)) { + return $type; + } + + $name = $type->name; + if (! isset(static::$extendTypeCache[$name])) { + if ($type instanceof CustomScalarType) { + static::$extendTypeCache[$name] = static::extendCustomScalarType($type); + } elseif ($type instanceof ObjectType) { + static::$extendTypeCache[$name] = static::extendObjectType($type); + } elseif ($type instanceof InterfaceType) { + static::$extendTypeCache[$name] = static::extendInterfaceType($type); + } elseif ($type instanceof UnionType) { + static::$extendTypeCache[$name] = static::extendUnionType($type); + } elseif ($type instanceof EnumType) { + static::$extendTypeCache[$name] = static::extendEnumType($type); + } elseif ($type instanceof InputObjectType) { + static::$extendTypeCache[$name] = static::extendInputObjectType($type); + } + } + + return static::$extendTypeCache[$name]; + } + + /** + * @return mixed|null + */ + protected static function extendMaybeNamedType(?NamedType $type = null) + { + if ($type !== null) { + return static::extendNamedType($type); + } + + return null; + } + + /** + * @param DirectiveDefinitionNode[] $directiveDefinitions + * + * @return Directive[] + */ + protected static function getMergedDirectives(Schema $schema, array $directiveDefinitions) : array + { + $existingDirectives = array_map(static function (Directive $directive) { + return static::extendDirective($directive); + }, $schema->getDirectives()); + + Utils::invariant(count($existingDirectives) > 0, 'schema must have default directives'); + + return array_merge( + $existingDirectives, + array_map(static function (DirectiveDefinitionNode $directive) { + return static::$astBuilder->buildDirective($directive); + }, $directiveDefinitions) + ); + } + + protected static function extendDirective(Directive $directive) : Directive + { + return new Directive([ + 'name' => $directive->name, + 'description' => $directive->description, + 'locations' => $directive->locations, + 'args' => static::extendArgs($directive->args), + 'astNode' => $directive->astNode, + ]); + } + + /** + * @param mixed[]|null $options + */ + public static function extend(Schema $schema, DocumentNode $documentAST, ?array $options = null) : Schema + { + if ($options === null || ! (isset($options['assumeValid']) || isset($options['assumeValidSDL']))) { + DocumentValidator::assertValidSDLExtension($documentAST, $schema); + } + + $typeDefinitionMap = []; + static::$typeExtensionsMap = []; + $directiveDefinitions = []; + /** @var SchemaDefinitionNode|null $schemaDef */ + $schemaDef = null; + /** @var SchemaTypeExtensionNode[] $schemaExtensions */ + $schemaExtensions = []; + + $definitionsCount = count($documentAST->definitions); + for ($i = 0; $i < $definitionsCount; $i++) { + + /** @var Node $def */ + $def = $documentAST->definitions[$i]; + + if ($def instanceof SchemaDefinitionNode) { + $schemaDef = $def; + } elseif ($def instanceof SchemaTypeExtensionNode) { + $schemaExtensions[] = $def; + } elseif ($def instanceof TypeDefinitionNode) { + $typeName = isset($def->name) ? $def->name->value : null; + + try { + $type = $schema->getType($typeName); + } catch (Error $error) { + $type = null; + } + + if ($type) { + throw new Error('Type "' . $typeName . '" already exists in the schema. It cannot also be defined in this type definition.', [$def]); + } + $typeDefinitionMap[$typeName] = $def; + } elseif ($def instanceof TypeExtensionNode) { + $extendedTypeName = isset($def->name) ? $def->name->value : null; + $existingType = $schema->getType($extendedTypeName); + if ($existingType === null) { + throw new Error('Cannot extend type "' . $extendedTypeName . '" because it does not exist in the existing schema.', [$def]); + } + + static::checkExtensionNode($existingType, $def); + + $existingTypeExtensions = static::$typeExtensionsMap[$extendedTypeName] ?? null; + static::$typeExtensionsMap[$extendedTypeName] = $existingTypeExtensions !== null ? array_merge($existingTypeExtensions, [$def]) : [$def]; + } elseif ($def instanceof DirectiveDefinitionNode) { + $directiveName = $def->name->value; + $existingDirective = $schema->getDirective($directiveName); + if ($existingDirective !== null) { + throw new Error('Directive "' . $directiveName . '" already exists in the schema. It cannot be redefined.', [$def]); + } + $directiveDefinitions[] = $def; + } + } + + if (count(static::$typeExtensionsMap) === 0 && + count($typeDefinitionMap) === 0 && + count($directiveDefinitions) === 0 && + count($schemaExtensions) === 0 && + $schemaDef === null + ) { + return $schema; + } + + static::$astBuilder = new ASTDefinitionBuilder( + $typeDefinitionMap, + $options, + static function (string $typeName) use ($schema) { + /** @var NamedType $existingType */ + $existingType = $schema->getType($typeName); + if ($existingType !== null) { + return static::extendNamedType($existingType); + } + + throw new Error('Unknown type: "' . $typeName . '". Ensure that this type exists either in the original schema, or is added in a type definition.', [$typeName]); + } + ); + + static::$extendTypeCache = []; + + $operationTypes = [ + 'query' => static::extendMaybeNamedType($schema->getQueryType()), + 'mutation' => static::extendMaybeNamedType($schema->getMutationType()), + 'subscription' => static::extendMaybeNamedType($schema->getSubscriptionType()), + ]; + + if ($schemaDef) { + foreach ($schemaDef->operationTypes as $operationType) { + $operation = $operationType->operation; + $type = $operationType->type; + + if (isset($operationTypes[$operation])) { + throw new Error('Must provide only one ' . $operation . ' type in schema.'); + } + + $operationTypes[$operation] = static::$astBuilder->buildType($type); + } + } + + foreach ($schemaExtensions as $schemaExtension) { + if (! $schemaExtension->operationTypes) { + continue; + } + + foreach ($schemaExtension->operationTypes as $operationType) { + $operation = $operationType->operation; + if (isset($operationTypes[$operation])) { + throw new Error('Must provide only one ' . $operation . ' type in schema.'); + } + $operationTypes[$operation] = static::$astBuilder->buildType($operationType->type); + } + } + + $schemaExtensionASTNodes = count($schemaExtensions) > 0 + ? ($schema->extensionASTNodes ? array_merge($schema->extensionASTNodes, $schemaExtensions) : $schemaExtensions) + : $schema->extensionASTNodes; + + $types = array_merge( + array_map(static function ($type) { + return static::extendType($type); + }, array_values($schema->getTypeMap())), + array_map(static function ($type) { + return static::$astBuilder->buildType($type); + }, array_values($typeDefinitionMap)) + ); + + return new Schema([ + 'query' => $operationTypes['query'], + 'mutation' => $operationTypes['mutation'], + 'subscription' => $operationTypes['subscription'], + 'types' => $types, + 'directives' => static::getMergedDirectives($schema, $directiveDefinitions), + 'astNode' => $schema->getAstNode(), + 'extensionASTNodes' => $schemaExtensionASTNodes, + ]); + } +} diff --git a/vendor/webonyx/graphql-php/src/Utils/SchemaPrinter.php b/vendor/webonyx/graphql-php/src/Utils/SchemaPrinter.php new file mode 100644 index 0000000..9e9e1ca --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Utils/SchemaPrinter.php @@ -0,0 +1,489 @@ +getDirectives(), + static function ($directive) use ($directiveFilter) { + return $directiveFilter($directive); + } + ); + + $types = $schema->getTypeMap(); + ksort($types); + $types = array_filter($types, $typeFilter); + + return sprintf( + "%s\n", + implode( + "\n\n", + array_filter( + array_merge( + [self::printSchemaDefinition($schema)], + array_map( + static function ($directive) use ($options) { + return self::printDirective($directive, $options); + }, + $directives + ), + array_map( + static function ($type) use ($options) { + return self::printType($type, $options); + }, + $types + ) + ) + ) + ) + ); + } + + private static function printSchemaDefinition(Schema $schema) + { + if (self::isSchemaOfCommonNames($schema)) { + return; + } + + $operationTypes = []; + + $queryType = $schema->getQueryType(); + if ($queryType) { + $operationTypes[] = sprintf(' query: %s', $queryType->name); + } + + $mutationType = $schema->getMutationType(); + if ($mutationType) { + $operationTypes[] = sprintf(' mutation: %s', $mutationType->name); + } + + $subscriptionType = $schema->getSubscriptionType(); + if ($subscriptionType) { + $operationTypes[] = sprintf(' subscription: %s', $subscriptionType->name); + } + + return sprintf("schema {\n%s\n}", implode("\n", $operationTypes)); + } + + /** + * GraphQL schema define root types for each type of operation. These types are + * the same as any other type and can be named in any manner, however there is + * a common naming convention: + * + * schema { + * query: Query + * mutation: Mutation + * } + * + * When using this naming convention, the schema description can be omitted. + */ + private static function isSchemaOfCommonNames(Schema $schema) + { + $queryType = $schema->getQueryType(); + if ($queryType && $queryType->name !== 'Query') { + return false; + } + + $mutationType = $schema->getMutationType(); + if ($mutationType && $mutationType->name !== 'Mutation') { + return false; + } + + $subscriptionType = $schema->getSubscriptionType(); + + return ! $subscriptionType || $subscriptionType->name === 'Subscription'; + } + + private static function printDirective($directive, $options) : string + { + return self::printDescription($options, $directive) . + 'directive @' . $directive->name . self::printArgs($options, $directive->args) . + ' on ' . implode(' | ', $directive->locations); + } + + private static function printDescription($options, $def, $indentation = '', $firstInBlock = true) : string + { + if (! $def->description) { + return ''; + } + $lines = self::descriptionLines($def->description, 120 - strlen($indentation)); + if (isset($options['commentDescriptions'])) { + return self::printDescriptionWithComments($lines, $indentation, $firstInBlock); + } + + $description = $indentation && ! $firstInBlock + ? "\n" . $indentation . '"""' + : $indentation . '"""'; + + // In some circumstances, a single line can be used for the description. + if (count($lines) === 1 && + mb_strlen($lines[0]) < 70 && + substr($lines[0], -1) !== '"' + ) { + return $description . self::escapeQuote($lines[0]) . "\"\"\"\n"; + } + + // Format a multi-line block quote to account for leading space. + $hasLeadingSpace = isset($lines[0]) && + ( + substr($lines[0], 0, 1) === ' ' || + substr($lines[0], 0, 1) === '\t' + ); + if (! $hasLeadingSpace) { + $description .= "\n"; + } + + $lineLength = count($lines); + for ($i = 0; $i < $lineLength; $i++) { + if ($i !== 0 || ! $hasLeadingSpace) { + $description .= $indentation; + } + $description .= self::escapeQuote($lines[$i]) . "\n"; + } + $description .= $indentation . "\"\"\"\n"; + + return $description; + } + + /** + * @return string[] + */ + private static function descriptionLines(string $description, int $maxLen) : array + { + $lines = []; + $rawLines = explode("\n", $description); + foreach ($rawLines as $line) { + if ($line === '') { + $lines[] = $line; + } else { + // For > 120 character long lines, cut at space boundaries into sublines + // of ~80 chars. + $sublines = self::breakLine($line, $maxLen); + foreach ($sublines as $subline) { + $lines[] = $subline; + } + } + } + + return $lines; + } + + /** + * @return string[] + */ + private static function breakLine(string $line, int $maxLen) : array + { + if (strlen($line) < $maxLen + 5) { + return [$line]; + } + preg_match_all('/((?: |^).{15,' . ($maxLen - 40) . '}(?= |$))/', $line, $parts); + $parts = $parts[0]; + + return array_map('trim', $parts); + } + + private static function printDescriptionWithComments($lines, $indentation, $firstInBlock) : string + { + $description = $indentation && ! $firstInBlock ? "\n" : ''; + foreach ($lines as $line) { + if ($line === '') { + $description .= $indentation . "#\n"; + } else { + $description .= $indentation . '# ' . $line . "\n"; + } + } + + return $description; + } + + private static function escapeQuote($line) : string + { + return str_replace('"""', '\\"""', $line); + } + + private static function printArgs($options, $args, $indentation = '') : string + { + if (! $args) { + return ''; + } + + // If every arg does not have a description, print them on one line. + if (Utils::every( + $args, + static function ($arg) { + return empty($arg->description); + } + )) { + return '(' . implode(', ', array_map('self::printInputValue', $args)) . ')'; + } + + return sprintf( + "(\n%s\n%s)", + implode( + "\n", + array_map( + static function ($arg, $i) use ($indentation, $options) { + return self::printDescription($options, $arg, ' ' . $indentation, ! $i) . ' ' . $indentation . + self::printInputValue($arg); + }, + $args, + array_keys($args) + ) + ), + $indentation + ); + } + + private static function printInputValue($arg) : string + { + $argDecl = $arg->name . ': ' . (string) $arg->getType(); + if ($arg->defaultValueExists()) { + $argDecl .= ' = ' . Printer::doPrint(AST::astFromValue($arg->defaultValue, $arg->getType())); + } + + return $argDecl; + } + + /** + * @param bool[] $options + */ + public static function printType(Type $type, array $options = []) : string + { + if ($type instanceof ScalarType) { + return self::printScalar($type, $options); + } + + if ($type instanceof ObjectType) { + return self::printObject($type, $options); + } + + if ($type instanceof InterfaceType) { + return self::printInterface($type, $options); + } + + if ($type instanceof UnionType) { + return self::printUnion($type, $options); + } + + if ($type instanceof EnumType) { + return self::printEnum($type, $options); + } + + if ($type instanceof InputObjectType) { + return self::printInputObject($type, $options); + } + + throw new Error(sprintf('Unknown type: %s.', Utils::printSafe($type))); + } + + /** + * @param bool[] $options + */ + private static function printScalar(ScalarType $type, array $options) : string + { + return sprintf('%sscalar %s', self::printDescription($options, $type), $type->name); + } + + /** + * @param bool[] $options + */ + private static function printObject(ObjectType $type, array $options) : string + { + $interfaces = $type->getInterfaces(); + $implementedInterfaces = ! empty($interfaces) ? + ' implements ' . implode( + ' & ', + array_map( + static function ($i) { + return $i->name; + }, + $interfaces + ) + ) : ''; + + return self::printDescription($options, $type) . + sprintf("type %s%s {\n%s\n}", $type->name, $implementedInterfaces, self::printFields($options, $type)); + } + + /** + * @param bool[] $options + */ + private static function printFields($options, $type) : string + { + $fields = array_values($type->getFields()); + + return implode( + "\n", + array_map( + static function ($f, $i) use ($options) { + return self::printDescription($options, $f, ' ', ! $i) . ' ' . + $f->name . self::printArgs($options, $f->args, ' ') . ': ' . + (string) $f->getType() . self::printDeprecated($f); + }, + $fields, + array_keys($fields) + ) + ); + } + + private static function printDeprecated($fieldOrEnumVal) : string + { + $reason = $fieldOrEnumVal->deprecationReason; + if (empty($reason)) { + return ''; + } + if ($reason === '' || $reason === Directive::DEFAULT_DEPRECATION_REASON) { + return ' @deprecated'; + } + + return ' @deprecated(reason: ' . + Printer::doPrint(AST::astFromValue($reason, Type::string())) . ')'; + } + + /** + * @param bool[] $options + */ + private static function printInterface(InterfaceType $type, array $options) : string + { + return self::printDescription($options, $type) . + sprintf("interface %s {\n%s\n}", $type->name, self::printFields($options, $type)); + } + + /** + * @param bool[] $options + */ + private static function printUnion(UnionType $type, array $options) : string + { + return self::printDescription($options, $type) . + sprintf('union %s = %s', $type->name, implode(' | ', $type->getTypes())); + } + + /** + * @param bool[] $options + */ + private static function printEnum(EnumType $type, array $options) : string + { + return self::printDescription($options, $type) . + sprintf("enum %s {\n%s\n}", $type->name, self::printEnumValues($type->getValues(), $options)); + } + + /** + * @param bool[] $options + */ + private static function printEnumValues($values, $options) : string + { + return implode( + "\n", + array_map( + static function ($value, $i) use ($options) { + return self::printDescription($options, $value, ' ', ! $i) . ' ' . + $value->name . self::printDeprecated($value); + }, + $values, + array_keys($values) + ) + ); + } + + /** + * @param bool[] $options + */ + private static function printInputObject(InputObjectType $type, array $options) : string + { + $fields = array_values($type->getFields()); + + return self::printDescription($options, $type) . + sprintf( + "input %s {\n%s\n}", + $type->name, + implode( + "\n", + array_map( + static function ($f, $i) use ($options) { + return self::printDescription($options, $f, ' ', ! $i) . ' ' . self::printInputValue($f); + }, + $fields, + array_keys($fields) + ) + ) + ); + } + + /** + * @param bool[] $options + * + * @api + */ + public static function printIntrospectionSchema(Schema $schema, array $options = []) : string + { + return self::printFilteredSchema( + $schema, + [Directive::class, 'isSpecifiedDirective'], + [Introspection::class, 'isIntrospectionType'], + $options + ); + } +} diff --git a/vendor/webonyx/graphql-php/src/Utils/TypeComparators.php b/vendor/webonyx/graphql-php/src/Utils/TypeComparators.php new file mode 100644 index 0000000..2beb942 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Utils/TypeComparators.php @@ -0,0 +1,140 @@ +getWrappedType(), $typeB->getWrappedType()); + } + + // If either type is a list, the other must also be a list. + if ($typeA instanceof ListOfType && $typeB instanceof ListOfType) { + return self::isEqualType($typeA->getWrappedType(), $typeB->getWrappedType()); + } + + // Otherwise the types are not equal. + return false; + } + + /** + * Provided a type and a super type, return true if the first type is either + * equal or a subset of the second super type (covariant). + * + * @param AbstractType $maybeSubType + * @param AbstractType $superType + * + * @return bool + */ + public static function isTypeSubTypeOf(Schema $schema, $maybeSubType, $superType) + { + // Equivalent type is a valid subtype + if ($maybeSubType === $superType) { + return true; + } + + // If superType is non-null, maybeSubType must also be nullable. + if ($superType instanceof NonNull) { + if ($maybeSubType instanceof NonNull) { + return self::isTypeSubTypeOf($schema, $maybeSubType->getWrappedType(), $superType->getWrappedType()); + } + + return false; + } + + if ($maybeSubType instanceof NonNull) { + // If superType is nullable, maybeSubType may be non-null. + return self::isTypeSubTypeOf($schema, $maybeSubType->getWrappedType(), $superType); + } + + // If superType type is a list, maybeSubType type must also be a list. + if ($superType instanceof ListOfType) { + if ($maybeSubType instanceof ListOfType) { + return self::isTypeSubTypeOf($schema, $maybeSubType->getWrappedType(), $superType->getWrappedType()); + } + + return false; + } + + if ($maybeSubType instanceof ListOfType) { + // If superType is not a list, maybeSubType must also be not a list. + return false; + } + + // If superType type is an abstract type, maybeSubType type may be a currently + // possible object type. + return Type::isAbstractType($superType) && + $maybeSubType instanceof ObjectType && + $schema->isPossibleType( + $superType, + $maybeSubType + ); + } + + /** + * Provided two composite types, determine if they "overlap". Two composite + * types overlap when the Sets of possible concrete types for each intersect. + * + * This is often used to determine if a fragment of a given type could possibly + * be visited in a context of another type. + * + * This function is commutative. + * + * @return bool + */ + public static function doTypesOverlap(Schema $schema, CompositeType $typeA, CompositeType $typeB) + { + // Equivalent types overlap + if ($typeA === $typeB) { + return true; + } + + if ($typeA instanceof AbstractType) { + if ($typeB instanceof AbstractType) { + // If both types are abstract, then determine if there is any intersection + // between possible concrete types of each. + foreach ($schema->getPossibleTypes($typeA) as $type) { + if ($schema->isPossibleType($typeB, $type)) { + return true; + } + } + + return false; + } + + // Determine if the latter type is a possible concrete type of the former. + return $schema->isPossibleType($typeA, $typeB); + } + + if ($typeB instanceof AbstractType) { + // Determine if the former type is a possible concrete type of the latter. + return $schema->isPossibleType($typeB, $typeA); + } + + // Otherwise the types do not overlap. + return false; + } +} diff --git a/vendor/webonyx/graphql-php/src/Utils/TypeInfo.php b/vendor/webonyx/graphql-php/src/Utils/TypeInfo.php new file mode 100644 index 0000000..89d4ea1 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Utils/TypeInfo.php @@ -0,0 +1,495 @@ + */ + private $typeStack; + + /** @var SplStack */ + private $parentTypeStack; + + /** @var SplStack */ + private $inputTypeStack; + + /** @var SplStack */ + private $fieldDefStack; + + /** @var Directive */ + private $directive; + + /** @var FieldArgument */ + private $argument; + + /** @var mixed */ + private $enumValue; + + /** + * @param Type|null $initialType + */ + public function __construct(Schema $schema, $initialType = null) + { + $this->schema = $schema; + $this->typeStack = []; + $this->parentTypeStack = []; + $this->inputTypeStack = []; + $this->fieldDefStack = []; + if (! $initialType) { + return; + } + + if (Type::isInputType($initialType)) { + $this->inputTypeStack[] = $initialType; + } + if (Type::isCompositeType($initialType)) { + $this->parentTypeStack[] = $initialType; + } + if (! Type::isOutputType($initialType)) { + return; + } + + $this->typeStack[] = $initialType; + } + + /** + * @deprecated moved to GraphQL\Utils\TypeComparators + */ + public static function isEqualType(Type $typeA, Type $typeB) + { + return TypeComparators::isEqualType($typeA, $typeB); + } + + /** + * @deprecated moved to GraphQL\Utils\TypeComparators + */ + public static function isTypeSubTypeOf(Schema $schema, Type $maybeSubType, Type $superType) + { + return TypeComparators::isTypeSubTypeOf($schema, $maybeSubType, $superType); + } + + /** + * @deprecated moved to GraphQL\Utils\TypeComparators + */ + public static function doTypesOverlap(Schema $schema, CompositeType $typeA, CompositeType $typeB) + { + return TypeComparators::doTypesOverlap($schema, $typeA, $typeB); + } + + /** + * Given root type scans through all fields to find nested types. Returns array where keys are for type name + * and value contains corresponding type instance. + * + * Example output: + * [ + * 'String' => $instanceOfStringType, + * 'MyType' => $instanceOfMyType, + * ... + * ] + * + * @param Type|null $type + * @param Type[]|null $typeMap + * + * @return Type[]|null + */ + public static function extractTypes($type, ?array $typeMap = null) + { + if (! $typeMap) { + $typeMap = []; + } + if (! $type) { + return $typeMap; + } + + if ($type instanceof WrappingType) { + return self::extractTypes($type->getWrappedType(true), $typeMap); + } + if (! $type instanceof Type) { + // Preserve these invalid types in map (at numeric index) to make them + // detectable during $schema->validate() + $i = 0; + $alreadyInMap = false; + while (isset($typeMap[$i])) { + $alreadyInMap = $alreadyInMap || $typeMap[$i] === $type; + $i++; + } + if (! $alreadyInMap) { + $typeMap[$i] = $type; + } + + return $typeMap; + } + + if (! empty($typeMap[$type->name])) { + Utils::invariant( + $typeMap[$type->name] === $type, + sprintf('Schema must contain unique named types but contains multiple types named "%s" ', $type) . + '(see http://webonyx.github.io/graphql-php/type-system/#type-registry).' + ); + + return $typeMap; + } + $typeMap[$type->name] = $type; + + $nestedTypes = []; + + if ($type instanceof UnionType) { + $nestedTypes = $type->getTypes(); + } + if ($type instanceof ObjectType) { + $nestedTypes = array_merge($nestedTypes, $type->getInterfaces()); + } + if ($type instanceof ObjectType || $type instanceof InterfaceType) { + foreach ($type->getFields() as $fieldName => $field) { + if (! empty($field->args)) { + $fieldArgTypes = array_map( + static function (FieldArgument $arg) { + return $arg->getType(); + }, + $field->args + ); + + $nestedTypes = array_merge($nestedTypes, $fieldArgTypes); + } + $nestedTypes[] = $field->getType(); + } + } + if ($type instanceof InputObjectType) { + foreach ($type->getFields() as $fieldName => $field) { + $nestedTypes[] = $field->getType(); + } + } + foreach ($nestedTypes as $nestedType) { + $typeMap = self::extractTypes($nestedType, $typeMap); + } + + return $typeMap; + } + + /** + * @param Type[] $typeMap + * + * @return Type[] + */ + public static function extractTypesFromDirectives(Directive $directive, array $typeMap = []) + { + if (is_array($directive->args)) { + foreach ($directive->args as $arg) { + $typeMap = self::extractTypes($arg->getType(), $typeMap); + } + } + + return $typeMap; + } + + /** + * @return InputType|null + */ + public function getParentInputType() + { + $inputTypeStackLength = count($this->inputTypeStack); + if ($inputTypeStackLength > 1) { + return $this->inputTypeStack[$inputTypeStackLength - 2]; + } + } + + /** + * @return FieldArgument|null + */ + public function getArgument() + { + return $this->argument; + } + + /** + * @return mixed + */ + public function getEnumValue() + { + return $this->enumValue; + } + + public function enter(Node $node) + { + $schema = $this->schema; + + // Note: many of the types below are explicitly typed as "mixed" to drop + // any assumptions of a valid schema to ensure runtime types are properly + // checked before continuing since TypeInfo is used as part of validation + // which occurs before guarantees of schema and document validity. + switch ($node->kind) { + case NodeKind::SELECTION_SET: + $namedType = Type::getNamedType($this->getType()); + $this->parentTypeStack[] = Type::isCompositeType($namedType) ? $namedType : null; + break; + + case NodeKind::FIELD: + $parentType = $this->getParentType(); + $fieldDef = null; + if ($parentType) { + $fieldDef = self::getFieldDefinition($schema, $parentType, $node); + } + $fieldType = null; + if ($fieldDef) { + $fieldType = $fieldDef->getType(); + } + $this->fieldDefStack[] = $fieldDef; + $this->typeStack[] = Type::isOutputType($fieldType) ? $fieldType : null; + break; + + case NodeKind::DIRECTIVE: + $this->directive = $schema->getDirective($node->name->value); + break; + + case NodeKind::OPERATION_DEFINITION: + $type = null; + if ($node->operation === 'query') { + $type = $schema->getQueryType(); + } elseif ($node->operation === 'mutation') { + $type = $schema->getMutationType(); + } elseif ($node->operation === 'subscription') { + $type = $schema->getSubscriptionType(); + } + $this->typeStack[] = Type::isOutputType($type) ? $type : null; + break; + + case NodeKind::INLINE_FRAGMENT: + case NodeKind::FRAGMENT_DEFINITION: + $typeConditionNode = $node->typeCondition; + $outputType = $typeConditionNode ? self::typeFromAST( + $schema, + $typeConditionNode + ) : Type::getNamedType($this->getType()); + $this->typeStack[] = Type::isOutputType($outputType) ? $outputType : null; + break; + + case NodeKind::VARIABLE_DEFINITION: + $inputType = self::typeFromAST($schema, $node->type); + $this->inputTypeStack[] = Type::isInputType($inputType) ? $inputType : null; // push + break; + + case NodeKind::ARGUMENT: + $fieldOrDirective = $this->getDirective() ?: $this->getFieldDef(); + $argDef = $argType = null; + if ($fieldOrDirective) { + $argDef = Utils::find( + $fieldOrDirective->args, + static function ($arg) use ($node) { + return $arg->name === $node->name->value; + } + ); + if ($argDef !== null) { + $argType = $argDef->getType(); + } + } + $this->argument = $argDef; + $this->inputTypeStack[] = Type::isInputType($argType) ? $argType : null; + break; + + case NodeKind::LST: + $listType = Type::getNullableType($this->getInputType()); + $itemType = $listType instanceof ListOfType + ? $listType->getWrappedType() + : $listType; + $this->inputTypeStack[] = Type::isInputType($itemType) ? $itemType : null; + break; + + case NodeKind::OBJECT_FIELD: + $objectType = Type::getNamedType($this->getInputType()); + $fieldType = null; + $inputFieldType = null; + if ($objectType instanceof InputObjectType) { + $tmp = $objectType->getFields(); + $inputField = $tmp[$node->name->value] ?? null; + $inputFieldType = $inputField ? $inputField->getType() : null; + } + $this->inputTypeStack[] = Type::isInputType($inputFieldType) ? $inputFieldType : null; + break; + + case NodeKind::ENUM: + $enumType = Type::getNamedType($this->getInputType()); + $enumValue = null; + if ($enumType instanceof EnumType) { + $enumValue = $enumType->getValue($node->value); + } + $this->enumValue = $enumValue; + break; + } + } + + /** + * @return Type + */ + public function getType() + { + if (! empty($this->typeStack)) { + return $this->typeStack[count($this->typeStack) - 1]; + } + + return null; + } + + /** + * @return Type + */ + public function getParentType() + { + if (! empty($this->parentTypeStack)) { + return $this->parentTypeStack[count($this->parentTypeStack) - 1]; + } + + return null; + } + + /** + * Not exactly the same as the executor's definition of getFieldDef, in this + * statically evaluated environment we do not always have an Object type, + * and need to handle Interface and Union types. + * + * @return FieldDefinition + */ + private static function getFieldDefinition(Schema $schema, Type $parentType, FieldNode $fieldNode) + { + $name = $fieldNode->name->value; + $schemaMeta = Introspection::schemaMetaFieldDef(); + if ($name === $schemaMeta->name && $schema->getQueryType() === $parentType) { + return $schemaMeta; + } + + $typeMeta = Introspection::typeMetaFieldDef(); + if ($name === $typeMeta->name && $schema->getQueryType() === $parentType) { + return $typeMeta; + } + $typeNameMeta = Introspection::typeNameMetaFieldDef(); + if ($name === $typeNameMeta->name && $parentType instanceof CompositeType) { + return $typeNameMeta; + } + if ($parentType instanceof ObjectType || + $parentType instanceof InterfaceType) { + $fields = $parentType->getFields(); + + return $fields[$name] ?? null; + } + + return null; + } + + /** + * @param NamedTypeNode|ListTypeNode|NonNullTypeNode $inputTypeNode + * + * @return Type|null + * + * @throws InvariantViolation + */ + public static function typeFromAST(Schema $schema, $inputTypeNode) + { + return AST::typeFromAST($schema, $inputTypeNode); + } + + /** + * @return Directive|null + */ + public function getDirective() + { + return $this->directive; + } + + /** + * @return FieldDefinition + */ + public function getFieldDef() + { + if (! empty($this->fieldDefStack)) { + return $this->fieldDefStack[count($this->fieldDefStack) - 1]; + } + + return null; + } + + /** + * @return InputType + */ + public function getInputType() + { + if (! empty($this->inputTypeStack)) { + return $this->inputTypeStack[count($this->inputTypeStack) - 1]; + } + + return null; + } + + public function leave(Node $node) + { + switch ($node->kind) { + case NodeKind::SELECTION_SET: + array_pop($this->parentTypeStack); + break; + + case NodeKind::FIELD: + array_pop($this->fieldDefStack); + array_pop($this->typeStack); + break; + + case NodeKind::DIRECTIVE: + $this->directive = null; + break; + + case NodeKind::OPERATION_DEFINITION: + case NodeKind::INLINE_FRAGMENT: + case NodeKind::FRAGMENT_DEFINITION: + array_pop($this->typeStack); + break; + case NodeKind::VARIABLE_DEFINITION: + array_pop($this->inputTypeStack); + break; + case NodeKind::ARGUMENT: + $this->argument = null; + array_pop($this->inputTypeStack); + break; + case NodeKind::LST: + case NodeKind::OBJECT_FIELD: + array_pop($this->inputTypeStack); + break; + case NodeKind::ENUM: + $this->enumValue = null; + break; + } + } +} diff --git a/vendor/webonyx/graphql-php/src/Utils/Utils.php b/vendor/webonyx/graphql-php/src/Utils/Utils.php new file mode 100644 index 0000000..8dddd65 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Utils/Utils.php @@ -0,0 +1,648 @@ + $value) { + if (! property_exists($obj, $key)) { + $cls = get_class($obj); + Warning::warn( + sprintf("Trying to set non-existing property '%s' on class '%s'", $key, $cls), + Warning::WARNING_ASSIGN + ); + } + $obj->{$key} = $value; + } + + return $obj; + } + + /** + * @param mixed|Traversable $traversable + * + * @return mixed|null + */ + public static function find($traversable, callable $predicate) + { + self::invariant( + is_array($traversable) || $traversable instanceof Traversable, + __METHOD__ . ' expects array or Traversable' + ); + + foreach ($traversable as $key => $value) { + if ($predicate($value, $key)) { + return $value; + } + } + + return null; + } + + /** + * @param mixed|Traversable $traversable + * + * @return mixed[] + * + * @throws Exception + */ + public static function filter($traversable, callable $predicate) + { + self::invariant( + is_array($traversable) || $traversable instanceof Traversable, + __METHOD__ . ' expects array or Traversable' + ); + + $result = []; + $assoc = false; + foreach ($traversable as $key => $value) { + if (! $assoc && ! is_int($key)) { + $assoc = true; + } + if (! $predicate($value, $key)) { + continue; + } + + $result[$key] = $value; + } + + return $assoc ? $result : array_values($result); + } + + /** + * @param mixed|Traversable $traversable + * + * @return mixed[] + * + * @throws Exception + */ + public static function map($traversable, callable $fn) + { + self::invariant( + is_array($traversable) || $traversable instanceof Traversable, + __METHOD__ . ' expects array or Traversable' + ); + + $map = []; + foreach ($traversable as $key => $value) { + $map[$key] = $fn($value, $key); + } + + return $map; + } + + /** + * @param mixed|Traversable $traversable + * + * @return mixed[] + * + * @throws Exception + */ + public static function mapKeyValue($traversable, callable $fn) + { + self::invariant( + is_array($traversable) || $traversable instanceof Traversable, + __METHOD__ . ' expects array or Traversable' + ); + + $map = []; + foreach ($traversable as $key => $value) { + [$newKey, $newValue] = $fn($value, $key); + $map[$newKey] = $newValue; + } + + return $map; + } + + /** + * @param mixed|Traversable $traversable + * + * @return mixed[] + * + * @throws Exception + */ + public static function keyMap($traversable, callable $keyFn) + { + self::invariant( + is_array($traversable) || $traversable instanceof Traversable, + __METHOD__ . ' expects array or Traversable' + ); + + $map = []; + foreach ($traversable as $key => $value) { + $newKey = $keyFn($value, $key); + if (! is_scalar($newKey)) { + continue; + } + + $map[$newKey] = $value; + } + + return $map; + } + + public static function each($traversable, callable $fn) + { + self::invariant( + is_array($traversable) || $traversable instanceof Traversable, + __METHOD__ . ' expects array or Traversable' + ); + + foreach ($traversable as $key => $item) { + $fn($item, $key); + } + } + + /** + * Splits original traversable to several arrays with keys equal to $keyFn return + * + * E.g. Utils::groupBy([1, 2, 3, 4, 5], function($value) {return $value % 3}) will output: + * [ + * 1 => [1, 4], + * 2 => [2, 5], + * 0 => [3], + * ] + * + * $keyFn is also allowed to return array of keys. Then value will be added to all arrays with given keys + * + * @param mixed[]|Traversable $traversable + * + * @return mixed[] + */ + public static function groupBy($traversable, callable $keyFn) + { + self::invariant( + is_array($traversable) || $traversable instanceof Traversable, + __METHOD__ . ' expects array or Traversable' + ); + + $grouped = []; + foreach ($traversable as $key => $value) { + $newKeys = (array) $keyFn($value, $key); + foreach ($newKeys as $newKey) { + $grouped[$newKey][] = $value; + } + } + + return $grouped; + } + + /** + * @param mixed[]|Traversable $traversable + * + * @return mixed[][] + */ + public static function keyValMap($traversable, callable $keyFn, callable $valFn) + { + $map = []; + foreach ($traversable as $item) { + $map[$keyFn($item)] = $valFn($item); + } + + return $map; + } + + /** + * @param mixed[] $traversable + * + * @return bool + */ + public static function every($traversable, callable $predicate) + { + foreach ($traversable as $key => $value) { + if (! $predicate($value, $key)) { + return false; + } + } + + return true; + } + + /** + * @param bool $test + * @param string $message + */ + public static function invariant($test, $message = '') + { + if (! $test) { + if (func_num_args() > 2) { + $args = func_get_args(); + array_shift($args); + $message = sprintf(...$args); + } + // TODO switch to Error here + throw new InvariantViolation($message); + } + } + + /** + * @param Type|mixed $var + * + * @return string + */ + public static function getVariableType($var) + { + if ($var instanceof Type) { + // FIXME: Replace with schema printer call + if ($var instanceof WrappingType) { + $var = $var->getWrappedType(true); + } + + return $var->name; + } + + return is_object($var) ? get_class($var) : gettype($var); + } + + /** + * @param mixed $var + * + * @return string + */ + public static function printSafeJson($var) + { + if ($var instanceof stdClass) { + $var = (array) $var; + } + if (is_array($var)) { + return json_encode($var); + } + if ($var === '') { + return '(empty string)'; + } + if ($var === null) { + return 'null'; + } + if ($var === false) { + return 'false'; + } + if ($var === true) { + return 'true'; + } + if (is_string($var)) { + return sprintf('"%s"', $var); + } + if (is_scalar($var)) { + return (string) $var; + } + + return gettype($var); + } + + /** + * @param Type|mixed $var + * + * @return string + */ + public static function printSafe($var) + { + if ($var instanceof Type) { + return $var->toString(); + } + if (is_object($var)) { + if (method_exists($var, '__toString')) { + return (string) $var; + } + + return 'instance of ' . get_class($var); + } + if (is_array($var)) { + return json_encode($var); + } + if ($var === '') { + return '(empty string)'; + } + if ($var === null) { + return 'null'; + } + if ($var === false) { + return 'false'; + } + if ($var === true) { + return 'true'; + } + if (is_string($var)) { + return $var; + } + if (is_scalar($var)) { + return (string) $var; + } + + return gettype($var); + } + + /** + * UTF-8 compatible chr() + * + * @param string $ord + * @param string $encoding + * + * @return string + */ + public static function chr($ord, $encoding = 'UTF-8') + { + if ($ord <= 255) { + return chr($ord); + } + if ($encoding === 'UCS-4BE') { + return pack('N', $ord); + } + + return mb_convert_encoding(self::chr($ord, 'UCS-4BE'), $encoding, 'UCS-4BE'); + } + + /** + * UTF-8 compatible ord() + * + * @param string $char + * @param string $encoding + * + * @return mixed + */ + public static function ord($char, $encoding = 'UTF-8') + { + if (! $char && $char !== '0') { + return 0; + } + if (! isset($char[1])) { + return ord($char); + } + if ($encoding !== 'UCS-4BE') { + $char = mb_convert_encoding($char, 'UCS-4BE', $encoding); + } + + return unpack('N', $char)[1]; + } + + /** + * Returns UTF-8 char code at given $positing of the $string + * + * @param string $string + * @param int $position + * + * @return mixed + */ + public static function charCodeAt($string, $position) + { + $char = mb_substr($string, $position, 1, 'UTF-8'); + + return self::ord($char); + } + + /** + * @param int|null $code + * + * @return string + */ + public static function printCharCode($code) + { + if ($code === null) { + return ''; + } + + return $code < 0x007F + // Trust JSON for ASCII. + ? json_encode(self::chr($code)) + // Otherwise print the escaped form. + : '"\\u' . dechex($code) . '"'; + } + + /** + * Upholds the spec rules about naming. + * + * @param string $name + * + * @throws Error + */ + public static function assertValidName($name) + { + $error = self::isValidNameError($name); + if ($error) { + throw $error; + } + } + + /** + * Returns an Error if a name is invalid. + * + * @param string $name + * @param Node|null $node + * + * @return Error|null + */ + public static function isValidNameError($name, $node = null) + { + self::invariant(is_string($name), 'Expected string'); + + if (isset($name[1]) && $name[0] === '_' && $name[1] === '_') { + return new Error( + sprintf('Name "%s" must not begin with "__", which is reserved by ', $name) . + 'GraphQL introspection.', + $node + ); + } + + if (! preg_match('/^[_a-zA-Z][_a-zA-Z0-9]*$/', $name)) { + return new Error( + sprintf('Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but "%s" does not.', $name), + $node + ); + } + + return null; + } + + /** + * Wraps original callable with PHP error handling (using set_error_handler). + * Resulting callable will collect all PHP errors that occur during the call in $errors array. + * + * @param ErrorException[] $errors + * + * @return callable + */ + public static function withErrorHandling(callable $fn, array &$errors) + { + return static function () use ($fn, &$errors) { + // Catch custom errors (to report them in query results) + set_error_handler(static function ($severity, $message, $file, $line) use (&$errors) { + $errors[] = new ErrorException($message, 0, $severity, $file, $line); + }); + + try { + return $fn(); + } finally { + restore_error_handler(); + } + }; + } + + /** + * @param string[] $items + * + * @return string + */ + public static function quotedOrList(array $items) + { + $items = array_map( + static function ($item) { + return sprintf('"%s"', $item); + }, + $items + ); + + return self::orList($items); + } + + /** + * @param string[] $items + * + * @return string + */ + public static function orList(array $items) + { + if (count($items) === 0) { + throw new LogicException('items must not need to be empty.'); + } + $selected = array_slice($items, 0, 5); + $selectedLength = count($selected); + $firstSelected = $selected[0]; + + if ($selectedLength === 1) { + return $firstSelected; + } + + return array_reduce( + range(1, $selectedLength - 1), + static function ($list, $index) use ($selected, $selectedLength) { + return $list . + ($selectedLength > 2 ? ', ' : ' ') . + ($index === $selectedLength - 1 ? 'or ' : '') . + $selected[$index]; + }, + $firstSelected + ); + } + + /** + * Given an invalid input string and a list of valid options, returns a filtered + * list of valid options sorted based on their similarity with the input. + * + * Includes a custom alteration from Damerau-Levenshtein to treat case changes + * as a single edit which helps identify mis-cased values with an edit distance + * of 1 + * + * @param string $input + * @param string[] $options + * + * @return string[] + */ + public static function suggestionList($input, array $options) + { + $optionsByDistance = []; + $inputThreshold = mb_strlen($input) / 2; + foreach ($options as $option) { + if ($input === $option) { + $distance = 0; + } else { + $distance = (strtolower($input) === strtolower($option) + ? 1 + : levenshtein($input, $option)); + } + $threshold = max($inputThreshold, mb_strlen($option) / 2, 1); + if ($distance > $threshold) { + continue; + } + + $optionsByDistance[$option] = $distance; + } + + asort($optionsByDistance); + + return array_keys($optionsByDistance); + } +} diff --git a/vendor/webonyx/graphql-php/src/Utils/Value.php b/vendor/webonyx/graphql-php/src/Utils/Value.php new file mode 100644 index 0000000..a3f8805 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Utils/Value.php @@ -0,0 +1,320 @@ +getWrappedType(), $blameNode, $path); + } + + if ($value === null) { + // Explicitly return the value null. + return self::ofValue(null); + } + + if ($type instanceof ScalarType) { + // Scalars determine if a value is valid via parseValue(), which can + // throw to indicate failure. If it throws, maintain a reference to + // the original error. + try { + return self::ofValue($type->parseValue($value)); + } catch (Exception $error) { + return self::ofErrors([ + self::coercionError( + sprintf('Expected type %s', $type->name), + $blameNode, + $path, + $error->getMessage(), + $error + ), + ]); + } catch (Throwable $error) { + return self::ofErrors([ + self::coercionError( + sprintf('Expected type %s', $type->name), + $blameNode, + $path, + $error->getMessage(), + $error + ), + ]); + } + } + + if ($type instanceof EnumType) { + if (is_string($value)) { + $enumValue = $type->getValue($value); + if ($enumValue) { + return self::ofValue($enumValue->value); + } + } + + $suggestions = Utils::suggestionList( + Utils::printSafe($value), + array_map( + static function ($enumValue) { + return $enumValue->name; + }, + $type->getValues() + ) + ); + + $didYouMean = $suggestions + ? 'did you mean ' . Utils::orList($suggestions) . '?' + : null; + + return self::ofErrors([ + self::coercionError( + sprintf('Expected type %s', $type->name), + $blameNode, + $path, + $didYouMean + ), + ]); + } + + if ($type instanceof ListOfType) { + $itemType = $type->getWrappedType(); + if (is_array($value) || $value instanceof Traversable) { + $errors = []; + $coercedValue = []; + foreach ($value as $index => $itemValue) { + $coercedItem = self::coerceValue( + $itemValue, + $itemType, + $blameNode, + self::atPath($path, $index) + ); + if ($coercedItem['errors']) { + $errors = self::add($errors, $coercedItem['errors']); + } else { + $coercedValue[] = $coercedItem['value']; + } + } + + return $errors ? self::ofErrors($errors) : self::ofValue($coercedValue); + } + // Lists accept a non-list value as a list of one. + $coercedItem = self::coerceValue($value, $itemType, $blameNode); + + return $coercedItem['errors'] ? $coercedItem : self::ofValue([$coercedItem['value']]); + } + + if ($type instanceof InputObjectType) { + if (! is_object($value) && ! is_array($value) && ! $value instanceof Traversable) { + return self::ofErrors([ + self::coercionError( + sprintf('Expected type %s to be an object', $type->name), + $blameNode, + $path + ), + ]); + } + + // Cast \stdClass to associative array before checking the fields. Note that the coerced value will be an array. + if ($value instanceof stdClass) { + $value = (array) $value; + } + + $errors = []; + $coercedValue = []; + $fields = $type->getFields(); + foreach ($fields as $fieldName => $field) { + if (array_key_exists($fieldName, $value)) { + $fieldValue = $value[$fieldName]; + $coercedField = self::coerceValue( + $fieldValue, + $field->getType(), + $blameNode, + self::atPath($path, $fieldName) + ); + if ($coercedField['errors']) { + $errors = self::add($errors, $coercedField['errors']); + } else { + $coercedValue[$fieldName] = $coercedField['value']; + } + } elseif ($field->defaultValueExists()) { + $coercedValue[$fieldName] = $field->defaultValue; + } elseif ($field->getType() instanceof NonNull) { + $fieldPath = self::printPath(self::atPath($path, $fieldName)); + $errors = self::add( + $errors, + self::coercionError( + sprintf( + 'Field %s of required type %s was not provided', + $fieldPath, + $field->type->toString() + ), + $blameNode + ) + ); + } + } + + // Ensure every provided field is defined. + foreach ($value as $fieldName => $field) { + if (array_key_exists($fieldName, $fields)) { + continue; + } + + $suggestions = Utils::suggestionList( + (string) $fieldName, + array_keys($fields) + ); + $didYouMean = $suggestions + ? 'did you mean ' . Utils::orList($suggestions) . '?' + : null; + $errors = self::add( + $errors, + self::coercionError( + sprintf('Field "%s" is not defined by type %s', $fieldName, $type->name), + $blameNode, + $path, + $didYouMean + ) + ); + } + + return $errors ? self::ofErrors($errors) : self::ofValue($coercedValue); + } + + throw new Error(sprintf('Unexpected type %s', $type->name)); + } + + private static function ofErrors($errors) + { + return ['errors' => $errors, 'value' => Utils::undefined()]; + } + + /** + * @param string $message + * @param Node $blameNode + * @param mixed[]|null $path + * @param string $subMessage + * @param Exception|Throwable|null $originalError + * + * @return Error + */ + private static function coercionError( + $message, + $blameNode, + ?array $path = null, + $subMessage = null, + $originalError = null + ) { + $pathStr = self::printPath($path); + + // Return a GraphQLError instance + return new Error( + $message . + ($pathStr ? ' at ' . $pathStr : '') . + ($subMessage ? '; ' . $subMessage : '.'), + $blameNode, + null, + null, + null, + $originalError + ); + } + + /** + * Build a string describing the path into the value where the error was found + * + * @param mixed[]|null $path + * + * @return string + */ + private static function printPath(?array $path = null) + { + $pathStr = ''; + $currentPath = $path; + while ($currentPath) { + $pathStr = + (is_string($currentPath['key']) + ? '.' . $currentPath['key'] + : '[' . $currentPath['key'] . ']') . $pathStr; + $currentPath = $currentPath['prev']; + } + + return $pathStr ? 'value' . $pathStr : ''; + } + + /** + * @param mixed $value + * + * @return (mixed|null)[] + */ + private static function ofValue($value) + { + return ['errors' => null, 'value' => $value]; + } + + /** + * @param mixed|null $prev + * @param mixed|null $key + * + * @return (mixed|null)[] + */ + private static function atPath($prev, $key) + { + return ['prev' => $prev, 'key' => $key]; + } + + /** + * @param Error[] $errors + * @param Error|Error[] $moreErrors + * + * @return Error[] + */ + private static function add($errors, $moreErrors) + { + return array_merge($errors, is_array($moreErrors) ? $moreErrors : [$moreErrors]); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/DocumentValidator.php b/vendor/webonyx/graphql-php/src/Validator/DocumentValidator.php new file mode 100644 index 0000000..0364839 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/DocumentValidator.php @@ -0,0 +1,326 @@ + new ExecutableDefinitions(), + UniqueOperationNames::class => new UniqueOperationNames(), + LoneAnonymousOperation::class => new LoneAnonymousOperation(), + KnownTypeNames::class => new KnownTypeNames(), + FragmentsOnCompositeTypes::class => new FragmentsOnCompositeTypes(), + VariablesAreInputTypes::class => new VariablesAreInputTypes(), + ScalarLeafs::class => new ScalarLeafs(), + FieldsOnCorrectType::class => new FieldsOnCorrectType(), + UniqueFragmentNames::class => new UniqueFragmentNames(), + KnownFragmentNames::class => new KnownFragmentNames(), + NoUnusedFragments::class => new NoUnusedFragments(), + PossibleFragmentSpreads::class => new PossibleFragmentSpreads(), + NoFragmentCycles::class => new NoFragmentCycles(), + UniqueVariableNames::class => new UniqueVariableNames(), + NoUndefinedVariables::class => new NoUndefinedVariables(), + NoUnusedVariables::class => new NoUnusedVariables(), + KnownDirectives::class => new KnownDirectives(), + UniqueDirectivesPerLocation::class => new UniqueDirectivesPerLocation(), + KnownArgumentNames::class => new KnownArgumentNames(), + UniqueArgumentNames::class => new UniqueArgumentNames(), + ValuesOfCorrectType::class => new ValuesOfCorrectType(), + ProvidedNonNullArguments::class => new ProvidedNonNullArguments(), + VariablesDefaultValueAllowed::class => new VariablesDefaultValueAllowed(), + VariablesInAllowedPosition::class => new VariablesInAllowedPosition(), + OverlappingFieldsCanBeMerged::class => new OverlappingFieldsCanBeMerged(), + UniqueInputFieldNames::class => new UniqueInputFieldNames(), + ]; + } + + return self::$defaultRules; + } + + /** + * @return QuerySecurityRule[] + */ + public static function securityRules() + { + // This way of defining rules is deprecated + // When custom security rule is required - it should be just added via DocumentValidator::addRule(); + // TODO: deprecate this + + if (self::$securityRules === null) { + self::$securityRules = [ + DisableIntrospection::class => new DisableIntrospection(DisableIntrospection::DISABLED), // DEFAULT DISABLED + QueryDepth::class => new QueryDepth(QueryDepth::DISABLED), // default disabled + QueryComplexity::class => new QueryComplexity(QueryComplexity::DISABLED), // default disabled + ]; + } + + return self::$securityRules; + } + + public static function sdlRules() + { + if (self::$sdlRules === null) { + self::$sdlRules = [ + LoneSchemaDefinition::class => new LoneSchemaDefinition(), + KnownDirectives::class => new KnownDirectives(), + KnownArgumentNamesOnDirectives::class => new KnownArgumentNamesOnDirectives(), + UniqueDirectivesPerLocation::class => new UniqueDirectivesPerLocation(), + UniqueArgumentNames::class => new UniqueArgumentNames(), + UniqueInputFieldNames::class => new UniqueInputFieldNames(), + ProvidedRequiredArgumentsOnDirectives::class => new ProvidedRequiredArgumentsOnDirectives(), + ]; + } + + return self::$sdlRules; + } + + /** + * This uses a specialized visitor which runs multiple visitors in parallel, + * while maintaining the visitor skip and break API. + * + * @param ValidationRule[] $rules + * + * @return Error[] + */ + public static function visitUsingRules(Schema $schema, TypeInfo $typeInfo, DocumentNode $documentNode, array $rules) + { + $context = new ValidationContext($schema, $documentNode, $typeInfo); + $visitors = []; + foreach ($rules as $rule) { + $visitors[] = $rule->getVisitor($context); + } + Visitor::visit($documentNode, Visitor::visitWithTypeInfo($typeInfo, Visitor::visitInParallel($visitors))); + + return $context->getErrors(); + } + + /** + * Returns global validation rule by name. Standard rules are named by class name, so + * example usage for such rules: + * + * $rule = DocumentValidator::getRule(GraphQL\Validator\Rules\QueryComplexity::class); + * + * @param string $name + * + * @return ValidationRule + * + * @api + */ + public static function getRule($name) + { + $rules = static::allRules(); + + if (isset($rules[$name])) { + return $rules[$name]; + } + + $name = sprintf('GraphQL\\Validator\\Rules\\%s', $name); + + return $rules[$name] ?? null; + } + + /** + * Add rule to list of global validation rules + * + * @api + */ + public static function addRule(ValidationRule $rule) + { + self::$rules[$rule->getName()] = $rule; + } + + public static function isError($value) + { + return is_array($value) + ? count(array_filter( + $value, + static function ($item) { + return $item instanceof Exception || $item instanceof Throwable; + } + )) === count($value) + : ($value instanceof Exception || $value instanceof Throwable); + } + + public static function append(&$arr, $items) + { + if (is_array($items)) { + $arr = array_merge($arr, $items); + } else { + $arr[] = $items; + } + + return $arr; + } + + /** + * Utility which determines if a value literal node is valid for an input type. + * + * Deprecated. Rely on validation for documents co + * ntaining literal values. + * + * @deprecated + * + * @return Error[] + */ + public static function isValidLiteralValue(Type $type, $valueNode) + { + $emptySchema = new Schema([]); + $emptyDoc = new DocumentNode(['definitions' => []]); + $typeInfo = new TypeInfo($emptySchema, $type); + $context = new ValidationContext($emptySchema, $emptyDoc, $typeInfo); + $validator = new ValuesOfCorrectType(); + $visitor = $validator->getVisitor($context); + Visitor::visit($valueNode, Visitor::visitWithTypeInfo($typeInfo, $visitor)); + + return $context->getErrors(); + } + + public static function assertValidSDLExtension(DocumentNode $documentAST, Schema $schema) + { + $errors = self::visitUsingRules($schema, new TypeInfo($schema), $documentAST, self::sdlRules()); + if (count($errors) !== 0) { + throw new Error( + implode( + "\n\n", + array_map(static function (Error $error) : string { + return $error->message; + }, $errors) + ) + ); + } + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/CustomValidationRule.php b/vendor/webonyx/graphql-php/src/Validator/Rules/CustomValidationRule.php new file mode 100644 index 0000000..83101a1 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/CustomValidationRule.php @@ -0,0 +1,30 @@ +name = $name; + $this->visitorFn = $visitorFn; + } + + /** + * @return Error[] + */ + public function getVisitor(ValidationContext $context) + { + $fn = $this->visitorFn; + + return $fn($context); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/DisableIntrospection.php b/vendor/webonyx/graphql-php/src/Validator/Rules/DisableIntrospection.php new file mode 100644 index 0000000..6e0efab --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/DisableIntrospection.php @@ -0,0 +1,57 @@ +setEnabled($enabled); + } + + public function setEnabled($enabled) + { + $this->isEnabled = $enabled; + } + + public function getVisitor(ValidationContext $context) + { + return $this->invokeIfNeeded( + $context, + [ + NodeKind::FIELD => static function (FieldNode $node) use ($context) { + if ($node->name->value !== '__type' && $node->name->value !== '__schema') { + return; + } + + $context->reportError(new Error( + static::introspectionDisabledMessage(), + [$node] + )); + }, + ] + ); + } + + public static function introspectionDisabledMessage() + { + return 'GraphQL introspection is not allowed, but the query contained __schema or __type'; + } + + protected function isEnabled() + { + return $this->isEnabled !== self::DISABLED; + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/ExecutableDefinitions.php b/vendor/webonyx/graphql-php/src/Validator/Rules/ExecutableDefinitions.php new file mode 100644 index 0000000..e626861 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/ExecutableDefinitions.php @@ -0,0 +1,52 @@ + static function (DocumentNode $node) use ($context) { + /** @var Node $definition */ + foreach ($node->definitions as $definition) { + if ($definition instanceof OperationDefinitionNode || + $definition instanceof FragmentDefinitionNode + ) { + continue; + } + + $context->reportError(new Error( + self::nonExecutableDefinitionMessage($definition->name->value), + [$definition->name] + )); + } + + return Visitor::skipNode(); + }, + ]; + } + + public static function nonExecutableDefinitionMessage($defName) + { + return sprintf('The "%s" definition is not executable.', $defName); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/FieldsOnCorrectType.php b/vendor/webonyx/graphql-php/src/Validator/Rules/FieldsOnCorrectType.php new file mode 100644 index 0000000..1053255 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/FieldsOnCorrectType.php @@ -0,0 +1,167 @@ + function (FieldNode $node) use ($context) { + $type = $context->getParentType(); + if (! $type) { + return; + } + + $fieldDef = $context->getFieldDef(); + if ($fieldDef) { + return; + } + + // This isn't valid. Let's find suggestions, if any. + $schema = $context->getSchema(); + $fieldName = $node->name->value; + // First determine if there are any suggested types to condition on. + $suggestedTypeNames = $this->getSuggestedTypeNames( + $schema, + $type, + $fieldName + ); + // If there are no suggested types, then perhaps this was a typo? + $suggestedFieldNames = $suggestedTypeNames + ? [] + : $this->getSuggestedFieldNames( + $schema, + $type, + $fieldName + ); + + // Report an error, including helpful suggestions. + $context->reportError(new Error( + static::undefinedFieldMessage( + $node->name->value, + $type->name, + $suggestedTypeNames, + $suggestedFieldNames + ), + [$node] + )); + }, + ]; + } + + /** + * Go through all of the implementations of type, as well as the interfaces + * that they implement. If any of those types include the provided field, + * suggest them, sorted by how often the type is referenced, starting + * with Interfaces. + * + * @param ObjectType|InterfaceType $type + * @param string $fieldName + * + * @return string[] + */ + private function getSuggestedTypeNames(Schema $schema, $type, $fieldName) + { + if (Type::isAbstractType($type)) { + $suggestedObjectTypes = []; + $interfaceUsageCount = []; + + foreach ($schema->getPossibleTypes($type) as $possibleType) { + $fields = $possibleType->getFields(); + if (! isset($fields[$fieldName])) { + continue; + } + // This object type defines this field. + $suggestedObjectTypes[] = $possibleType->name; + foreach ($possibleType->getInterfaces() as $possibleInterface) { + $fields = $possibleInterface->getFields(); + if (! isset($fields[$fieldName])) { + continue; + } + // This interface type defines this field. + $interfaceUsageCount[$possibleInterface->name] = + ! isset($interfaceUsageCount[$possibleInterface->name]) + ? 0 + : $interfaceUsageCount[$possibleInterface->name] + 1; + } + } + + // Suggest interface types based on how common they are. + arsort($interfaceUsageCount); + $suggestedInterfaceTypes = array_keys($interfaceUsageCount); + + // Suggest both interface and object types. + return array_merge($suggestedInterfaceTypes, $suggestedObjectTypes); + } + + // Otherwise, must be an Object type, which does not have possible fields. + return []; + } + + /** + * For the field name provided, determine if there are any similar field names + * that may be the result of a typo. + * + * @param ObjectType|InterfaceType $type + * @param string $fieldName + * + * @return array|string[] + */ + private function getSuggestedFieldNames(Schema $schema, $type, $fieldName) + { + if ($type instanceof ObjectType || $type instanceof InterfaceType) { + $possibleFieldNames = array_keys($type->getFields()); + + return Utils::suggestionList($fieldName, $possibleFieldNames); + } + + // Otherwise, must be a Union type, which does not define fields. + return []; + } + + /** + * @param string $fieldName + * @param string $type + * @param string[] $suggestedTypeNames + * @param string[] $suggestedFieldNames + * + * @return string + */ + public static function undefinedFieldMessage( + $fieldName, + $type, + array $suggestedTypeNames, + array $suggestedFieldNames + ) { + $message = sprintf('Cannot query field "%s" on type "%s".', $fieldName, $type); + + if ($suggestedTypeNames) { + $suggestions = Utils::quotedOrList($suggestedTypeNames); + + $message .= sprintf(' Did you mean to use an inline fragment on %s?', $suggestions); + } elseif (! empty($suggestedFieldNames)) { + $suggestions = Utils::quotedOrList($suggestedFieldNames); + + $message .= sprintf(' Did you mean %s?', $suggestions); + } + + return $message; + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/FragmentsOnCompositeTypes.php b/vendor/webonyx/graphql-php/src/Validator/Rules/FragmentsOnCompositeTypes.php new file mode 100644 index 0000000..c5ca807 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/FragmentsOnCompositeTypes.php @@ -0,0 +1,64 @@ + static function (InlineFragmentNode $node) use ($context) { + if (! $node->typeCondition) { + return; + } + + $type = TypeInfo::typeFromAST($context->getSchema(), $node->typeCondition); + if (! $type || Type::isCompositeType($type)) { + return; + } + + $context->reportError(new Error( + static::inlineFragmentOnNonCompositeErrorMessage($type), + [$node->typeCondition] + )); + }, + NodeKind::FRAGMENT_DEFINITION => static function (FragmentDefinitionNode $node) use ($context) { + $type = TypeInfo::typeFromAST($context->getSchema(), $node->typeCondition); + + if (! $type || Type::isCompositeType($type)) { + return; + } + + $context->reportError(new Error( + static::fragmentOnNonCompositeErrorMessage( + $node->name->value, + Printer::doPrint($node->typeCondition) + ), + [$node->typeCondition] + )); + }, + ]; + } + + public static function inlineFragmentOnNonCompositeErrorMessage($type) + { + return sprintf('Fragment cannot condition on non composite type "%s".', $type); + } + + public static function fragmentOnNonCompositeErrorMessage($fragName, $type) + { + return sprintf('Fragment "%s" cannot condition on non composite type "%s".', $fragName, $type); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/KnownArgumentNames.php b/vendor/webonyx/graphql-php/src/Validator/Rules/KnownArgumentNames.php new file mode 100644 index 0000000..96fd800 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/KnownArgumentNames.php @@ -0,0 +1,109 @@ + static function (ArgumentNode $node, $key, $parent, $path, $ancestors) use ($context) { + /** @var NodeList|Node[] $ancestors */ + $argDef = $context->getArgument(); + if ($argDef !== null) { + return; + } + + $argumentOf = $ancestors[count($ancestors) - 1]; + if ($argumentOf->kind === NodeKind::FIELD) { + $fieldDef = $context->getFieldDef(); + $parentType = $context->getParentType(); + if ($fieldDef && $parentType) { + $context->reportError(new Error( + self::unknownArgMessage( + $node->name->value, + $fieldDef->name, + $parentType->name, + Utils::suggestionList( + $node->name->value, + array_map( + static function ($arg) { + return $arg->name; + }, + $fieldDef->args + ) + ) + ), + [$node] + )); + } + } elseif ($argumentOf->kind === NodeKind::DIRECTIVE) { + $directive = $context->getDirective(); + if ($directive) { + $context->reportError(new Error( + self::unknownDirectiveArgMessage( + $node->name->value, + $directive->name, + Utils::suggestionList( + $node->name->value, + array_map( + static function ($arg) { + return $arg->name; + }, + $directive->args + ) + ) + ), + [$node] + )); + } + } + }, + ]; + } + + /** + * @param string[] $suggestedArgs + */ + public static function unknownArgMessage($argName, $fieldName, $typeName, array $suggestedArgs) + { + $message = sprintf('Unknown argument "%s" on field "%s" of type "%s".', $argName, $fieldName, $typeName); + if (! empty($suggestedArgs)) { + $message .= sprintf(' Did you mean %s?', Utils::quotedOrList($suggestedArgs)); + } + + return $message; + } + + /** + * @param string[] $suggestedArgs + */ + public static function unknownDirectiveArgMessage($argName, $directiveName, array $suggestedArgs) + { + $message = sprintf('Unknown argument "%s" on directive "@%s".', $argName, $directiveName); + if (! empty($suggestedArgs)) { + $message .= sprintf(' Did you mean %s?', Utils::quotedOrList($suggestedArgs)); + } + + return $message; + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/KnownArgumentNamesOnDirectives.php b/vendor/webonyx/graphql-php/src/Validator/Rules/KnownArgumentNamesOnDirectives.php new file mode 100644 index 0000000..a013820 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/KnownArgumentNamesOnDirectives.php @@ -0,0 +1,93 @@ +getSchema(); + $definedDirectives = $schema !== null ? $schema->getDirectives() : Directive::getInternalDirectives(); + + foreach ($definedDirectives as $directive) { + $directiveArgs[$directive->name] = array_map( + static function (FieldArgument $arg) : string { + return $arg->name; + }, + $directive->args + ); + } + + $astDefinitions = $context->getDocument()->definitions; + foreach ($astDefinitions as $def) { + if (! ($def instanceof DirectiveDefinitionNode)) { + continue; + } + + $name = $def->name->value; + if ($def->arguments !== null) { + $arguments = $def->arguments; + + if ($arguments instanceof NodeList) { + $arguments = iterator_to_array($arguments->getIterator()); + } + + $directiveArgs[$name] = array_map(static function (InputValueDefinitionNode $arg) : string { + return $arg->name->value; + }, $arguments); + } else { + $directiveArgs[$name] = []; + } + } + + return [ + NodeKind::DIRECTIVE => static function (DirectiveNode $directiveNode) use ($directiveArgs, $context) { + $directiveName = $directiveNode->name->value; + $knownArgs = $directiveArgs[$directiveName] ?? null; + + if ($directiveNode->arguments === null || ! $knownArgs) { + return; + } + + foreach ($directiveNode->arguments as $argNode) { + $argName = $argNode->name->value; + if (in_array($argName, $knownArgs, true)) { + continue; + } + + $context->reportError(new Error( + self::unknownDirectiveArgMessage($argName, $directiveName), + [$argNode] + )); + } + }, + ]; + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/KnownDirectives.php b/vendor/webonyx/graphql-php/src/Validator/Rules/KnownDirectives.php new file mode 100644 index 0000000..927ce26 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/KnownDirectives.php @@ -0,0 +1,156 @@ +getSchema(); + $definedDirectives = $schema->getDirectives(); + + foreach ($definedDirectives as $directive) { + $locationsMap[$directive->name] = $directive->locations; + } + + $astDefinition = $context->getDocument()->definitions; + + foreach ($astDefinition as $def) { + if (! ($def instanceof DirectiveDefinitionNode)) { + continue; + } + + $locationsMap[$def->name->value] = array_map( + static function ($name) { + return $name->value; + }, + $def->locations + ); + } + + return [ + NodeKind::DIRECTIVE => function ( + DirectiveNode $node, + $key, + $parent, + $path, + $ancestors + ) use ( + $context, + $locationsMap + ) { + $name = $node->name->value; + $locations = $locationsMap[$name] ?? null; + + if (! $locations) { + $context->reportError(new Error( + self::unknownDirectiveMessage($name), + [$node] + )); + + return; + } + + $candidateLocation = $this->getDirectiveLocationForASTPath($ancestors); + + if (! $candidateLocation || in_array($candidateLocation, $locations, true)) { + return; + } + $context->reportError( + new Error( + self::misplacedDirectiveMessage($name, $candidateLocation), + [$node] + ) + ); + }, + ]; + } + + public static function unknownDirectiveMessage($directiveName) + { + return sprintf('Unknown directive "%s".', $directiveName); + } + + /** + * @param Node[]|NodeList[] $ancestors The type is actually (Node|NodeList)[] but this PSR-5 syntax is so far not supported by most of the tools + * + * @return string + */ + private function getDirectiveLocationForASTPath(array $ancestors) + { + $appliedTo = $ancestors[count($ancestors) - 1]; + switch ($appliedTo->kind) { + case NodeKind::OPERATION_DEFINITION: + switch ($appliedTo->operation) { + case 'query': + return DirectiveLocation::QUERY; + case 'mutation': + return DirectiveLocation::MUTATION; + case 'subscription': + return DirectiveLocation::SUBSCRIPTION; + } + break; + case NodeKind::FIELD: + return DirectiveLocation::FIELD; + case NodeKind::FRAGMENT_SPREAD: + return DirectiveLocation::FRAGMENT_SPREAD; + case NodeKind::INLINE_FRAGMENT: + return DirectiveLocation::INLINE_FRAGMENT; + case NodeKind::FRAGMENT_DEFINITION: + return DirectiveLocation::FRAGMENT_DEFINITION; + case NodeKind::SCHEMA_DEFINITION: + case NodeKind::SCHEMA_EXTENSION: + return DirectiveLocation::SCHEMA; + case NodeKind::SCALAR_TYPE_DEFINITION: + case NodeKind::SCALAR_TYPE_EXTENSION: + return DirectiveLocation::SCALAR; + case NodeKind::OBJECT_TYPE_DEFINITION: + case NodeKind::OBJECT_TYPE_EXTENSION: + return DirectiveLocation::OBJECT; + case NodeKind::FIELD_DEFINITION: + return DirectiveLocation::FIELD_DEFINITION; + case NodeKind::INTERFACE_TYPE_DEFINITION: + case NodeKind::INTERFACE_TYPE_EXTENSION: + return DirectiveLocation::IFACE; + case NodeKind::UNION_TYPE_DEFINITION: + case NodeKind::UNION_TYPE_EXTENSION: + return DirectiveLocation::UNION; + case NodeKind::ENUM_TYPE_DEFINITION: + case NodeKind::ENUM_TYPE_EXTENSION: + return DirectiveLocation::ENUM; + case NodeKind::ENUM_VALUE_DEFINITION: + return DirectiveLocation::ENUM_VALUE; + case NodeKind::INPUT_OBJECT_TYPE_DEFINITION: + case NodeKind::INPUT_OBJECT_TYPE_EXTENSION: + return DirectiveLocation::INPUT_OBJECT; + case NodeKind::INPUT_VALUE_DEFINITION: + $parentNode = $ancestors[count($ancestors) - 3]; + + return $parentNode instanceof InputObjectTypeDefinitionNode + ? DirectiveLocation::INPUT_FIELD_DEFINITION + : DirectiveLocation::ARGUMENT_DEFINITION; + } + } + + public static function misplacedDirectiveMessage($directiveName, $location) + { + return sprintf('Directive "%s" may not be used on "%s".', $directiveName, $location); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/KnownFragmentNames.php b/vendor/webonyx/graphql-php/src/Validator/Rules/KnownFragmentNames.php new file mode 100644 index 0000000..e26e233 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/KnownFragmentNames.php @@ -0,0 +1,40 @@ + static function (FragmentSpreadNode $node) use ($context) { + $fragmentName = $node->name->value; + $fragment = $context->getFragment($fragmentName); + if ($fragment) { + return; + } + + $context->reportError(new Error( + self::unknownFragmentMessage($fragmentName), + [$node->name] + )); + }, + ]; + } + + /** + * @param string $fragName + */ + public static function unknownFragmentMessage($fragName) + { + return sprintf('Unknown fragment "%s".', $fragName); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/KnownTypeNames.php b/vendor/webonyx/graphql-php/src/Validator/Rules/KnownTypeNames.php new file mode 100644 index 0000000..9abaf0a --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/KnownTypeNames.php @@ -0,0 +1,72 @@ + $skip, + NodeKind::INTERFACE_TYPE_DEFINITION => $skip, + NodeKind::UNION_TYPE_DEFINITION => $skip, + NodeKind::INPUT_OBJECT_TYPE_DEFINITION => $skip, + NodeKind::NAMED_TYPE => static function (NamedTypeNode $node) use ($context) { + $schema = $context->getSchema(); + $typeName = $node->name->value; + $type = $schema->getType($typeName); + if ($type !== null) { + return; + } + + $context->reportError(new Error( + self::unknownTypeMessage( + $typeName, + Utils::suggestionList($typeName, array_keys($schema->getTypeMap())) + ), + [$node] + )); + }, + ]; + } + + /** + * @param string $type + * @param string[] $suggestedTypes + */ + public static function unknownTypeMessage($type, array $suggestedTypes) + { + $message = sprintf('Unknown type "%s".', $type); + if (! empty($suggestedTypes)) { + $suggestions = Utils::quotedOrList($suggestedTypes); + + $message .= sprintf(' Did you mean %s?', $suggestions); + } + + return $message; + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/LoneAnonymousOperation.php b/vendor/webonyx/graphql-php/src/Validator/Rules/LoneAnonymousOperation.php new file mode 100644 index 0000000..40ff821 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/LoneAnonymousOperation.php @@ -0,0 +1,58 @@ + static function (DocumentNode $node) use (&$operationCount) { + $tmp = Utils::filter( + $node->definitions, + static function (Node $definition) { + return $definition->kind === NodeKind::OPERATION_DEFINITION; + } + ); + + $operationCount = count($tmp); + }, + NodeKind::OPERATION_DEFINITION => static function (OperationDefinitionNode $node) use ( + &$operationCount, + $context + ) { + if ($node->name || $operationCount <= 1) { + return; + } + + $context->reportError( + new Error(self::anonOperationNotAloneMessage(), [$node]) + ); + }, + ]; + } + + public static function anonOperationNotAloneMessage() + { + return 'This anonymous operation must be the only defined operation.'; + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/LoneSchemaDefinition.php b/vendor/webonyx/graphql-php/src/Validator/Rules/LoneSchemaDefinition.php new file mode 100644 index 0000000..1a8da67 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/LoneSchemaDefinition.php @@ -0,0 +1,47 @@ +getSchema(); + $alreadyDefined = $oldSchema !== null ? ( + $oldSchema->getAstNode() || + $oldSchema->getQueryType() || + $oldSchema->getMutationType() || + $oldSchema->getSubscriptionType() + ) : false; + + $schemaDefinitionsCount = 0; + + return [ + NodeKind::SCHEMA_DEFINITION => static function (SchemaDefinitionNode $node) use ($alreadyDefined, $context, &$schemaDefinitionsCount) { + if ($alreadyDefined !== false) { + $context->reportError(new Error('Cannot define a new schema within a schema extension.', $node)); + + return; + } + + if ($schemaDefinitionsCount > 0) { + $context->reportError(new Error('Must provide only one schema definition.', $node)); + } + + ++$schemaDefinitionsCount; + }, + ]; + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/NoFragmentCycles.php b/vendor/webonyx/graphql-php/src/Validator/Rules/NoFragmentCycles.php new file mode 100644 index 0000000..1180a4e --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/NoFragmentCycles.php @@ -0,0 +1,125 @@ +visitedFrags = []; + + // Array of AST nodes used to produce meaningful errors + $this->spreadPath = []; + + // Position in the spread path + $this->spreadPathIndexByName = []; + + return [ + NodeKind::OPERATION_DEFINITION => static function () { + return Visitor::skipNode(); + }, + NodeKind::FRAGMENT_DEFINITION => function (FragmentDefinitionNode $node) use ($context) { + if (! isset($this->visitedFrags[$node->name->value])) { + $this->detectCycleRecursive($node, $context); + } + + return Visitor::skipNode(); + }, + ]; + } + + private function detectCycleRecursive(FragmentDefinitionNode $fragment, ValidationContext $context) + { + $fragmentName = $fragment->name->value; + $this->visitedFrags[$fragmentName] = true; + + $spreadNodes = $context->getFragmentSpreads($fragment); + + if (empty($spreadNodes)) { + return; + } + + $this->spreadPathIndexByName[$fragmentName] = count($this->spreadPath); + + for ($i = 0; $i < count($spreadNodes); $i++) { + $spreadNode = $spreadNodes[$i]; + $spreadName = $spreadNode->name->value; + $cycleIndex = $this->spreadPathIndexByName[$spreadName] ?? null; + + if ($cycleIndex === null) { + $this->spreadPath[] = $spreadNode; + if (empty($this->visitedFrags[$spreadName])) { + $spreadFragment = $context->getFragment($spreadName); + if ($spreadFragment) { + $this->detectCycleRecursive($spreadFragment, $context); + } + } + array_pop($this->spreadPath); + } else { + $cyclePath = array_slice($this->spreadPath, $cycleIndex); + $nodes = $cyclePath; + + if (is_array($spreadNode)) { + $nodes = array_merge($nodes, $spreadNode); + } else { + $nodes[] = $spreadNode; + } + + $context->reportError(new Error( + self::cycleErrorMessage( + $spreadName, + Utils::map( + $cyclePath, + static function ($s) { + return $s->name->value; + } + ) + ), + $nodes + )); + } + } + + $this->spreadPathIndexByName[$fragmentName] = null; + } + + /** + * @param string[] $spreadNames + */ + public static function cycleErrorMessage($fragName, array $spreadNames = []) + { + return sprintf( + 'Cannot spread fragment "%s" within itself%s.', + $fragName, + ! empty($spreadNames) ? ' via ' . implode(', ', $spreadNames) : '' + ); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/NoUndefinedVariables.php b/vendor/webonyx/graphql-php/src/Validator/Rules/NoUndefinedVariables.php new file mode 100644 index 0000000..c0cd22c --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/NoUndefinedVariables.php @@ -0,0 +1,62 @@ + [ + 'enter' => static function () use (&$variableNameDefined) { + $variableNameDefined = []; + }, + 'leave' => static function (OperationDefinitionNode $operation) use (&$variableNameDefined, $context) { + $usages = $context->getRecursiveVariableUsages($operation); + + foreach ($usages as $usage) { + $node = $usage['node']; + $varName = $node->name->value; + + if (! empty($variableNameDefined[$varName])) { + continue; + } + + $context->reportError(new Error( + self::undefinedVarMessage( + $varName, + $operation->name ? $operation->name->value : null + ), + [$node, $operation] + )); + } + }, + ], + NodeKind::VARIABLE_DEFINITION => static function (VariableDefinitionNode $def) use (&$variableNameDefined) { + $variableNameDefined[$def->variable->name->value] = true; + }, + ]; + } + + public static function undefinedVarMessage($varName, $opName = null) + { + return $opName + ? sprintf('Variable "$%s" is not defined by operation "%s".', $varName, $opName) + : sprintf('Variable "$%s" is not defined.', $varName); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/NoUnusedFragments.php b/vendor/webonyx/graphql-php/src/Validator/Rules/NoUnusedFragments.php new file mode 100644 index 0000000..d1cd366 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/NoUnusedFragments.php @@ -0,0 +1,69 @@ +operationDefs = []; + $this->fragmentDefs = []; + + return [ + NodeKind::OPERATION_DEFINITION => function ($node) { + $this->operationDefs[] = $node; + + return Visitor::skipNode(); + }, + NodeKind::FRAGMENT_DEFINITION => function (FragmentDefinitionNode $def) { + $this->fragmentDefs[] = $def; + + return Visitor::skipNode(); + }, + NodeKind::DOCUMENT => [ + 'leave' => function () use ($context) { + $fragmentNameUsed = []; + + foreach ($this->operationDefs as $operation) { + foreach ($context->getRecursivelyReferencedFragments($operation) as $fragment) { + $fragmentNameUsed[$fragment->name->value] = true; + } + } + + foreach ($this->fragmentDefs as $fragmentDef) { + $fragName = $fragmentDef->name->value; + if (! empty($fragmentNameUsed[$fragName])) { + continue; + } + + $context->reportError(new Error( + self::unusedFragMessage($fragName), + [$fragmentDef] + )); + } + }, + ], + ]; + } + + public static function unusedFragMessage($fragName) + { + return sprintf('Fragment "%s" is never used.', $fragName); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/NoUnusedVariables.php b/vendor/webonyx/graphql-php/src/Validator/Rules/NoUnusedVariables.php new file mode 100644 index 0000000..e8f7ff3 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/NoUnusedVariables.php @@ -0,0 +1,64 @@ +variableDefs = []; + + return [ + NodeKind::OPERATION_DEFINITION => [ + 'enter' => function () { + $this->variableDefs = []; + }, + 'leave' => function (OperationDefinitionNode $operation) use ($context) { + $variableNameUsed = []; + $usages = $context->getRecursiveVariableUsages($operation); + $opName = $operation->name ? $operation->name->value : null; + + foreach ($usages as $usage) { + $node = $usage['node']; + $variableNameUsed[$node->name->value] = true; + } + + foreach ($this->variableDefs as $variableDef) { + $variableName = $variableDef->variable->name->value; + + if (! empty($variableNameUsed[$variableName])) { + continue; + } + + $context->reportError(new Error( + self::unusedVariableMessage($variableName, $opName), + [$variableDef] + )); + } + }, + ], + NodeKind::VARIABLE_DEFINITION => function ($def) { + $this->variableDefs[] = $def; + }, + ]; + } + + public static function unusedVariableMessage($varName, $opName = null) + { + return $opName + ? sprintf('Variable "$%s" is never used in operation "%s".', $varName, $opName) + : sprintf('Variable "$%s" is never used.', $varName); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/OverlappingFieldsCanBeMerged.php b/vendor/webonyx/graphql-php/src/Validator/Rules/OverlappingFieldsCanBeMerged.php new file mode 100644 index 0000000..8dfa7f1 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/OverlappingFieldsCanBeMerged.php @@ -0,0 +1,900 @@ +comparedFragmentPairs = new PairSet(); + $this->cachedFieldsAndFragmentNames = new SplObjectStorage(); + + return [ + NodeKind::SELECTION_SET => function (SelectionSetNode $selectionSet) use ($context) { + $conflicts = $this->findConflictsWithinSelectionSet( + $context, + $context->getParentType(), + $selectionSet + ); + + foreach ($conflicts as $conflict) { + [[$responseName, $reason], $fields1, $fields2] = $conflict; + + $context->reportError(new Error( + self::fieldsConflictMessage($responseName, $reason), + array_merge($fields1, $fields2) + )); + } + }, + ]; + } + + /** + * Find all conflicts found "within" a selection set, including those found + * via spreading in fragments. Called when visiting each SelectionSet in the + * GraphQL Document. + * + * @param CompositeType $parentType + * + * @return mixed[] + */ + private function findConflictsWithinSelectionSet( + ValidationContext $context, + $parentType, + SelectionSetNode $selectionSet + ) { + [$fieldMap, $fragmentNames] = $this->getFieldsAndFragmentNames( + $context, + $parentType, + $selectionSet + ); + + $conflicts = []; + + // (A) Find find all conflicts "within" the fields of this selection set. + // Note: this is the *only place* `collectConflictsWithin` is called. + $this->collectConflictsWithin( + $context, + $conflicts, + $fieldMap + ); + + $fragmentNamesLength = count($fragmentNames); + if ($fragmentNamesLength !== 0) { + // (B) Then collect conflicts between these fields and those represented by + // each spread fragment name found. + $comparedFragments = []; + for ($i = 0; $i < $fragmentNamesLength; $i++) { + $this->collectConflictsBetweenFieldsAndFragment( + $context, + $conflicts, + $comparedFragments, + false, + $fieldMap, + $fragmentNames[$i] + ); + // (C) Then compare this fragment with all other fragments found in this + // selection set to collect conflicts between fragments spread together. + // This compares each item in the list of fragment names to every other item + // in that same list (except for itself). + for ($j = $i + 1; $j < $fragmentNamesLength; $j++) { + $this->collectConflictsBetweenFragments( + $context, + $conflicts, + false, + $fragmentNames[$i], + $fragmentNames[$j] + ); + } + } + } + + return $conflicts; + } + + /** + * Given a selection set, return the collection of fields (a mapping of response + * name to field ASTs and definitions) as well as a list of fragment names + * referenced via fragment spreads. + * + * @param CompositeType $parentType + * + * @return mixed[]|SplObjectStorage + */ + private function getFieldsAndFragmentNames( + ValidationContext $context, + $parentType, + SelectionSetNode $selectionSet + ) { + if (isset($this->cachedFieldsAndFragmentNames[$selectionSet])) { + $cached = $this->cachedFieldsAndFragmentNames[$selectionSet]; + } else { + $astAndDefs = []; + $fragmentNames = []; + + $this->internalCollectFieldsAndFragmentNames( + $context, + $parentType, + $selectionSet, + $astAndDefs, + $fragmentNames + ); + $cached = [$astAndDefs, array_keys($fragmentNames)]; + $this->cachedFieldsAndFragmentNames[$selectionSet] = $cached; + } + + return $cached; + } + + /** + * Algorithm: + * + * Conflicts occur when two fields exist in a query which will produce the same + * response name, but represent differing values, thus creating a conflict. + * The algorithm below finds all conflicts via making a series of comparisons + * between fields. In order to compare as few fields as possible, this makes + * a series of comparisons "within" sets of fields and "between" sets of fields. + * + * Given any selection set, a collection produces both a set of fields by + * also including all inline fragments, as well as a list of fragments + * referenced by fragment spreads. + * + * A) Each selection set represented in the document first compares "within" its + * collected set of fields, finding any conflicts between every pair of + * overlapping fields. + * Note: This is the *only time* that a the fields "within" a set are compared + * to each other. After this only fields "between" sets are compared. + * + * B) Also, if any fragment is referenced in a selection set, then a + * comparison is made "between" the original set of fields and the + * referenced fragment. + * + * C) Also, if multiple fragments are referenced, then comparisons + * are made "between" each referenced fragment. + * + * D) When comparing "between" a set of fields and a referenced fragment, first + * a comparison is made between each field in the original set of fields and + * each field in the the referenced set of fields. + * + * E) Also, if any fragment is referenced in the referenced selection set, + * then a comparison is made "between" the original set of fields and the + * referenced fragment (recursively referring to step D). + * + * F) When comparing "between" two fragments, first a comparison is made between + * each field in the first referenced set of fields and each field in the the + * second referenced set of fields. + * + * G) Also, any fragments referenced by the first must be compared to the + * second, and any fragments referenced by the second must be compared to the + * first (recursively referring to step F). + * + * H) When comparing two fields, if both have selection sets, then a comparison + * is made "between" both selection sets, first comparing the set of fields in + * the first selection set with the set of fields in the second. + * + * I) Also, if any fragment is referenced in either selection set, then a + * comparison is made "between" the other set of fields and the + * referenced fragment. + * + * J) Also, if two fragments are referenced in both selection sets, then a + * comparison is made "between" the two fragments. + */ + + /** + * Given a reference to a fragment, return the represented collection of fields + * as well as a list of nested fragment names referenced via fragment spreads. + * + * @param CompositeType $parentType + * @param mixed[][][] $astAndDefs + * @param bool[] $fragmentNames + */ + private function internalCollectFieldsAndFragmentNames( + ValidationContext $context, + $parentType, + SelectionSetNode $selectionSet, + array &$astAndDefs, + array &$fragmentNames + ) { + foreach ($selectionSet->selections as $selection) { + switch (true) { + case $selection instanceof FieldNode: + $fieldName = $selection->name->value; + $fieldDef = null; + if ($parentType instanceof ObjectType || + $parentType instanceof InterfaceType) { + $tmp = $parentType->getFields(); + if (isset($tmp[$fieldName])) { + $fieldDef = $tmp[$fieldName]; + } + } + $responseName = $selection->alias ? $selection->alias->value : $fieldName; + + if (! isset($astAndDefs[$responseName])) { + $astAndDefs[$responseName] = []; + } + $astAndDefs[$responseName][] = [$parentType, $selection, $fieldDef]; + break; + case $selection instanceof FragmentSpreadNode: + $fragmentNames[$selection->name->value] = true; + break; + case $selection instanceof InlineFragmentNode: + $typeCondition = $selection->typeCondition; + $inlineFragmentType = $typeCondition + ? TypeInfo::typeFromAST($context->getSchema(), $typeCondition) + : $parentType; + + $this->internalCollectFieldsAndFragmentNames( + $context, + $inlineFragmentType, + $selection->selectionSet, + $astAndDefs, + $fragmentNames + ); + break; + } + } + } + + /** + * Collect all Conflicts "within" one collection of fields. + * + * @param mixed[][] $conflicts + * @param mixed[][] $fieldMap + */ + private function collectConflictsWithin( + ValidationContext $context, + array &$conflicts, + array $fieldMap + ) { + // A field map is a keyed collection, where each key represents a response + // name and the value at that key is a list of all fields which provide that + // response name. For every response name, if there are multiple fields, they + // must be compared to find a potential conflict. + foreach ($fieldMap as $responseName => $fields) { + // This compares every field in the list to every other field in this list + // (except to itself). If the list only has one item, nothing needs to + // be compared. + $fieldsLength = count($fields); + if ($fieldsLength <= 1) { + continue; + } + + for ($i = 0; $i < $fieldsLength; $i++) { + for ($j = $i + 1; $j < $fieldsLength; $j++) { + $conflict = $this->findConflict( + $context, + false, // within one collection is never mutually exclusive + $responseName, + $fields[$i], + $fields[$j] + ); + if (! $conflict) { + continue; + } + + $conflicts[] = $conflict; + } + } + } + } + + /** + * Determines if there is a conflict between two particular fields, including + * comparing their sub-fields. + * + * @param bool $parentFieldsAreMutuallyExclusive + * @param string $responseName + * @param mixed[] $field1 + * @param mixed[] $field2 + * + * @return mixed[]|null + */ + private function findConflict( + ValidationContext $context, + $parentFieldsAreMutuallyExclusive, + $responseName, + array $field1, + array $field2 + ) { + [$parentType1, $ast1, $def1] = $field1; + [$parentType2, $ast2, $def2] = $field2; + + // If it is known that two fields could not possibly apply at the same + // time, due to the parent types, then it is safe to permit them to diverge + // in aliased field or arguments used as they will not present any ambiguity + // by differing. + // It is known that two parent types could never overlap if they are + // different Object types. Interface or Union types might overlap - if not + // in the current state of the schema, then perhaps in some future version, + // thus may not safely diverge. + $areMutuallyExclusive = + $parentFieldsAreMutuallyExclusive || + ( + $parentType1 !== $parentType2 && + $parentType1 instanceof ObjectType && + $parentType2 instanceof ObjectType + ); + + // The return type for each field. + $type1 = $def1 === null ? null : $def1->getType(); + $type2 = $def2 === null ? null : $def2->getType(); + + if (! $areMutuallyExclusive) { + // Two aliases must refer to the same field. + $name1 = $ast1->name->value; + $name2 = $ast2->name->value; + if ($name1 !== $name2) { + return [ + [$responseName, sprintf('%s and %s are different fields', $name1, $name2)], + [$ast1], + [$ast2], + ]; + } + + if (! $this->sameArguments($ast1->arguments ?: [], $ast2->arguments ?: [])) { + return [ + [$responseName, 'they have differing arguments'], + [$ast1], + [$ast2], + ]; + } + } + + if ($type1 && $type2 && $this->doTypesConflict($type1, $type2)) { + return [ + [$responseName, sprintf('they return conflicting types %s and %s', $type1, $type2)], + [$ast1], + [$ast2], + ]; + } + + // Collect and compare sub-fields. Use the same "visited fragment names" list + // for both collections so fields in a fragment reference are never + // compared to themselves. + $selectionSet1 = $ast1->selectionSet; + $selectionSet2 = $ast2->selectionSet; + if ($selectionSet1 && $selectionSet2) { + $conflicts = $this->findConflictsBetweenSubSelectionSets( + $context, + $areMutuallyExclusive, + Type::getNamedType($type1), + $selectionSet1, + Type::getNamedType($type2), + $selectionSet2 + ); + + return $this->subfieldConflicts( + $conflicts, + $responseName, + $ast1, + $ast2 + ); + } + + return null; + } + + /** + * @param ArgumentNode[] $arguments1 + * @param ArgumentNode[] $arguments2 + * + * @return bool + */ + private function sameArguments($arguments1, $arguments2) + { + if (count($arguments1) !== count($arguments2)) { + return false; + } + foreach ($arguments1 as $argument1) { + $argument2 = null; + foreach ($arguments2 as $argument) { + if ($argument->name->value === $argument1->name->value) { + $argument2 = $argument; + break; + } + } + if (! $argument2) { + return false; + } + + if (! $this->sameValue($argument1->value, $argument2->value)) { + return false; + } + } + + return true; + } + + /** + * @return bool + */ + private function sameValue(Node $value1, Node $value2) + { + return (! $value1 && ! $value2) || (Printer::doPrint($value1) === Printer::doPrint($value2)); + } + + /** + * Two types conflict if both types could not apply to a value simultaneously. + * Composite types are ignored as their individual field types will be compared + * later recursively. However List and Non-Null types must match. + * + * @return bool + */ + private function doTypesConflict(OutputType $type1, OutputType $type2) + { + if ($type1 instanceof ListOfType) { + return $type2 instanceof ListOfType ? + $this->doTypesConflict($type1->getWrappedType(), $type2->getWrappedType()) : + true; + } + if ($type2 instanceof ListOfType) { + return $type1 instanceof ListOfType ? + $this->doTypesConflict($type1->getWrappedType(), $type2->getWrappedType()) : + true; + } + if ($type1 instanceof NonNull) { + return $type2 instanceof NonNull ? + $this->doTypesConflict($type1->getWrappedType(), $type2->getWrappedType()) : + true; + } + if ($type2 instanceof NonNull) { + return $type1 instanceof NonNull ? + $this->doTypesConflict($type1->getWrappedType(), $type2->getWrappedType()) : + true; + } + if (Type::isLeafType($type1) || Type::isLeafType($type2)) { + return $type1 !== $type2; + } + + return false; + } + + /** + * Find all conflicts found between two selection sets, including those found + * via spreading in fragments. Called when determining if conflicts exist + * between the sub-fields of two overlapping fields. + * + * @param bool $areMutuallyExclusive + * @param CompositeType $parentType1 + * @param CompositeType $parentType2 + * + * @return mixed[][] + */ + private function findConflictsBetweenSubSelectionSets( + ValidationContext $context, + $areMutuallyExclusive, + $parentType1, + SelectionSetNode $selectionSet1, + $parentType2, + SelectionSetNode $selectionSet2 + ) { + $conflicts = []; + + [$fieldMap1, $fragmentNames1] = $this->getFieldsAndFragmentNames( + $context, + $parentType1, + $selectionSet1 + ); + [$fieldMap2, $fragmentNames2] = $this->getFieldsAndFragmentNames( + $context, + $parentType2, + $selectionSet2 + ); + + // (H) First, collect all conflicts between these two collections of field. + $this->collectConflictsBetween( + $context, + $conflicts, + $areMutuallyExclusive, + $fieldMap1, + $fieldMap2 + ); + + // (I) Then collect conflicts between the first collection of fields and + // those referenced by each fragment name associated with the second. + $fragmentNames2Length = count($fragmentNames2); + if ($fragmentNames2Length !== 0) { + $comparedFragments = []; + for ($j = 0; $j < $fragmentNames2Length; $j++) { + $this->collectConflictsBetweenFieldsAndFragment( + $context, + $conflicts, + $comparedFragments, + $areMutuallyExclusive, + $fieldMap1, + $fragmentNames2[$j] + ); + } + } + + // (I) Then collect conflicts between the second collection of fields and + // those referenced by each fragment name associated with the first. + $fragmentNames1Length = count($fragmentNames1); + if ($fragmentNames1Length !== 0) { + $comparedFragments = []; + for ($i = 0; $i < $fragmentNames1Length; $i++) { + $this->collectConflictsBetweenFieldsAndFragment( + $context, + $conflicts, + $comparedFragments, + $areMutuallyExclusive, + $fieldMap2, + $fragmentNames1[$i] + ); + } + } + + // (J) Also collect conflicts between any fragment names by the first and + // fragment names by the second. This compares each item in the first set of + // names to each item in the second set of names. + for ($i = 0; $i < $fragmentNames1Length; $i++) { + for ($j = 0; $j < $fragmentNames2Length; $j++) { + $this->collectConflictsBetweenFragments( + $context, + $conflicts, + $areMutuallyExclusive, + $fragmentNames1[$i], + $fragmentNames2[$j] + ); + } + } + + return $conflicts; + } + + /** + * Collect all Conflicts between two collections of fields. This is similar to, + * but different from the `collectConflictsWithin` function above. This check + * assumes that `collectConflictsWithin` has already been called on each + * provided collection of fields. This is true because this validator traverses + * each individual selection set. + * + * @param mixed[][] $conflicts + * @param bool $parentFieldsAreMutuallyExclusive + * @param mixed[] $fieldMap1 + * @param mixed[] $fieldMap2 + */ + private function collectConflictsBetween( + ValidationContext $context, + array &$conflicts, + $parentFieldsAreMutuallyExclusive, + array $fieldMap1, + array $fieldMap2 + ) { + // A field map is a keyed collection, where each key represents a response + // name and the value at that key is a list of all fields which provide that + // response name. For any response name which appears in both provided field + // maps, each field from the first field map must be compared to every field + // in the second field map to find potential conflicts. + foreach ($fieldMap1 as $responseName => $fields1) { + if (! isset($fieldMap2[$responseName])) { + continue; + } + + $fields2 = $fieldMap2[$responseName]; + $fields1Length = count($fields1); + $fields2Length = count($fields2); + for ($i = 0; $i < $fields1Length; $i++) { + for ($j = 0; $j < $fields2Length; $j++) { + $conflict = $this->findConflict( + $context, + $parentFieldsAreMutuallyExclusive, + $responseName, + $fields1[$i], + $fields2[$j] + ); + if (! $conflict) { + continue; + } + + $conflicts[] = $conflict; + } + } + } + } + + /** + * Collect all conflicts found between a set of fields and a fragment reference + * including via spreading in any nested fragments. + * + * @param mixed[][] $conflicts + * @param bool[] $comparedFragments + * @param bool $areMutuallyExclusive + * @param mixed[][] $fieldMap + * @param string $fragmentName + */ + private function collectConflictsBetweenFieldsAndFragment( + ValidationContext $context, + array &$conflicts, + array &$comparedFragments, + $areMutuallyExclusive, + array $fieldMap, + $fragmentName + ) { + if (isset($comparedFragments[$fragmentName])) { + return; + } + $comparedFragments[$fragmentName] = true; + + $fragment = $context->getFragment($fragmentName); + if (! $fragment) { + return; + } + + [$fieldMap2, $fragmentNames2] = $this->getReferencedFieldsAndFragmentNames( + $context, + $fragment + ); + + if ($fieldMap === $fieldMap2) { + return; + } + + // (D) First collect any conflicts between the provided collection of fields + // and the collection of fields represented by the given fragment. + $this->collectConflictsBetween( + $context, + $conflicts, + $areMutuallyExclusive, + $fieldMap, + $fieldMap2 + ); + + // (E) Then collect any conflicts between the provided collection of fields + // and any fragment names found in the given fragment. + $fragmentNames2Length = count($fragmentNames2); + for ($i = 0; $i < $fragmentNames2Length; $i++) { + $this->collectConflictsBetweenFieldsAndFragment( + $context, + $conflicts, + $comparedFragments, + $areMutuallyExclusive, + $fieldMap, + $fragmentNames2[$i] + ); + } + } + + /** + * Given a reference to a fragment, return the represented collection of fields + * as well as a list of nested fragment names referenced via fragment spreads. + * + * @return mixed[]|SplObjectStorage + */ + private function getReferencedFieldsAndFragmentNames( + ValidationContext $context, + FragmentDefinitionNode $fragment + ) { + // Short-circuit building a type from the AST if possible. + if (isset($this->cachedFieldsAndFragmentNames[$fragment->selectionSet])) { + return $this->cachedFieldsAndFragmentNames[$fragment->selectionSet]; + } + + $fragmentType = TypeInfo::typeFromAST($context->getSchema(), $fragment->typeCondition); + + return $this->getFieldsAndFragmentNames( + $context, + $fragmentType, + $fragment->selectionSet + ); + } + + /** + * Collect all conflicts found between two fragments, including via spreading in + * any nested fragments. + * + * @param mixed[][] $conflicts + * @param bool $areMutuallyExclusive + * @param string $fragmentName1 + * @param string $fragmentName2 + */ + private function collectConflictsBetweenFragments( + ValidationContext $context, + array &$conflicts, + $areMutuallyExclusive, + $fragmentName1, + $fragmentName2 + ) { + // No need to compare a fragment to itself. + if ($fragmentName1 === $fragmentName2) { + return; + } + + // Memoize so two fragments are not compared for conflicts more than once. + if ($this->comparedFragmentPairs->has( + $fragmentName1, + $fragmentName2, + $areMutuallyExclusive + ) + ) { + return; + } + $this->comparedFragmentPairs->add( + $fragmentName1, + $fragmentName2, + $areMutuallyExclusive + ); + + $fragment1 = $context->getFragment($fragmentName1); + $fragment2 = $context->getFragment($fragmentName2); + if (! $fragment1 || ! $fragment2) { + return; + } + + [$fieldMap1, $fragmentNames1] = $this->getReferencedFieldsAndFragmentNames( + $context, + $fragment1 + ); + [$fieldMap2, $fragmentNames2] = $this->getReferencedFieldsAndFragmentNames( + $context, + $fragment2 + ); + + // (F) First, collect all conflicts between these two collections of fields + // (not including any nested fragments). + $this->collectConflictsBetween( + $context, + $conflicts, + $areMutuallyExclusive, + $fieldMap1, + $fieldMap2 + ); + + // (G) Then collect conflicts between the first fragment and any nested + // fragments spread in the second fragment. + $fragmentNames2Length = count($fragmentNames2); + for ($j = 0; $j < $fragmentNames2Length; $j++) { + $this->collectConflictsBetweenFragments( + $context, + $conflicts, + $areMutuallyExclusive, + $fragmentName1, + $fragmentNames2[$j] + ); + } + + // (G) Then collect conflicts between the second fragment and any nested + // fragments spread in the first fragment. + $fragmentNames1Length = count($fragmentNames1); + for ($i = 0; $i < $fragmentNames1Length; $i++) { + $this->collectConflictsBetweenFragments( + $context, + $conflicts, + $areMutuallyExclusive, + $fragmentNames1[$i], + $fragmentName2 + ); + } + } + + /** + * Given a series of Conflicts which occurred between two sub-fields, generate + * a single Conflict. + * + * @param mixed[][] $conflicts + * @param string $responseName + * + * @return mixed[]|null + */ + private function subfieldConflicts( + array $conflicts, + $responseName, + FieldNode $ast1, + FieldNode $ast2 + ) { + if (count($conflicts) === 0) { + return null; + } + + return [ + [ + $responseName, + array_map( + static function ($conflict) { + return $conflict[0]; + }, + $conflicts + ), + ], + array_reduce( + $conflicts, + static function ($allFields, $conflict) { + return array_merge($allFields, $conflict[1]); + }, + [$ast1] + ), + array_reduce( + $conflicts, + static function ($allFields, $conflict) { + return array_merge($allFields, $conflict[2]); + }, + [$ast2] + ), + ]; + } + + /** + * @param string $responseName + * @param string $reason + */ + public static function fieldsConflictMessage($responseName, $reason) + { + $reasonMessage = self::reasonMessage($reason); + + return sprintf( + 'Fields "%s" conflict because %s. Use different aliases on the fields to fetch both if this was intentional.', + $responseName, + $reasonMessage + ); + } + + public static function reasonMessage($reason) + { + if (is_array($reason)) { + $tmp = array_map( + static function ($tmp) { + [$responseName, $subReason] = $tmp; + + $reasonMessage = self::reasonMessage($subReason); + + return sprintf('subfields "%s" conflict because %s', $responseName, $reasonMessage); + }, + $reason + ); + + return implode(' and ', $tmp); + } + + return $reason; + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/PossibleFragmentSpreads.php b/vendor/webonyx/graphql-php/src/Validator/Rules/PossibleFragmentSpreads.php new file mode 100644 index 0000000..26611e6 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/PossibleFragmentSpreads.php @@ -0,0 +1,160 @@ + function (InlineFragmentNode $node) use ($context) { + $fragType = $context->getType(); + $parentType = $context->getParentType(); + + if (! ($fragType instanceof CompositeType) || + ! ($parentType instanceof CompositeType) || + $this->doTypesOverlap($context->getSchema(), $fragType, $parentType)) { + return; + } + + $context->reportError(new Error( + self::typeIncompatibleAnonSpreadMessage($parentType, $fragType), + [$node] + )); + }, + NodeKind::FRAGMENT_SPREAD => function (FragmentSpreadNode $node) use ($context) { + $fragName = $node->name->value; + $fragType = $this->getFragmentType($context, $fragName); + $parentType = $context->getParentType(); + + if (! $fragType || + ! $parentType || + $this->doTypesOverlap($context->getSchema(), $fragType, $parentType) + ) { + return; + } + + $context->reportError(new Error( + self::typeIncompatibleSpreadMessage($fragName, $parentType, $fragType), + [$node] + )); + }, + ]; + } + + private function doTypesOverlap(Schema $schema, CompositeType $fragType, CompositeType $parentType) + { + // Checking in the order of the most frequently used scenarios: + // Parent type === fragment type + if ($parentType === $fragType) { + return true; + } + + // Parent type is interface or union, fragment type is object type + if ($parentType instanceof AbstractType && $fragType instanceof ObjectType) { + return $schema->isPossibleType($parentType, $fragType); + } + + // Parent type is object type, fragment type is interface (or rather rare - union) + if ($parentType instanceof ObjectType && $fragType instanceof AbstractType) { + return $schema->isPossibleType($fragType, $parentType); + } + + // Both are object types: + if ($parentType instanceof ObjectType && $fragType instanceof ObjectType) { + return $parentType === $fragType; + } + + // Both are interfaces + // This case may be assumed valid only when implementations of two interfaces intersect + // But we don't have information about all implementations at runtime + // (getting this information via $schema->getPossibleTypes() requires scanning through whole schema + // which is very costly to do at each request due to PHP "shared nothing" architecture) + // + // So in this case we just make it pass - invalid fragment spreads will be simply ignored during execution + // See also https://github.com/webonyx/graphql-php/issues/69#issuecomment-283954602 + if ($parentType instanceof InterfaceType && $fragType instanceof InterfaceType) { + return true; + + // Note that there is one case when we do have information about all implementations: + // When schema descriptor is defined ($schema->hasDescriptor()) + // BUT we must avoid situation when some query that worked in development had suddenly stopped + // working in production. So staying consistent and always validate. + } + + // Interface within union + if ($parentType instanceof UnionType && $fragType instanceof InterfaceType) { + foreach ($parentType->getTypes() as $type) { + if ($type->implementsInterface($fragType)) { + return true; + } + } + } + + if ($parentType instanceof InterfaceType && $fragType instanceof UnionType) { + foreach ($fragType->getTypes() as $type) { + if ($type->implementsInterface($parentType)) { + return true; + } + } + } + + if ($parentType instanceof UnionType && $fragType instanceof UnionType) { + foreach ($fragType->getTypes() as $type) { + if ($parentType->isPossibleType($type)) { + return true; + } + } + } + + return false; + } + + public static function typeIncompatibleAnonSpreadMessage($parentType, $fragType) + { + return sprintf( + 'Fragment cannot be spread here as objects of type "%s" can never be of type "%s".', + $parentType, + $fragType + ); + } + + private function getFragmentType(ValidationContext $context, $name) + { + $frag = $context->getFragment($name); + if ($frag) { + $type = TypeInfo::typeFromAST($context->getSchema(), $frag->typeCondition); + if ($type instanceof CompositeType) { + return $type; + } + } + + return null; + } + + public static function typeIncompatibleSpreadMessage($fragName, $parentType, $fragType) + { + return sprintf( + 'Fragment "%s" cannot be spread here as objects of type "%s" can never be of type "%s".', + $fragName, + $parentType, + $fragType + ); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/ProvidedNonNullArguments.php b/vendor/webonyx/graphql-php/src/Validator/Rules/ProvidedNonNullArguments.php new file mode 100644 index 0000000..976f38b --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/ProvidedNonNullArguments.php @@ -0,0 +1,98 @@ + [ + 'leave' => static function (FieldNode $fieldNode) use ($context) { + $fieldDef = $context->getFieldDef(); + + if (! $fieldDef) { + return Visitor::skipNode(); + } + $argNodes = $fieldNode->arguments ?: []; + + $argNodeMap = []; + foreach ($argNodes as $argNode) { + $argNodeMap[$argNode->name->value] = $argNodes; + } + foreach ($fieldDef->args as $argDef) { + $argNode = $argNodeMap[$argDef->name] ?? null; + if ($argNode || ! ($argDef->getType() instanceof NonNull)) { + continue; + } + + $context->reportError(new Error( + self::missingFieldArgMessage($fieldNode->name->value, $argDef->name, $argDef->getType()), + [$fieldNode] + )); + } + }, + ], + NodeKind::DIRECTIVE => [ + 'leave' => static function (DirectiveNode $directiveNode) use ($context) { + $directiveDef = $context->getDirective(); + if (! $directiveDef) { + return Visitor::skipNode(); + } + $argNodes = $directiveNode->arguments ?: []; + $argNodeMap = []; + foreach ($argNodes as $argNode) { + $argNodeMap[$argNode->name->value] = $argNodes; + } + + foreach ($directiveDef->args as $argDef) { + $argNode = $argNodeMap[$argDef->name] ?? null; + if ($argNode || ! ($argDef->getType() instanceof NonNull)) { + continue; + } + + $context->reportError(new Error( + self::missingDirectiveArgMessage( + $directiveNode->name->value, + $argDef->name, + $argDef->getType() + ), + [$directiveNode] + )); + } + }, + ], + ]; + } + + public static function missingFieldArgMessage($fieldName, $argName, $type) + { + return sprintf( + 'Field "%s" argument "%s" of type "%s" is required but not provided.', + $fieldName, + $argName, + $type + ); + } + + public static function missingDirectiveArgMessage($directiveName, $argName, $type) + { + return sprintf( + 'Directive "@%s" argument "%s" of type "%s" is required but not provided.', + $directiveName, + $argName, + $type + ); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/ProvidedRequiredArgumentsOnDirectives.php b/vendor/webonyx/graphql-php/src/Validator/Rules/ProvidedRequiredArgumentsOnDirectives.php new file mode 100644 index 0000000..8750711 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/ProvidedRequiredArgumentsOnDirectives.php @@ -0,0 +1,110 @@ +getSchema(); + $definedDirectives = $schema->getDirectives(); + + foreach ($definedDirectives as $directive) { + $requiredArgsMap[$directive->name] = Utils::keyMap( + array_filter($directive->args, static function (FieldArgument $arg) : bool { + return $arg->getType() instanceof NonNull && ! isset($arg->defaultValue); + }), + static function (FieldArgument $arg) : string { + return $arg->name; + } + ); + } + + $astDefinition = $context->getDocument()->definitions; + foreach ($astDefinition as $def) { + if (! ($def instanceof DirectiveDefinitionNode)) { + continue; + } + + if (is_array($def->arguments)) { + $arguments = $def->arguments; + } elseif ($def->arguments instanceof NodeList) { + $arguments = iterator_to_array($def->arguments->getIterator()); + } else { + $arguments = null; + } + + $requiredArgsMap[$def->name->value] = Utils::keyMap( + $arguments ? array_filter($arguments, static function (Node $argument) : bool { + return $argument instanceof NonNullTypeNode && + ( + ! isset($argument->defaultValue) || + $argument->defaultValue === null + ); + }) : [], + static function (NamedTypeNode $argument) : string { + return $argument->name->value; + } + ); + } + + return [ + NodeKind::DIRECTIVE => static function (DirectiveNode $directiveNode) use ($requiredArgsMap, $context) { + $directiveName = $directiveNode->name->value; + $requiredArgs = $requiredArgsMap[$directiveName] ?? null; + if (! $requiredArgs) { + return; + } + + $argNodes = $directiveNode->arguments ?: []; + $argNodeMap = Utils::keyMap( + $argNodes, + static function (ArgumentNode $arg) : string { + return $arg->name->value; + } + ); + + foreach ($requiredArgs as $argName => $arg) { + if (isset($argNodeMap[$argName])) { + continue; + } + + $context->reportError( + new Error(static::missingDirectiveArgMessage($directiveName, $argName), [$directiveNode]) + ); + } + }, + ]; + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/QueryComplexity.php b/vendor/webonyx/graphql-php/src/Validator/Rules/QueryComplexity.php new file mode 100644 index 0000000..b5c33f9 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/QueryComplexity.php @@ -0,0 +1,297 @@ +setMaxQueryComplexity($maxQueryComplexity); + } + + public function getVisitor(ValidationContext $context) + { + $this->context = $context; + + $this->variableDefs = new ArrayObject(); + $this->fieldNodeAndDefs = new ArrayObject(); + $this->complexity = 0; + + return $this->invokeIfNeeded( + $context, + [ + NodeKind::SELECTION_SET => function (SelectionSetNode $selectionSet) use ($context) { + $this->fieldNodeAndDefs = $this->collectFieldASTsAndDefs( + $context, + $context->getParentType(), + $selectionSet, + null, + $this->fieldNodeAndDefs + ); + }, + NodeKind::VARIABLE_DEFINITION => function ($def) { + $this->variableDefs[] = $def; + + return Visitor::skipNode(); + }, + NodeKind::OPERATION_DEFINITION => [ + 'leave' => function (OperationDefinitionNode $operationDefinition) use ($context, &$complexity) { + $errors = $context->getErrors(); + + if (! empty($errors)) { + return; + } + + $this->complexity = $this->fieldComplexity($operationDefinition, $complexity); + + if ($this->getQueryComplexity() <= $this->getMaxQueryComplexity()) { + return; + } + + $context->reportError( + new Error(self::maxQueryComplexityErrorMessage( + $this->getMaxQueryComplexity(), + $this->getQueryComplexity() + )) + ); + }, + ], + ] + ); + } + + private function fieldComplexity($node, $complexity = 0) + { + if (isset($node->selectionSet) && $node->selectionSet instanceof SelectionSetNode) { + foreach ($node->selectionSet->selections as $childNode) { + $complexity = $this->nodeComplexity($childNode, $complexity); + } + } + + return $complexity; + } + + private function nodeComplexity(Node $node, $complexity = 0) + { + switch ($node->kind) { + case NodeKind::FIELD: + /** @var FieldNode $node */ + // default values + $args = []; + $complexityFn = FieldDefinition::DEFAULT_COMPLEXITY_FN; + + // calculate children complexity if needed + $childrenComplexity = 0; + + // node has children? + if (isset($node->selectionSet)) { + $childrenComplexity = $this->fieldComplexity($node); + } + + $astFieldInfo = $this->astFieldInfo($node); + $fieldDef = $astFieldInfo[1]; + + if ($fieldDef instanceof FieldDefinition) { + if ($this->directiveExcludesField($node)) { + break; + } + + $args = $this->buildFieldArguments($node); + //get complexity fn using fieldDef complexity + if (method_exists($fieldDef, 'getComplexityFn')) { + $complexityFn = $fieldDef->getComplexityFn(); + } + } + + $complexity += call_user_func_array($complexityFn, [$childrenComplexity, $args]); + break; + + case NodeKind::INLINE_FRAGMENT: + /** @var InlineFragmentNode $node */ + // node has children? + if (isset($node->selectionSet)) { + $complexity = $this->fieldComplexity($node, $complexity); + } + break; + + case NodeKind::FRAGMENT_SPREAD: + /** @var FragmentSpreadNode $node */ + $fragment = $this->getFragment($node); + + if ($fragment !== null) { + $complexity = $this->fieldComplexity($fragment, $complexity); + } + break; + } + + return $complexity; + } + + private function astFieldInfo(FieldNode $field) + { + $fieldName = $this->getFieldName($field); + $astFieldInfo = [null, null]; + if (isset($this->fieldNodeAndDefs[$fieldName])) { + foreach ($this->fieldNodeAndDefs[$fieldName] as $astAndDef) { + if ($astAndDef[0] === $field) { + $astFieldInfo = $astAndDef; + break; + } + } + } + + return $astFieldInfo; + } + + private function directiveExcludesField(FieldNode $node) + { + foreach ($node->directives as $directiveNode) { + if ($directiveNode->name->value === 'deprecated') { + return false; + } + [$errors, $variableValues] = Values::getVariableValues( + $this->context->getSchema(), + $this->variableDefs, + $this->getRawVariableValues() + ); + if (! empty($errors)) { + throw new Error(implode( + "\n\n", + array_map( + static function ($error) { + return $error->getMessage(); + }, + $errors + ) + )); + } + if ($directiveNode->name->value === 'include') { + $directive = Directive::includeDirective(); + /** @var bool $directiveArgsIf */ + $directiveArgsIf = Values::getArgumentValues($directive, $directiveNode, $variableValues)['if']; + + return ! $directiveArgsIf; + } + $directive = Directive::skipDirective(); + $directiveArgsIf = Values::getArgumentValues($directive, $directiveNode, $variableValues); + + return $directiveArgsIf['if']; + } + } + + public function getRawVariableValues() + { + return $this->rawVariableValues; + } + + /** + * @param mixed[]|null $rawVariableValues + */ + public function setRawVariableValues(?array $rawVariableValues = null) + { + $this->rawVariableValues = $rawVariableValues ?: []; + } + + private function buildFieldArguments(FieldNode $node) + { + $rawVariableValues = $this->getRawVariableValues(); + $astFieldInfo = $this->astFieldInfo($node); + $fieldDef = $astFieldInfo[1]; + + $args = []; + + if ($fieldDef instanceof FieldDefinition) { + [$errors, $variableValues] = Values::getVariableValues( + $this->context->getSchema(), + $this->variableDefs, + $rawVariableValues + ); + + if (! empty($errors)) { + throw new Error(implode( + "\n\n", + array_map( + static function ($error) { + return $error->getMessage(); + }, + $errors + ) + )); + } + + $args = Values::getArgumentValues($fieldDef, $node, $variableValues); + } + + return $args; + } + + public function getQueryComplexity() + { + return $this->complexity; + } + + public function getMaxQueryComplexity() + { + return $this->maxQueryComplexity; + } + + /** + * Set max query complexity. If equal to 0 no check is done. Must be greater or equal to 0. + */ + public function setMaxQueryComplexity($maxQueryComplexity) + { + $this->checkIfGreaterOrEqualToZero('maxQueryComplexity', $maxQueryComplexity); + + $this->maxQueryComplexity = (int) $maxQueryComplexity; + } + + public static function maxQueryComplexityErrorMessage($max, $count) + { + return sprintf('Max query complexity should be %d but got %d.', $max, $count); + } + + protected function isEnabled() + { + return $this->getMaxQueryComplexity() !== self::DISABLED; + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/QueryDepth.php b/vendor/webonyx/graphql-php/src/Validator/Rules/QueryDepth.php new file mode 100644 index 0000000..e4b31a0 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/QueryDepth.php @@ -0,0 +1,118 @@ +setMaxQueryDepth($maxQueryDepth); + } + + public function getVisitor(ValidationContext $context) + { + return $this->invokeIfNeeded( + $context, + [ + NodeKind::OPERATION_DEFINITION => [ + 'leave' => function (OperationDefinitionNode $operationDefinition) use ($context) { + $maxDepth = $this->fieldDepth($operationDefinition); + + if ($maxDepth <= $this->getMaxQueryDepth()) { + return; + } + + $context->reportError( + new Error(self::maxQueryDepthErrorMessage($this->getMaxQueryDepth(), $maxDepth)) + ); + }, + ], + ] + ); + } + + private function fieldDepth($node, $depth = 0, $maxDepth = 0) + { + if (isset($node->selectionSet) && $node->selectionSet instanceof SelectionSetNode) { + foreach ($node->selectionSet->selections as $childNode) { + $maxDepth = $this->nodeDepth($childNode, $depth, $maxDepth); + } + } + + return $maxDepth; + } + + private function nodeDepth(Node $node, $depth = 0, $maxDepth = 0) + { + switch ($node->kind) { + case NodeKind::FIELD: + /** @var FieldNode $node */ + // node has children? + if ($node->selectionSet !== null) { + // update maxDepth if needed + if ($depth > $maxDepth) { + $maxDepth = $depth; + } + $maxDepth = $this->fieldDepth($node, $depth + 1, $maxDepth); + } + break; + + case NodeKind::INLINE_FRAGMENT: + /** @var InlineFragmentNode $node */ + // node has children? + if ($node->selectionSet !== null) { + $maxDepth = $this->fieldDepth($node, $depth, $maxDepth); + } + break; + + case NodeKind::FRAGMENT_SPREAD: + /** @var FragmentSpreadNode $node */ + $fragment = $this->getFragment($node); + + if ($fragment !== null) { + $maxDepth = $this->fieldDepth($fragment, $depth, $maxDepth); + } + break; + } + + return $maxDepth; + } + + public function getMaxQueryDepth() + { + return $this->maxQueryDepth; + } + + /** + * Set max query depth. If equal to 0 no check is done. Must be greater or equal to 0. + */ + public function setMaxQueryDepth($maxQueryDepth) + { + $this->checkIfGreaterOrEqualToZero('maxQueryDepth', $maxQueryDepth); + + $this->maxQueryDepth = (int) $maxQueryDepth; + } + + public static function maxQueryDepthErrorMessage($max, $count) + { + return sprintf('Max query depth should be %d but got %d.', $max, $count); + } + + protected function isEnabled() + { + return $this->getMaxQueryDepth() !== self::DISABLED; + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/QuerySecurityRule.php b/vendor/webonyx/graphql-php/src/Validator/Rules/QuerySecurityRule.php new file mode 100644 index 0000000..c5f0260 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/QuerySecurityRule.php @@ -0,0 +1,188 @@ +name->value; + $fragments = $this->getFragments(); + + return $fragments[$spreadName] ?? null; + } + + /** + * @return FragmentDefinitionNode[] + */ + protected function getFragments() + { + return $this->fragments; + } + + /** + * @param callable[] $validators + * + * @return callable[] + */ + protected function invokeIfNeeded(ValidationContext $context, array $validators) + { + // is disabled? + if (! $this->isEnabled()) { + return []; + } + + $this->gatherFragmentDefinition($context); + + return $validators; + } + + abstract protected function isEnabled(); + + protected function gatherFragmentDefinition(ValidationContext $context) + { + // Gather all the fragment definition. + // Importantly this does not include inline fragments. + $definitions = $context->getDocument()->definitions; + foreach ($definitions as $node) { + if (! ($node instanceof FragmentDefinitionNode)) { + continue; + } + + $this->fragments[$node->name->value] = $node; + } + } + + /** + * Given a selectionSet, adds all of the fields in that selection to + * the passed in map of fields, and returns it at the end. + * + * Note: This is not the same as execution's collectFields because at static + * time we do not know what object type will be used, so we unconditionally + * spread in all fragments. + * + * @see \GraphQL\Validator\Rules\OverlappingFieldsCanBeMerged + * + * @param Type|null $parentType + * + * @return ArrayObject + */ + protected function collectFieldASTsAndDefs( + ValidationContext $context, + $parentType, + SelectionSetNode $selectionSet, + ?ArrayObject $visitedFragmentNames = null, + ?ArrayObject $astAndDefs = null + ) { + $_visitedFragmentNames = $visitedFragmentNames ?: new ArrayObject(); + $_astAndDefs = $astAndDefs ?: new ArrayObject(); + + foreach ($selectionSet->selections as $selection) { + switch ($selection->kind) { + case NodeKind::FIELD: + /** @var FieldNode $selection */ + $fieldName = $selection->name->value; + $fieldDef = null; + if ($parentType && method_exists($parentType, 'getFields')) { + $tmp = $parentType->getFields(); + $schemaMetaFieldDef = Introspection::schemaMetaFieldDef(); + $typeMetaFieldDef = Introspection::typeMetaFieldDef(); + $typeNameMetaFieldDef = Introspection::typeNameMetaFieldDef(); + + if ($fieldName === $schemaMetaFieldDef->name && $context->getSchema()->getQueryType() === $parentType) { + $fieldDef = $schemaMetaFieldDef; + } elseif ($fieldName === $typeMetaFieldDef->name && $context->getSchema()->getQueryType() === $parentType) { + $fieldDef = $typeMetaFieldDef; + } elseif ($fieldName === $typeNameMetaFieldDef->name) { + $fieldDef = $typeNameMetaFieldDef; + } elseif (isset($tmp[$fieldName])) { + $fieldDef = $tmp[$fieldName]; + } + } + $responseName = $this->getFieldName($selection); + if (! isset($_astAndDefs[$responseName])) { + $_astAndDefs[$responseName] = new ArrayObject(); + } + // create field context + $_astAndDefs[$responseName][] = [$selection, $fieldDef]; + break; + case NodeKind::INLINE_FRAGMENT: + /** @var InlineFragmentNode $selection */ + $_astAndDefs = $this->collectFieldASTsAndDefs( + $context, + TypeInfo::typeFromAST($context->getSchema(), $selection->typeCondition), + $selection->selectionSet, + $_visitedFragmentNames, + $_astAndDefs + ); + break; + case NodeKind::FRAGMENT_SPREAD: + /** @var FragmentSpreadNode $selection */ + $fragName = $selection->name->value; + + if (empty($_visitedFragmentNames[$fragName])) { + $_visitedFragmentNames[$fragName] = true; + $fragment = $context->getFragment($fragName); + + if ($fragment) { + $_astAndDefs = $this->collectFieldASTsAndDefs( + $context, + TypeInfo::typeFromAST($context->getSchema(), $fragment->typeCondition), + $fragment->selectionSet, + $_visitedFragmentNames, + $_astAndDefs + ); + } + } + break; + } + } + + return $_astAndDefs; + } + + protected function getFieldName(FieldNode $node) + { + $fieldName = $node->name->value; + + return $node->alias ? $node->alias->value : $fieldName; + } +} + +class_alias(QuerySecurityRule::class, 'GraphQL\Validator\Rules\AbstractQuerySecurity'); diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/ScalarLeafs.php b/vendor/webonyx/graphql-php/src/Validator/Rules/ScalarLeafs.php new file mode 100644 index 0000000..1bd2515 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/ScalarLeafs.php @@ -0,0 +1,51 @@ + static function (FieldNode $node) use ($context) { + $type = $context->getType(); + if (! $type) { + return; + } + + if (Type::isLeafType(Type::getNamedType($type))) { + if ($node->selectionSet) { + $context->reportError(new Error( + self::noSubselectionAllowedMessage($node->name->value, $type), + [$node->selectionSet] + )); + } + } elseif (! $node->selectionSet) { + $context->reportError(new Error( + self::requiredSubselectionMessage($node->name->value, $type), + [$node] + )); + } + }, + ]; + } + + public static function noSubselectionAllowedMessage($field, $type) + { + return sprintf('Field "%s" of type "%s" must not have a sub selection.', $field, $type); + } + + public static function requiredSubselectionMessage($field, $type) + { + return sprintf('Field "%s" of type "%s" must have a sub selection.', $field, $type); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/UniqueArgumentNames.php b/vendor/webonyx/graphql-php/src/Validator/Rules/UniqueArgumentNames.php new file mode 100644 index 0000000..2e83d43 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/UniqueArgumentNames.php @@ -0,0 +1,51 @@ +knownArgNames = []; + + return [ + NodeKind::FIELD => function () { + $this->knownArgNames = []; + }, + NodeKind::DIRECTIVE => function () { + $this->knownArgNames = []; + }, + NodeKind::ARGUMENT => function (ArgumentNode $node) use ($context) { + $argName = $node->name->value; + if (! empty($this->knownArgNames[$argName])) { + $context->reportError(new Error( + self::duplicateArgMessage($argName), + [$this->knownArgNames[$argName], $node->name] + )); + } else { + $this->knownArgNames[$argName] = $node->name; + } + + return Visitor::skipNode(); + }, + ]; + } + + public static function duplicateArgMessage($argName) + { + return sprintf('There can be only one argument named "%s".', $argName); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/UniqueDirectivesPerLocation.php b/vendor/webonyx/graphql-php/src/Validator/Rules/UniqueDirectivesPerLocation.php new file mode 100644 index 0000000..f0e8c45 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/UniqueDirectivesPerLocation.php @@ -0,0 +1,44 @@ + static function (Node $node) use ($context) { + if (! isset($node->directives)) { + return; + } + + $knownDirectives = []; + foreach ($node->directives as $directive) { + /** @var DirectiveNode $directive */ + $directiveName = $directive->name->value; + if (isset($knownDirectives[$directiveName])) { + $context->reportError(new Error( + self::duplicateDirectiveMessage($directiveName), + [$knownDirectives[$directiveName], $directive] + )); + } else { + $knownDirectives[$directiveName] = $directive; + } + } + }, + ]; + } + + public static function duplicateDirectiveMessage($directiveName) + { + return sprintf('The directive "%s" can only be used once at this location.', $directiveName); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/UniqueFragmentNames.php b/vendor/webonyx/graphql-php/src/Validator/Rules/UniqueFragmentNames.php new file mode 100644 index 0000000..475e6b3 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/UniqueFragmentNames.php @@ -0,0 +1,48 @@ +knownFragmentNames = []; + + return [ + NodeKind::OPERATION_DEFINITION => static function () { + return Visitor::skipNode(); + }, + NodeKind::FRAGMENT_DEFINITION => function (FragmentDefinitionNode $node) use ($context) { + $fragmentName = $node->name->value; + if (empty($this->knownFragmentNames[$fragmentName])) { + $this->knownFragmentNames[$fragmentName] = $node->name; + } else { + $context->reportError(new Error( + self::duplicateFragmentNameMessage($fragmentName), + [$this->knownFragmentNames[$fragmentName], $node->name] + )); + } + + return Visitor::skipNode(); + }, + ]; + } + + public static function duplicateFragmentNameMessage($fragName) + { + return sprintf('There can be only one fragment named "%s".', $fragName); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/UniqueInputFieldNames.php b/vendor/webonyx/graphql-php/src/Validator/Rules/UniqueInputFieldNames.php new file mode 100644 index 0000000..6426b43 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/UniqueInputFieldNames.php @@ -0,0 +1,59 @@ +knownNames = []; + $this->knownNameStack = []; + + return [ + NodeKind::OBJECT => [ + 'enter' => function () { + $this->knownNameStack[] = $this->knownNames; + $this->knownNames = []; + }, + 'leave' => function () { + $this->knownNames = array_pop($this->knownNameStack); + }, + ], + NodeKind::OBJECT_FIELD => function (ObjectFieldNode $node) use ($context) { + $fieldName = $node->name->value; + + if (! empty($this->knownNames[$fieldName])) { + $context->reportError(new Error( + self::duplicateInputFieldMessage($fieldName), + [$this->knownNames[$fieldName], $node->name] + )); + } else { + $this->knownNames[$fieldName] = $node->name; + } + + return Visitor::skipNode(); + }, + ]; + } + + public static function duplicateInputFieldMessage($fieldName) + { + return sprintf('There can be only one input field named "%s".', $fieldName); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/UniqueOperationNames.php b/vendor/webonyx/graphql-php/src/Validator/Rules/UniqueOperationNames.php new file mode 100644 index 0000000..969b90e --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/UniqueOperationNames.php @@ -0,0 +1,51 @@ +knownOperationNames = []; + + return [ + NodeKind::OPERATION_DEFINITION => function (OperationDefinitionNode $node) use ($context) { + $operationName = $node->name; + + if ($operationName) { + if (empty($this->knownOperationNames[$operationName->value])) { + $this->knownOperationNames[$operationName->value] = $operationName; + } else { + $context->reportError(new Error( + self::duplicateOperationNameMessage($operationName->value), + [$this->knownOperationNames[$operationName->value], $operationName] + )); + } + } + + return Visitor::skipNode(); + }, + NodeKind::FRAGMENT_DEFINITION => static function () { + return Visitor::skipNode(); + }, + ]; + } + + public static function duplicateOperationNameMessage($operationName) + { + return sprintf('There can be only one operation named "%s".', $operationName); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/UniqueVariableNames.php b/vendor/webonyx/graphql-php/src/Validator/Rules/UniqueVariableNames.php new file mode 100644 index 0000000..f050a73 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/UniqueVariableNames.php @@ -0,0 +1,45 @@ +knownVariableNames = []; + + return [ + NodeKind::OPERATION_DEFINITION => function () { + $this->knownVariableNames = []; + }, + NodeKind::VARIABLE_DEFINITION => function (VariableDefinitionNode $node) use ($context) { + $variableName = $node->variable->name->value; + if (empty($this->knownVariableNames[$variableName])) { + $this->knownVariableNames[$variableName] = $node->variable->name; + } else { + $context->reportError(new Error( + self::duplicateVariableMessage($variableName), + [$this->knownVariableNames[$variableName], $node->variable->name] + )); + } + }, + ]; + } + + public static function duplicateVariableMessage($variableName) + { + return sprintf('There can be only one variable named "%s".', $variableName); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/ValidationRule.php b/vendor/webonyx/graphql-php/src/Validator/Rules/ValidationRule.php new file mode 100644 index 0000000..fe8504d --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/ValidationRule.php @@ -0,0 +1,35 @@ +name ?: static::class; + } + + public function __invoke(ValidationContext $context) + { + return $this->getVisitor($context); + } + + /** + * Returns structure suitable for GraphQL\Language\Visitor + * + * @see \GraphQL\Language\Visitor + * + * @return mixed[] + */ + abstract public function getVisitor(ValidationContext $context); +} + +class_alias(ValidationRule::class, 'GraphQL\Validator\Rules\AbstractValidationRule'); diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/ValuesOfCorrectType.php b/vendor/webonyx/graphql-php/src/Validator/Rules/ValuesOfCorrectType.php new file mode 100644 index 0000000..4e8199b --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/ValuesOfCorrectType.php @@ -0,0 +1,288 @@ + [ + 'enter' => static function (FieldNode $node) use (&$fieldName) { + $fieldName = $node->name->value; + }, + ], + NodeKind::NULL => static function (NullValueNode $node) use ($context, &$fieldName) { + $type = $context->getInputType(); + if (! ($type instanceof NonNull)) { + return; + } + + $context->reportError( + new Error( + self::getBadValueMessage((string) $type, Printer::doPrint($node), null, $context, $fieldName), + $node + ) + ); + }, + NodeKind::LST => function (ListValueNode $node) use ($context, &$fieldName) { + // Note: TypeInfo will traverse into a list's item type, so look to the + // parent input type to check if it is a list. + $type = Type::getNullableType($context->getParentInputType()); + if (! $type instanceof ListOfType) { + $this->isValidScalar($context, $node, $fieldName); + + return Visitor::skipNode(); + } + }, + NodeKind::OBJECT => function (ObjectValueNode $node) use ($context, &$fieldName) { + // Note: TypeInfo will traverse into a list's item type, so look to the + // parent input type to check if it is a list. + $type = Type::getNamedType($context->getInputType()); + if (! $type instanceof InputObjectType) { + $this->isValidScalar($context, $node, $fieldName); + + return Visitor::skipNode(); + } + unset($fieldName); + // Ensure every required field exists. + $inputFields = $type->getFields(); + $nodeFields = iterator_to_array($node->fields); + $fieldNodeMap = array_combine( + array_map( + static function ($field) { + return $field->name->value; + }, + $nodeFields + ), + array_values($nodeFields) + ); + foreach ($inputFields as $fieldName => $fieldDef) { + $fieldType = $fieldDef->getType(); + if (isset($fieldNodeMap[$fieldName]) || ! ($fieldType instanceof NonNull)) { + continue; + } + + $context->reportError( + new Error( + self::requiredFieldMessage($type->name, $fieldName, (string) $fieldType), + $node + ) + ); + } + }, + NodeKind::OBJECT_FIELD => static function (ObjectFieldNode $node) use ($context) { + $parentType = Type::getNamedType($context->getParentInputType()); + $fieldType = $context->getInputType(); + if ($fieldType || ! ($parentType instanceof InputObjectType)) { + return; + } + + $suggestions = Utils::suggestionList( + $node->name->value, + array_keys($parentType->getFields()) + ); + $didYouMean = $suggestions + ? 'Did you mean ' . Utils::orList($suggestions) . '?' + : null; + + $context->reportError( + new Error( + self::unknownFieldMessage($parentType->name, $node->name->value, $didYouMean), + $node + ) + ); + }, + NodeKind::ENUM => function (EnumValueNode $node) use ($context, &$fieldName) { + $type = Type::getNamedType($context->getInputType()); + if (! $type instanceof EnumType) { + $this->isValidScalar($context, $node, $fieldName); + } elseif (! $type->getValue($node->value)) { + $context->reportError( + new Error( + self::getBadValueMessage( + $type->name, + Printer::doPrint($node), + $this->enumTypeSuggestion($type, $node), + $context, + $fieldName + ), + $node + ) + ); + } + }, + NodeKind::INT => function (IntValueNode $node) use ($context, &$fieldName) { + $this->isValidScalar($context, $node, $fieldName); + }, + NodeKind::FLOAT => function (FloatValueNode $node) use ($context, &$fieldName) { + $this->isValidScalar($context, $node, $fieldName); + }, + NodeKind::STRING => function (StringValueNode $node) use ($context, &$fieldName) { + $this->isValidScalar($context, $node, $fieldName); + }, + NodeKind::BOOLEAN => function (BooleanValueNode $node) use ($context, &$fieldName) { + $this->isValidScalar($context, $node, $fieldName); + }, + ]; + } + + public static function badValueMessage($typeName, $valueName, $message = null) + { + return sprintf('Expected type %s, found %s', $typeName, $valueName) . + ($message ? "; ${message}" : '.'); + } + + private function isValidScalar(ValidationContext $context, ValueNode $node, $fieldName) + { + // Report any error at the full type expected by the location. + $locationType = $context->getInputType(); + + if (! $locationType) { + return; + } + + $type = Type::getNamedType($locationType); + + if (! $type instanceof ScalarType) { + $context->reportError( + new Error( + self::getBadValueMessage( + (string) $locationType, + Printer::doPrint($node), + $this->enumTypeSuggestion($type, $node), + $context, + $fieldName + ), + $node + ) + ); + + return; + } + + // Scalars determine if a literal value is valid via parseLiteral() which + // may throw to indicate failure. + try { + $type->parseLiteral($node); + } catch (Exception $error) { + // Ensure a reference to the original error is maintained. + $context->reportError( + new Error( + self::getBadValueMessage( + (string) $locationType, + Printer::doPrint($node), + $error->getMessage(), + $context, + $fieldName + ), + $node + ) + ); + } catch (Throwable $error) { + // Ensure a reference to the original error is maintained. + $context->reportError( + new Error( + self::getBadValueMessage( + (string) $locationType, + Printer::doPrint($node), + $error->getMessage(), + $context, + $fieldName + ), + $node + ) + ); + } + } + + private function enumTypeSuggestion($type, ValueNode $node) + { + if ($type instanceof EnumType) { + $suggestions = Utils::suggestionList( + Printer::doPrint($node), + array_map( + static function (EnumValueDefinition $value) { + return $value->name; + }, + $type->getValues() + ) + ); + + return $suggestions ? 'Did you mean the enum value ' . Utils::orList($suggestions) . '?' : null; + } + } + + public static function badArgumentValueMessage($typeName, $valueName, $fieldName, $argName, $message = null) + { + return sprintf('Field "%s" argument "%s" requires type %s, found %s', $fieldName, $argName, $typeName, $valueName) . + ($message ? sprintf('; %s', $message) : '.'); + } + + public static function requiredFieldMessage($typeName, $fieldName, $fieldTypeName) + { + return sprintf('Field %s.%s of required type %s was not provided.', $typeName, $fieldName, $fieldTypeName); + } + + public static function unknownFieldMessage($typeName, $fieldName, $message = null) + { + return sprintf('Field "%s" is not defined by type %s', $fieldName, $typeName) . + ($message ? sprintf('; %s', $message) : '.'); + } + + private static function getBadValueMessage($typeName, $valueName, $message = null, $context = null, $fieldName = null) + { + if ($context) { + $arg = $context->getArgument(); + if ($arg) { + return self::badArgumentValueMessage($typeName, $valueName, $fieldName, $arg->name, $message); + } + } + + return self::badValueMessage($typeName, $valueName, $message); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/VariablesAreInputTypes.php b/vendor/webonyx/graphql-php/src/Validator/Rules/VariablesAreInputTypes.php new file mode 100644 index 0000000..5dc27b4 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/VariablesAreInputTypes.php @@ -0,0 +1,42 @@ + static function (VariableDefinitionNode $node) use ($context) { + $type = TypeInfo::typeFromAST($context->getSchema(), $node->type); + + // If the variable type is not an input type, return an error. + if (! $type || Type::isInputType($type)) { + return; + } + + $variableName = $node->variable->name->value; + $context->reportError(new Error( + self::nonInputTypeOnVarMessage($variableName, Printer::doPrint($node->type)), + [$node->type] + )); + }, + ]; + } + + public static function nonInputTypeOnVarMessage($variableName, $typeName) + { + return sprintf('Variable "$%s" cannot be non-input type "%s".', $variableName, $typeName); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/VariablesDefaultValueAllowed.php b/vendor/webonyx/graphql-php/src/Validator/Rules/VariablesDefaultValueAllowed.php new file mode 100644 index 0000000..a19c14d --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/VariablesDefaultValueAllowed.php @@ -0,0 +1,65 @@ + static function (VariableDefinitionNode $node) use ($context) { + $name = $node->variable->name->value; + $defaultValue = $node->defaultValue; + $type = $context->getInputType(); + if ($type instanceof NonNull && $defaultValue) { + $context->reportError( + new Error( + self::defaultForRequiredVarMessage( + $name, + $type, + $type->getWrappedType() + ), + [$defaultValue] + ) + ); + } + + return Visitor::skipNode(); + }, + NodeKind::SELECTION_SET => static function (SelectionSetNode $node) { + return Visitor::skipNode(); + }, + NodeKind::FRAGMENT_DEFINITION => static function (FragmentDefinitionNode $node) { + return Visitor::skipNode(); + }, + ]; + } + + public static function defaultForRequiredVarMessage($varName, $type, $guessType) + { + return sprintf( + 'Variable "$%s" of type "%s" is required and will not use the default value. Perhaps you meant to use type "%s".', + $varName, + $type, + $guessType + ); + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/Rules/VariablesInAllowedPosition.php b/vendor/webonyx/graphql-php/src/Validator/Rules/VariablesInAllowedPosition.php new file mode 100644 index 0000000..2deb0e9 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/Rules/VariablesInAllowedPosition.php @@ -0,0 +1,112 @@ + [ + 'enter' => function () { + $this->varDefMap = []; + }, + 'leave' => function (OperationDefinitionNode $operation) use ($context) { + $usages = $context->getRecursiveVariableUsages($operation); + + foreach ($usages as $usage) { + $node = $usage['node']; + $type = $usage['type']; + $varName = $node->name->value; + $varDef = $this->varDefMap[$varName] ?? null; + + if ($varDef === null || $type === null) { + continue; + } + + // A var type is allowed if it is the same or more strict (e.g. is + // a subtype of) than the expected type. It can be more strict if + // the variable type is non-null when the expected type is nullable. + // If both are list types, the variable item type can be more strict + // than the expected item type (contravariant). + $schema = $context->getSchema(); + $varType = TypeInfo::typeFromAST($schema, $varDef->type); + + if (! $varType || TypeComparators::isTypeSubTypeOf( + $schema, + $this->effectiveType($varType, $varDef), + $type + )) { + continue; + } + + $context->reportError(new Error( + self::badVarPosMessage($varName, $varType, $type), + [$varDef, $node] + )); + } + }, + ], + NodeKind::VARIABLE_DEFINITION => function (VariableDefinitionNode $varDefNode) { + $this->varDefMap[$varDefNode->variable->name->value] = $varDefNode; + }, + ]; + } + + private function effectiveType($varType, $varDef) + { + return ! $varDef->defaultValue || $varType instanceof NonNull ? $varType : new NonNull($varType); + } + + /** + * A var type is allowed if it is the same or more strict than the expected + * type. It can be more strict if the variable type is non-null when the + * expected type is nullable. If both are list types, the variable item type can + * be more strict than the expected item type. + */ + public static function badVarPosMessage($varName, $varType, $expectedType) + { + return sprintf( + 'Variable "$%s" of type "%s" used in position expecting type "%s".', + $varName, + $varType, + $expectedType + ); + } + + /** If a variable definition has a default value, it's effectively non-null. */ + private function varTypeAllowedForType($varType, $expectedType) + { + if ($expectedType instanceof NonNull) { + if ($varType instanceof NonNull) { + return $this->varTypeAllowedForType($varType->getWrappedType(), $expectedType->getWrappedType()); + } + + return false; + } + if ($varType instanceof NonNull) { + return $this->varTypeAllowedForType($varType->getWrappedType(), $expectedType); + } + if ($varType instanceof ListOfType && $expectedType instanceof ListOfType) { + return $this->varTypeAllowedForType($varType->getWrappedType(), $expectedType->getWrappedType()); + } + + return $varType === $expectedType; + } +} diff --git a/vendor/webonyx/graphql-php/src/Validator/ValidationContext.php b/vendor/webonyx/graphql-php/src/Validator/ValidationContext.php new file mode 100644 index 0000000..7163371 --- /dev/null +++ b/vendor/webonyx/graphql-php/src/Validator/ValidationContext.php @@ -0,0 +1,297 @@ +schema = $schema; + $this->ast = $ast; + $this->typeInfo = $typeInfo; + $this->errors = []; + $this->fragmentSpreads = new SplObjectStorage(); + $this->recursivelyReferencedFragments = new SplObjectStorage(); + $this->variableUsages = new SplObjectStorage(); + $this->recursiveVariableUsages = new SplObjectStorage(); + } + + public function reportError(Error $error) + { + $this->errors[] = $error; + } + + /** + * @return Error[] + */ + public function getErrors() + { + return $this->errors; + } + + /** + * @return Schema + */ + public function getSchema() + { + return $this->schema; + } + + /** + * @return mixed[][] List of ['node' => VariableNode, 'type' => ?InputObjectType] + */ + public function getRecursiveVariableUsages(OperationDefinitionNode $operation) + { + $usages = $this->recursiveVariableUsages[$operation] ?? null; + + if ($usages === null) { + $usages = $this->getVariableUsages($operation); + $fragments = $this->getRecursivelyReferencedFragments($operation); + + $tmp = [$usages]; + foreach ($fragments as $i => $fragment) { + $tmp[] = $this->getVariableUsages($fragments[$i]); + } + $usages = call_user_func_array('array_merge', $tmp); + $this->recursiveVariableUsages[$operation] = $usages; + } + + return $usages; + } + + /** + * @return mixed[][] List of ['node' => VariableNode, 'type' => ?InputObjectType] + */ + private function getVariableUsages(HasSelectionSet $node) + { + $usages = $this->variableUsages[$node] ?? null; + + if ($usages === null) { + $newUsages = []; + $typeInfo = new TypeInfo($this->schema); + Visitor::visit( + $node, + Visitor::visitWithTypeInfo( + $typeInfo, + [ + NodeKind::VARIABLE_DEFINITION => static function () { + return false; + }, + NodeKind::VARIABLE => static function (VariableNode $variable) use ( + &$newUsages, + $typeInfo + ) { + $newUsages[] = ['node' => $variable, 'type' => $typeInfo->getInputType()]; + }, + ] + ) + ); + $usages = $newUsages; + $this->variableUsages[$node] = $usages; + } + + return $usages; + } + + /** + * @return FragmentDefinitionNode[] + */ + public function getRecursivelyReferencedFragments(OperationDefinitionNode $operation) + { + $fragments = $this->recursivelyReferencedFragments[$operation] ?? null; + + if ($fragments === null) { + $fragments = []; + $collectedNames = []; + $nodesToVisit = [$operation]; + while (! empty($nodesToVisit)) { + $node = array_pop($nodesToVisit); + $spreads = $this->getFragmentSpreads($node); + foreach ($spreads as $spread) { + $fragName = $spread->name->value; + + if (! empty($collectedNames[$fragName])) { + continue; + } + + $collectedNames[$fragName] = true; + $fragment = $this->getFragment($fragName); + if (! $fragment) { + continue; + } + + $fragments[] = $fragment; + $nodesToVisit[] = $fragment; + } + } + $this->recursivelyReferencedFragments[$operation] = $fragments; + } + + return $fragments; + } + + /** + * @return FragmentSpreadNode[] + */ + public function getFragmentSpreads(HasSelectionSet $node) + { + $spreads = $this->fragmentSpreads[$node] ?? null; + if ($spreads === null) { + $spreads = []; + /** @var SelectionSetNode[] $setsToVisit */ + $setsToVisit = [$node->selectionSet]; + while (! empty($setsToVisit)) { + $set = array_pop($setsToVisit); + + for ($i = 0, $selectionCount = count($set->selections); $i < $selectionCount; $i++) { + $selection = $set->selections[$i]; + if ($selection->kind === NodeKind::FRAGMENT_SPREAD) { + $spreads[] = $selection; + } elseif ($selection->selectionSet) { + $setsToVisit[] = $selection->selectionSet; + } + } + } + $this->fragmentSpreads[$node] = $spreads; + } + + return $spreads; + } + + /** + * @param string $name + * + * @return FragmentDefinitionNode|null + */ + public function getFragment($name) + { + $fragments = $this->fragments; + if (! $fragments) { + $fragments = []; + foreach ($this->getDocument()->definitions as $statement) { + if ($statement->kind !== NodeKind::FRAGMENT_DEFINITION) { + continue; + } + + $fragments[$statement->name->value] = $statement; + } + $this->fragments = $fragments; + } + + return $fragments[$name] ?? null; + } + + /** + * @return DocumentNode + */ + public function getDocument() + { + return $this->ast; + } + + /** + * Returns OutputType + * + * @return Type + */ + public function getType() + { + return $this->typeInfo->getType(); + } + + /** + * @return Type + */ + public function getParentType() + { + return $this->typeInfo->getParentType(); + } + + /** + * @return InputType + */ + public function getInputType() + { + return $this->typeInfo->getInputType(); + } + + /** + * @return InputType + */ + public function getParentInputType() + { + return $this->typeInfo->getParentInputType(); + } + + /** + * @return FieldDefinition + */ + public function getFieldDef() + { + return $this->typeInfo->getFieldDef(); + } + + public function getDirective() + { + return $this->typeInfo->getDirective(); + } + + public function getArgument() + { + return $this->typeInfo->getArgument(); + } +}