@graphql-tools/utils 8.6.7 → 8.6.10

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.
Files changed (3) hide show
  1. package/index.js +107 -139
  2. package/index.mjs +107 -139
  3. package/package.json +2 -2
package/index.js CHANGED
@@ -3220,155 +3220,123 @@ function addTypes(schema, newTypesOrDirectives) {
3220
3220
  * @param options Additional options for removing unused types from the schema
3221
3221
  */
3222
3222
  function pruneSchema(schema, options = {}) {
3223
- const pruningContext = createPruningContext(schema);
3224
- visitTypes(pruningContext);
3225
- const types = Object.values(schema.getTypeMap());
3226
- const typesToPrune = new Set();
3227
- for (const type of types) {
3228
- if (type.name.startsWith('__')) {
3229
- continue;
3230
- }
3231
- // If we should NOT prune the type, return it immediately as unmodified
3232
- if (options.skipPruning && options.skipPruning(type)) {
3233
- continue;
3234
- }
3235
- if (graphql.isObjectType(type) || graphql.isInputObjectType(type)) {
3236
- if ((!Object.keys(type.getFields()).length && !options.skipEmptyCompositeTypePruning) ||
3237
- (pruningContext.unusedTypes[type.name] && !options.skipUnusedTypesPruning)) {
3238
- typesToPrune.add(type.name);
3239
- }
3240
- }
3241
- else if (graphql.isUnionType(type)) {
3242
- if ((!type.getTypes().length && !options.skipEmptyUnionPruning) ||
3243
- (pruningContext.unusedTypes[type.name] && !options.skipUnusedTypesPruning)) {
3244
- typesToPrune.add(type.name);
3245
- }
3246
- }
3247
- else if (graphql.isInterfaceType(type)) {
3248
- const implementations = getImplementations(pruningContext, type);
3249
- if ((!Object.keys(type.getFields()).length && !options.skipEmptyCompositeTypePruning) ||
3250
- (implementations && !Object.keys(implementations).length && !options.skipUnimplementedInterfacesPruning) ||
3251
- (pruningContext.unusedTypes[type.name] && !options.skipUnusedTypesPruning)) {
3252
- typesToPrune.add(type.name);
3223
+ const { skipEmptyCompositeTypePruning, skipEmptyUnionPruning, skipPruning, skipUnimplementedInterfacesPruning, skipUnusedTypesPruning, } = options;
3224
+ let prunedTypes = []; // Pruned types during mapping
3225
+ let prunedSchema = schema;
3226
+ do {
3227
+ let visited = visitSchema(prunedSchema);
3228
+ // Custom pruning was defined, so we need to pre-emptively revisit the schema accounting for this
3229
+ if (skipPruning) {
3230
+ const revisit = [];
3231
+ for (const typeName in prunedSchema.getTypeMap()) {
3232
+ if (typeName.startsWith('__')) {
3233
+ continue;
3234
+ }
3235
+ const type = prunedSchema.getType(typeName);
3236
+ // if we want to skip pruning for this type, add it to the list of types to revisit
3237
+ if (type && skipPruning(type)) {
3238
+ revisit.push(typeName);
3239
+ }
3253
3240
  }
3241
+ visited = visitQueue(revisit, prunedSchema, visited); // visit again
3242
+ }
3243
+ prunedTypes = [];
3244
+ prunedSchema = mapSchema(prunedSchema, {
3245
+ [exports.MapperKind.TYPE]: type => {
3246
+ if (!visited.has(type.name) && !graphql.isSpecifiedScalarType(type)) {
3247
+ if (graphql.isUnionType(type) ||
3248
+ graphql.isInputObjectType(type) ||
3249
+ graphql.isInterfaceType(type) ||
3250
+ graphql.isObjectType(type) ||
3251
+ graphql.isScalarType(type)) {
3252
+ // skipUnusedTypesPruning: skip pruning unused types
3253
+ if (skipUnusedTypesPruning) {
3254
+ return type;
3255
+ }
3256
+ // skipEmptyUnionPruning: skip pruning empty unions
3257
+ if (graphql.isUnionType(type) && skipEmptyUnionPruning && !Object.keys(type.getTypes()).length) {
3258
+ return type;
3259
+ }
3260
+ if (graphql.isInputObjectType(type) || graphql.isInterfaceType(type) || graphql.isObjectType(type)) {
3261
+ // skipEmptyCompositeTypePruning: skip pruning object types or interfaces with no fields
3262
+ if (skipEmptyCompositeTypePruning && !Object.keys(type.getFields()).length) {
3263
+ return type;
3264
+ }
3265
+ }
3266
+ // skipUnimplementedInterfacesPruning: skip pruning interfaces that are not implemented by any other types
3267
+ if (graphql.isInterfaceType(type) && skipUnimplementedInterfacesPruning) {
3268
+ return type;
3269
+ }
3270
+ }
3271
+ prunedTypes.push(type.name);
3272
+ visited.delete(type.name);
3273
+ return null;
3274
+ }
3275
+ return type;
3276
+ },
3277
+ });
3278
+ } while (prunedTypes.length); // Might have empty types and need to prune again
3279
+ return prunedSchema;
3280
+ }
3281
+ function visitSchema(schema) {
3282
+ const queue = []; // queue of nodes to visit
3283
+ // Grab the root types and start there
3284
+ for (const type of getRootTypes(schema)) {
3285
+ queue.push(type.name);
3286
+ }
3287
+ return visitQueue(queue, schema);
3288
+ }
3289
+ function visitQueue(queue, schema, visited = new Set()) {
3290
+ // Interfaces encountered that are field return types need to be revisited to add their implementations
3291
+ const revisit = new Map();
3292
+ // Navigate all types starting with pre-queued types (root types)
3293
+ while (queue.length) {
3294
+ const typeName = queue.pop();
3295
+ // Skip types we already visited unless it is an interface type that needs revisiting
3296
+ if (visited.has(typeName) && revisit[typeName] !== true) {
3297
+ continue;
3254
3298
  }
3255
- else {
3256
- if (pruningContext.unusedTypes[type.name] && !options.skipUnusedTypesPruning) {
3257
- typesToPrune.add(type.name);
3299
+ const type = schema.getType(typeName);
3300
+ if (type) {
3301
+ // Get types for union
3302
+ if (graphql.isUnionType(type)) {
3303
+ queue.push(...type.getTypes().map(type => type.name));
3258
3304
  }
3259
- }
3260
- }
3261
- // TODO: consider not returning a new schema if there was nothing to prune. This would be a breaking change.
3262
- const prunedSchema = mapSchema(schema, {
3263
- [exports.MapperKind.TYPE]: (type) => {
3264
- if (typesToPrune.has(type.name)) {
3265
- return null;
3305
+ // If it is an interface and it is a returned type, grab all implementations so we can use proper __typename in fragments
3306
+ if (graphql.isInterfaceType(type) && revisit[typeName] === true) {
3307
+ queue.push(...getImplementingTypes(type.name, schema));
3308
+ // No need to revisit this interface again
3309
+ revisit[typeName] = false;
3266
3310
  }
3267
- },
3268
- });
3269
- // if we pruned something, we need to prune again in case there are now objects without fields
3270
- return typesToPrune.size ? pruneSchema(prunedSchema, options) : prunedSchema;
3271
- }
3272
- function visitOutputType(visitedTypes, pruningContext, type) {
3273
- if (visitedTypes[type.name]) {
3274
- return;
3275
- }
3276
- visitedTypes[type.name] = true;
3277
- pruningContext.unusedTypes[type.name] = false;
3278
- if (graphql.isObjectType(type) || graphql.isInterfaceType(type)) {
3279
- const fields = type.getFields();
3280
- for (const fieldName in fields) {
3281
- const field = fields[fieldName];
3282
- const namedType = graphql.getNamedType(field.type);
3283
- visitOutputType(visitedTypes, pruningContext, namedType);
3284
- for (const arg of field.args) {
3285
- const type = graphql.getNamedType(arg.type);
3286
- visitInputType(visitedTypes, pruningContext, type);
3311
+ // Visit interfaces this type is implementing if they haven't been visited yet
3312
+ if ('getInterfaces' in type) {
3313
+ // Only pushes to queue to visit but not return types
3314
+ queue.push(...type.getInterfaces().map(iface => iface.name));
3287
3315
  }
3288
- }
3289
- if (graphql.isInterfaceType(type)) {
3290
- const implementations = getImplementations(pruningContext, type);
3291
- if (implementations) {
3292
- for (const typeName in implementations) {
3293
- visitOutputType(visitedTypes, pruningContext, pruningContext.schema.getType(typeName));
3316
+ // If the type has files visit those field types
3317
+ if ('getFields' in type) {
3318
+ const fields = type.getFields();
3319
+ const entries = Object.entries(fields);
3320
+ if (!entries.length) {
3321
+ continue;
3294
3322
  }
3295
- }
3296
- }
3297
- if ('getInterfaces' in type) {
3298
- for (const iFace of type.getInterfaces()) {
3299
- visitOutputType(visitedTypes, pruningContext, iFace);
3300
- }
3301
- }
3302
- }
3303
- else if (graphql.isUnionType(type)) {
3304
- const types = type.getTypes();
3305
- for (const type of types) {
3306
- visitOutputType(visitedTypes, pruningContext, type);
3307
- }
3308
- }
3309
- }
3310
- /**
3311
- * Initialize a pruneContext given a schema.
3312
- */
3313
- function createPruningContext(schema) {
3314
- const pruningContext = {
3315
- schema,
3316
- unusedTypes: Object.create(null),
3317
- implementations: Object.create(null),
3318
- };
3319
- for (const typeName in schema.getTypeMap()) {
3320
- const type = schema.getType(typeName);
3321
- if (type && 'getInterfaces' in type) {
3322
- for (const iface of type.getInterfaces()) {
3323
- const implementations = getImplementations(pruningContext, iface);
3324
- if (implementations == null) {
3325
- pruningContext.implementations[iface.name] = Object.create(null);
3323
+ for (const [, field] of entries) {
3324
+ if (graphql.isObjectType(type)) {
3325
+ // Visit arg types
3326
+ queue.push(...field.args.map(arg => graphql.getNamedType(arg.type).name));
3327
+ }
3328
+ const namedType = graphql.getNamedType(field.type);
3329
+ queue.push(namedType.name);
3330
+ // Interfaces returned on fields need to be revisited to add their implementations
3331
+ if (graphql.isInterfaceType(namedType) && !(namedType.name in revisit)) {
3332
+ revisit[namedType.name] = true;
3333
+ }
3326
3334
  }
3327
- pruningContext.implementations[iface.name][type.name] = true;
3328
3335
  }
3336
+ visited.add(typeName); // Mark as visited (and therefore it is used and should be kept)
3329
3337
  }
3330
3338
  }
3331
- return pruningContext;
3332
- }
3333
- /**
3334
- * Get the implementations of an interface. May return undefined.
3335
- */
3336
- function getImplementations(pruningContext, type) {
3337
- return pruningContext.implementations[type.name];
3338
- }
3339
- function visitInputType(visitedTypes, pruningContext, type) {
3340
- if (visitedTypes[type.name]) {
3341
- return;
3342
- }
3343
- pruningContext.unusedTypes[type.name] = false;
3344
- visitedTypes[type.name] = true;
3345
- if (graphql.isInputObjectType(type)) {
3346
- const fields = type.getFields();
3347
- for (const fieldName in fields) {
3348
- const field = fields[fieldName];
3349
- const namedType = graphql.getNamedType(field.type);
3350
- visitInputType(visitedTypes, pruningContext, namedType);
3351
- }
3352
- }
3353
- }
3354
- function visitTypes(pruningContext) {
3355
- const schema = pruningContext.schema;
3356
- for (const typeName in schema.getTypeMap()) {
3357
- if (!typeName.startsWith('__')) {
3358
- pruningContext.unusedTypes[typeName] = true;
3359
- }
3360
- }
3361
- const visitedTypes = Object.create(null);
3362
- const rootTypes = getRootTypes(schema);
3363
- for (const rootType of rootTypes) {
3364
- visitOutputType(visitedTypes, pruningContext, rootType);
3365
- }
3366
- for (const directive of schema.getDirectives()) {
3367
- for (const arg of directive.args) {
3368
- const type = graphql.getNamedType(arg.type);
3369
- visitInputType(visitedTypes, pruningContext, type);
3370
- }
3371
- }
3339
+ return visited;
3372
3340
  }
3373
3341
 
3374
3342
  function mergeDeep(sources, respectPrototype = false) {
package/index.mjs CHANGED
@@ -3218,155 +3218,123 @@ function addTypes(schema, newTypesOrDirectives) {
3218
3218
  * @param options Additional options for removing unused types from the schema
3219
3219
  */
3220
3220
  function pruneSchema(schema, options = {}) {
3221
- const pruningContext = createPruningContext(schema);
3222
- visitTypes(pruningContext);
3223
- const types = Object.values(schema.getTypeMap());
3224
- const typesToPrune = new Set();
3225
- for (const type of types) {
3226
- if (type.name.startsWith('__')) {
3227
- continue;
3228
- }
3229
- // If we should NOT prune the type, return it immediately as unmodified
3230
- if (options.skipPruning && options.skipPruning(type)) {
3231
- continue;
3232
- }
3233
- if (isObjectType(type) || isInputObjectType(type)) {
3234
- if ((!Object.keys(type.getFields()).length && !options.skipEmptyCompositeTypePruning) ||
3235
- (pruningContext.unusedTypes[type.name] && !options.skipUnusedTypesPruning)) {
3236
- typesToPrune.add(type.name);
3237
- }
3238
- }
3239
- else if (isUnionType(type)) {
3240
- if ((!type.getTypes().length && !options.skipEmptyUnionPruning) ||
3241
- (pruningContext.unusedTypes[type.name] && !options.skipUnusedTypesPruning)) {
3242
- typesToPrune.add(type.name);
3243
- }
3244
- }
3245
- else if (isInterfaceType(type)) {
3246
- const implementations = getImplementations(pruningContext, type);
3247
- if ((!Object.keys(type.getFields()).length && !options.skipEmptyCompositeTypePruning) ||
3248
- (implementations && !Object.keys(implementations).length && !options.skipUnimplementedInterfacesPruning) ||
3249
- (pruningContext.unusedTypes[type.name] && !options.skipUnusedTypesPruning)) {
3250
- typesToPrune.add(type.name);
3221
+ const { skipEmptyCompositeTypePruning, skipEmptyUnionPruning, skipPruning, skipUnimplementedInterfacesPruning, skipUnusedTypesPruning, } = options;
3222
+ let prunedTypes = []; // Pruned types during mapping
3223
+ let prunedSchema = schema;
3224
+ do {
3225
+ let visited = visitSchema(prunedSchema);
3226
+ // Custom pruning was defined, so we need to pre-emptively revisit the schema accounting for this
3227
+ if (skipPruning) {
3228
+ const revisit = [];
3229
+ for (const typeName in prunedSchema.getTypeMap()) {
3230
+ if (typeName.startsWith('__')) {
3231
+ continue;
3232
+ }
3233
+ const type = prunedSchema.getType(typeName);
3234
+ // if we want to skip pruning for this type, add it to the list of types to revisit
3235
+ if (type && skipPruning(type)) {
3236
+ revisit.push(typeName);
3237
+ }
3251
3238
  }
3239
+ visited = visitQueue(revisit, prunedSchema, visited); // visit again
3240
+ }
3241
+ prunedTypes = [];
3242
+ prunedSchema = mapSchema(prunedSchema, {
3243
+ [MapperKind.TYPE]: type => {
3244
+ if (!visited.has(type.name) && !isSpecifiedScalarType(type)) {
3245
+ if (isUnionType(type) ||
3246
+ isInputObjectType(type) ||
3247
+ isInterfaceType(type) ||
3248
+ isObjectType(type) ||
3249
+ isScalarType(type)) {
3250
+ // skipUnusedTypesPruning: skip pruning unused types
3251
+ if (skipUnusedTypesPruning) {
3252
+ return type;
3253
+ }
3254
+ // skipEmptyUnionPruning: skip pruning empty unions
3255
+ if (isUnionType(type) && skipEmptyUnionPruning && !Object.keys(type.getTypes()).length) {
3256
+ return type;
3257
+ }
3258
+ if (isInputObjectType(type) || isInterfaceType(type) || isObjectType(type)) {
3259
+ // skipEmptyCompositeTypePruning: skip pruning object types or interfaces with no fields
3260
+ if (skipEmptyCompositeTypePruning && !Object.keys(type.getFields()).length) {
3261
+ return type;
3262
+ }
3263
+ }
3264
+ // skipUnimplementedInterfacesPruning: skip pruning interfaces that are not implemented by any other types
3265
+ if (isInterfaceType(type) && skipUnimplementedInterfacesPruning) {
3266
+ return type;
3267
+ }
3268
+ }
3269
+ prunedTypes.push(type.name);
3270
+ visited.delete(type.name);
3271
+ return null;
3272
+ }
3273
+ return type;
3274
+ },
3275
+ });
3276
+ } while (prunedTypes.length); // Might have empty types and need to prune again
3277
+ return prunedSchema;
3278
+ }
3279
+ function visitSchema(schema) {
3280
+ const queue = []; // queue of nodes to visit
3281
+ // Grab the root types and start there
3282
+ for (const type of getRootTypes(schema)) {
3283
+ queue.push(type.name);
3284
+ }
3285
+ return visitQueue(queue, schema);
3286
+ }
3287
+ function visitQueue(queue, schema, visited = new Set()) {
3288
+ // Interfaces encountered that are field return types need to be revisited to add their implementations
3289
+ const revisit = new Map();
3290
+ // Navigate all types starting with pre-queued types (root types)
3291
+ while (queue.length) {
3292
+ const typeName = queue.pop();
3293
+ // Skip types we already visited unless it is an interface type that needs revisiting
3294
+ if (visited.has(typeName) && revisit[typeName] !== true) {
3295
+ continue;
3252
3296
  }
3253
- else {
3254
- if (pruningContext.unusedTypes[type.name] && !options.skipUnusedTypesPruning) {
3255
- typesToPrune.add(type.name);
3297
+ const type = schema.getType(typeName);
3298
+ if (type) {
3299
+ // Get types for union
3300
+ if (isUnionType(type)) {
3301
+ queue.push(...type.getTypes().map(type => type.name));
3256
3302
  }
3257
- }
3258
- }
3259
- // TODO: consider not returning a new schema if there was nothing to prune. This would be a breaking change.
3260
- const prunedSchema = mapSchema(schema, {
3261
- [MapperKind.TYPE]: (type) => {
3262
- if (typesToPrune.has(type.name)) {
3263
- return null;
3303
+ // If it is an interface and it is a returned type, grab all implementations so we can use proper __typename in fragments
3304
+ if (isInterfaceType(type) && revisit[typeName] === true) {
3305
+ queue.push(...getImplementingTypes(type.name, schema));
3306
+ // No need to revisit this interface again
3307
+ revisit[typeName] = false;
3264
3308
  }
3265
- },
3266
- });
3267
- // if we pruned something, we need to prune again in case there are now objects without fields
3268
- return typesToPrune.size ? pruneSchema(prunedSchema, options) : prunedSchema;
3269
- }
3270
- function visitOutputType(visitedTypes, pruningContext, type) {
3271
- if (visitedTypes[type.name]) {
3272
- return;
3273
- }
3274
- visitedTypes[type.name] = true;
3275
- pruningContext.unusedTypes[type.name] = false;
3276
- if (isObjectType(type) || isInterfaceType(type)) {
3277
- const fields = type.getFields();
3278
- for (const fieldName in fields) {
3279
- const field = fields[fieldName];
3280
- const namedType = getNamedType(field.type);
3281
- visitOutputType(visitedTypes, pruningContext, namedType);
3282
- for (const arg of field.args) {
3283
- const type = getNamedType(arg.type);
3284
- visitInputType(visitedTypes, pruningContext, type);
3309
+ // Visit interfaces this type is implementing if they haven't been visited yet
3310
+ if ('getInterfaces' in type) {
3311
+ // Only pushes to queue to visit but not return types
3312
+ queue.push(...type.getInterfaces().map(iface => iface.name));
3285
3313
  }
3286
- }
3287
- if (isInterfaceType(type)) {
3288
- const implementations = getImplementations(pruningContext, type);
3289
- if (implementations) {
3290
- for (const typeName in implementations) {
3291
- visitOutputType(visitedTypes, pruningContext, pruningContext.schema.getType(typeName));
3314
+ // If the type has files visit those field types
3315
+ if ('getFields' in type) {
3316
+ const fields = type.getFields();
3317
+ const entries = Object.entries(fields);
3318
+ if (!entries.length) {
3319
+ continue;
3292
3320
  }
3293
- }
3294
- }
3295
- if ('getInterfaces' in type) {
3296
- for (const iFace of type.getInterfaces()) {
3297
- visitOutputType(visitedTypes, pruningContext, iFace);
3298
- }
3299
- }
3300
- }
3301
- else if (isUnionType(type)) {
3302
- const types = type.getTypes();
3303
- for (const type of types) {
3304
- visitOutputType(visitedTypes, pruningContext, type);
3305
- }
3306
- }
3307
- }
3308
- /**
3309
- * Initialize a pruneContext given a schema.
3310
- */
3311
- function createPruningContext(schema) {
3312
- const pruningContext = {
3313
- schema,
3314
- unusedTypes: Object.create(null),
3315
- implementations: Object.create(null),
3316
- };
3317
- for (const typeName in schema.getTypeMap()) {
3318
- const type = schema.getType(typeName);
3319
- if (type && 'getInterfaces' in type) {
3320
- for (const iface of type.getInterfaces()) {
3321
- const implementations = getImplementations(pruningContext, iface);
3322
- if (implementations == null) {
3323
- pruningContext.implementations[iface.name] = Object.create(null);
3321
+ for (const [, field] of entries) {
3322
+ if (isObjectType(type)) {
3323
+ // Visit arg types
3324
+ queue.push(...field.args.map(arg => getNamedType(arg.type).name));
3325
+ }
3326
+ const namedType = getNamedType(field.type);
3327
+ queue.push(namedType.name);
3328
+ // Interfaces returned on fields need to be revisited to add their implementations
3329
+ if (isInterfaceType(namedType) && !(namedType.name in revisit)) {
3330
+ revisit[namedType.name] = true;
3331
+ }
3324
3332
  }
3325
- pruningContext.implementations[iface.name][type.name] = true;
3326
3333
  }
3334
+ visited.add(typeName); // Mark as visited (and therefore it is used and should be kept)
3327
3335
  }
3328
3336
  }
3329
- return pruningContext;
3330
- }
3331
- /**
3332
- * Get the implementations of an interface. May return undefined.
3333
- */
3334
- function getImplementations(pruningContext, type) {
3335
- return pruningContext.implementations[type.name];
3336
- }
3337
- function visitInputType(visitedTypes, pruningContext, type) {
3338
- if (visitedTypes[type.name]) {
3339
- return;
3340
- }
3341
- pruningContext.unusedTypes[type.name] = false;
3342
- visitedTypes[type.name] = true;
3343
- if (isInputObjectType(type)) {
3344
- const fields = type.getFields();
3345
- for (const fieldName in fields) {
3346
- const field = fields[fieldName];
3347
- const namedType = getNamedType(field.type);
3348
- visitInputType(visitedTypes, pruningContext, namedType);
3349
- }
3350
- }
3351
- }
3352
- function visitTypes(pruningContext) {
3353
- const schema = pruningContext.schema;
3354
- for (const typeName in schema.getTypeMap()) {
3355
- if (!typeName.startsWith('__')) {
3356
- pruningContext.unusedTypes[typeName] = true;
3357
- }
3358
- }
3359
- const visitedTypes = Object.create(null);
3360
- const rootTypes = getRootTypes(schema);
3361
- for (const rootType of rootTypes) {
3362
- visitOutputType(visitedTypes, pruningContext, rootType);
3363
- }
3364
- for (const directive of schema.getDirectives()) {
3365
- for (const arg of directive.args) {
3366
- const type = getNamedType(arg.type);
3367
- visitInputType(visitedTypes, pruningContext, type);
3368
- }
3369
- }
3337
+ return visited;
3370
3338
  }
3371
3339
 
3372
3340
  function mergeDeep(sources, respectPrototype = false) {
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@graphql-tools/utils",
3
- "version": "8.6.7",
3
+ "version": "8.6.10",
4
4
  "description": "Common package containing utils and types for GraphQL tools",
5
5
  "sideEffects": false,
6
6
  "peerDependencies": {
7
7
  "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0"
8
8
  },
9
9
  "dependencies": {
10
- "tslib": "~2.3.0"
10
+ "tslib": "~2.4.0"
11
11
  },
12
12
  "repository": {
13
13
  "type": "git",