graphql-jit 0.9.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,7 +11,7 @@ import { queryToJSONSchema } from "./json.js";
11
11
  import { createNullTrimmer } from "./non-null.js";
12
12
  import { createResolveInfoThunk } from "./resolve-info.js";
13
13
  import { compileVariableParsing, failToParseVariables } from "./variables.js";
14
- import { getGraphQLErrorOptions, getOperationRootType } from "./compat.js";
14
+ import { coerceOutputValue, getGraphQLErrorOptions, getOperationRootType } from "./compat.js";
15
15
  const inspect = createInspect();
16
16
  // prefix for the variable used ot cache validation results
17
17
  const SAFETY_CHECK_PREFIX = "__validNode";
@@ -114,7 +114,7 @@ export function isCompiledQuery(query) {
114
114
  }
115
115
  // Exported only for an error test
116
116
  export function createBoundQuery(compilationContext, document, func, getVariableValues, operationName) {
117
- const { resolvers, typeResolvers, isTypeOfs, serializers, resolveInfos } = compilationContext;
117
+ const { resolvers, typeResolvers, isTypeOfs, serializers, resolveInfos, literals } = compilationContext;
118
118
  const trimmer = createNullTrimmer(compilationContext);
119
119
  const fnName = operationName || "query";
120
120
  /**
@@ -146,6 +146,7 @@ export function createBoundQuery(compilationContext, document, func, getVariable
146
146
  isTypeOfs,
147
147
  serializers,
148
148
  resolveInfos,
149
+ literals,
149
150
  trimmer,
150
151
  rt: jitRuntime,
151
152
  promiseCounter: 0,
@@ -703,31 +704,71 @@ function compileListType(context, parentType, type, fieldNodes, originalObjectPa
703
704
  return `(typeof ${name} === "string" || typeof ${name}[Symbol.iterator] !== "function") ? ${errorCase} :
704
705
  ${GLOBAL_SAFE_MAP_NAME}(${GLOBAL_EXECUTION_CONTEXT}, ${name}, ${safeMapHandler}, ${parentIndexes})`;
705
706
  }
706
- const MAGIC_MINUS_INFINITY = "__MAGIC_MINUS_INFINITY__71d4310a_d4a3_4a05_b1fe_e60779d24998";
707
- const MAGIC_PLUS_INFINITY = "__MAGIC_PLUS_INFINITY__bb201c39_3333_4695_b4ad_7f1722e7aa7a";
708
- const MAGIC_NAN = "__MAGIC_NAN__57f286b9_4c20_487f_b409_79804ddcb4f8";
709
- const MAGIC_DATE = "__MAGIC_DATE__33a9e76d_02e0_4128_8e92_3530ad3da74d";
710
- function specialValueReplacer(key, value) {
711
- if (Number.isNaN(value)) {
712
- return MAGIC_NAN;
707
+ /**
708
+ * Whether the value cannot be written into source as a literal: a bigint,
709
+ * symbol, function, or any object other than a plain object, array or Date.
710
+ */
711
+ function isUnserializable(value) {
712
+ switch (typeof value) {
713
+ case "bigint":
714
+ case "symbol":
715
+ case "function":
716
+ return true;
717
+ case "object": {
718
+ if (value === null) {
719
+ return false;
720
+ }
721
+ const proto = Object.getPrototypeOf(value);
722
+ if (Array.isArray(value)) {
723
+ return proto !== Array.prototype;
724
+ }
725
+ if (value instanceof Date) {
726
+ return proto !== Date.prototype;
727
+ }
728
+ return proto !== null && proto !== Object.prototype;
729
+ }
730
+ default:
731
+ return false;
732
+ }
733
+ }
734
+ /**
735
+ * Serializes an argument value to a JS expression. Unserializable values are
736
+ * stored via `hoist` and referenced from `context.literals`.
737
+ */
738
+ function objectStringify(val, hoist) {
739
+ if (isUnserializable(val)) {
740
+ return `${GLOBAL_EXECUTION_CONTEXT}.literals.${hoist(val)}`;
713
741
  }
714
- if (value === Infinity) {
715
- return MAGIC_PLUS_INFINITY;
742
+ if (typeof val === "number") {
743
+ // JSON.stringify would turn NaN/Infinity into null
744
+ return Number.isFinite(val) ? JSON.stringify(val) : String(val);
716
745
  }
717
- if (value === -Infinity) {
718
- return MAGIC_MINUS_INFINITY;
746
+ if (val === undefined) {
747
+ return "undefined";
719
748
  }
720
- if (this[key] instanceof Date) {
721
- return MAGIC_DATE + this[key].getTime();
749
+ if (val === null || typeof val !== "object") {
750
+ return JSON.stringify(val);
722
751
  }
723
- return value;
724
- }
725
- function objectStringify(val) {
726
- return JSON.stringify(val, specialValueReplacer)
727
- .replace(new RegExp(`"${MAGIC_NAN}"`, "g"), "NaN")
728
- .replace(new RegExp(`"${MAGIC_PLUS_INFINITY}"`, "g"), "Infinity")
729
- .replace(new RegExp(`"${MAGIC_MINUS_INFINITY}"`, "g"), "-Infinity")
730
- .replace(new RegExp(`"${MAGIC_DATE}([^"]+)"`, "g"), "new Date($1)");
752
+ if (val instanceof Date) {
753
+ return `new Date(${val.getTime()})`;
754
+ }
755
+ if (Array.isArray(val)) {
756
+ const items = [];
757
+ for (let i = 0; i < val.length; ++i) {
758
+ items.push(i in val ? objectStringify(val[i], hoist) : "null");
759
+ }
760
+ return `[${items.join(",")}]`;
761
+ }
762
+ const props = [];
763
+ for (const key of Object.keys(val)) {
764
+ if (val[key] === undefined) {
765
+ continue;
766
+ }
767
+ // a computed key stops "__proto__" from setting the prototype
768
+ const name = JSON.stringify(key);
769
+ props.push(`${key === "__proto__" ? `[${name}]` : name}:${objectStringify(val[key], hoist)}`);
770
+ }
771
+ return `{${props.join(",")}}`;
731
772
  }
732
773
  /**
733
774
  * Calculates a GraphQLResolveInfo object for the resolver calls.
@@ -792,7 +833,11 @@ function compileArguments(context, args, topLevelArg, validArgs, returnType, pat
792
833
  // default to assuming arguments are valid
793
834
  let body = `
794
835
  let ${validArgs} = true;
795
- const ${topLevelArg} = ${objectStringify(args.values)};
836
+ const ${topLevelArg} = ${objectStringify(args.values, (value) => {
837
+ const key = `literal${Object.keys(context.literals).length}`;
838
+ context.literals[key] = value;
839
+ return key;
840
+ })};
796
841
  `;
797
842
  const errorDestination = getErrorDestination(returnType);
798
843
  for (const variable of args.missing) {
@@ -906,7 +951,7 @@ function serializeResponsePath(path) {
906
951
  */
907
952
  function getSerializer(scalar, customSerializer) {
908
953
  const { name } = scalar;
909
- const serialize = customSerializer || ((val) => scalar.serialize(val));
954
+ const serialize = customSerializer || ((val) => coerceOutputValue(scalar, val));
910
955
  return function leafSerializer(context, v, onError, ...idx) {
911
956
  try {
912
957
  const value = serialize(v);
@@ -1006,6 +1051,7 @@ export function buildCompilationContext(schema, document, options, operationName
1006
1051
  typeResolvers: {},
1007
1052
  isTypeOfs: {},
1008
1053
  resolveInfos: {},
1054
+ literals: {},
1009
1055
  hoistedFunctions: [],
1010
1056
  hoistedFunctionNames: new Map(),
1011
1057
  leafErrHandlerCache: new Map(),
@@ -1139,7 +1185,7 @@ function compileSubscriptionOperation(context, type, fieldMap, queryFn) {
1139
1185
  };
1140
1186
  }
1141
1187
  function createBoundSubscribe(compilationContext, document, func, getVariableValues, operationName) {
1142
- const { resolvers, typeResolvers, isTypeOfs, serializers, resolveInfos } = compilationContext;
1188
+ const { resolvers, typeResolvers, isTypeOfs, serializers, resolveInfos, literals } = compilationContext;
1143
1189
  const trimmer = createNullTrimmer(compilationContext);
1144
1190
  const fnName = operationName || "subscribe";
1145
1191
  const ret = {
@@ -1161,6 +1207,7 @@ function createBoundSubscribe(compilationContext, document, func, getVariableVal
1161
1207
  isTypeOfs,
1162
1208
  serializers,
1163
1209
  resolveInfos,
1210
+ literals,
1164
1211
  trimmer,
1165
1212
  rt: jitRuntime,
1166
1213
  promiseCounter: 0,