@apollo/federation-internals 2.13.2 → 2.14.0
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.
- package/dist/definitions.d.ts +24 -2
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +428 -37
- package/dist/definitions.js.map +1 -1
- package/dist/federation.d.ts +2 -2
- package/dist/federation.js +2 -2
- package/dist/schemaUpgrader.d.ts.map +1 -1
- package/dist/schemaUpgrader.js +19 -7
- package/dist/schemaUpgrader.js.map +1 -1
- package/dist/specs/connectSpec.d.ts.map +1 -1
- package/dist/specs/connectSpec.js +2 -2
- package/dist/specs/connectSpec.js.map +1 -1
- package/dist/specs/coreSpec.d.ts +7 -1
- package/dist/specs/coreSpec.d.ts.map +1 -1
- package/dist/specs/coreSpec.js +19 -1
- package/dist/specs/coreSpec.js.map +1 -1
- package/dist/specs/federationSpec.d.ts.map +1 -1
- package/dist/specs/federationSpec.js +2 -1
- package/dist/specs/federationSpec.js.map +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +4 -3
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/definitions.ts +758 -47
- package/src/federation.ts +2 -2
- package/src/schemaUpgrader.ts +27 -12
- package/src/specs/connectSpec.ts +3 -2
- package/src/specs/coreSpec.ts +44 -2
- package/src/specs/federationSpec.ts +2 -1
- package/src/utils.ts +6 -3
- package/dist/specs/sourceSpec.d.ts +0 -69
- package/dist/specs/sourceSpec.d.ts.map +0 -1
- package/dist/specs/sourceSpec.js +0 -345
- package/dist/specs/sourceSpec.js.map +0 -1
package/dist/definitions.js
CHANGED
|
@@ -6,6 +6,7 @@ const graphql_1 = require("graphql");
|
|
|
6
6
|
const coreSpec_1 = require("./specs/coreSpec");
|
|
7
7
|
const utils_1 = require("./utils");
|
|
8
8
|
const values_1 = require("./values");
|
|
9
|
+
const tagSpec_1 = require("./specs/tagSpec");
|
|
9
10
|
const inaccessibleSpec_1 = require("./specs/inaccessibleSpec");
|
|
10
11
|
const print_1 = require("./print");
|
|
11
12
|
const types_1 = require("./types");
|
|
@@ -725,6 +726,8 @@ class CoreFeatures {
|
|
|
725
726
|
this.coreItself = coreItself;
|
|
726
727
|
this.byAlias = new Map();
|
|
727
728
|
this.byIdentity = new Map();
|
|
729
|
+
this.byImportName = new Map();
|
|
730
|
+
this.conflictsByAlias = new utils_1.SetMultiMap();
|
|
728
731
|
this.add(coreItself);
|
|
729
732
|
const coreDef = (0, coreSpec_1.findCoreSpecVersion)(coreItself.url);
|
|
730
733
|
if (!coreDef) {
|
|
@@ -733,16 +736,44 @@ class CoreFeatures {
|
|
|
733
736
|
this.coreDefinition = coreDef;
|
|
734
737
|
}
|
|
735
738
|
getByIdentity(identity) {
|
|
736
|
-
|
|
739
|
+
var _a;
|
|
740
|
+
return (_a = this.byIdentity.get(identity)) === null || _a === void 0 ? void 0 : _a[0];
|
|
737
741
|
}
|
|
738
742
|
allFeatures() {
|
|
739
|
-
return this.byIdentity.values();
|
|
743
|
+
return [...this.byIdentity.values()].map(([feature]) => feature);
|
|
740
744
|
}
|
|
741
745
|
removeFeature(featureIdentity) {
|
|
742
|
-
const
|
|
743
|
-
if (
|
|
746
|
+
const entry = this.byIdentity.get(featureIdentity);
|
|
747
|
+
if (entry) {
|
|
748
|
+
const [feature] = entry;
|
|
744
749
|
this.byIdentity.delete(featureIdentity);
|
|
745
|
-
|
|
750
|
+
const alias = feature.nameInSchema;
|
|
751
|
+
this.byAlias.delete(alias);
|
|
752
|
+
for (const { name: importInSpec, as } of feature.imports) {
|
|
753
|
+
const importInSchema = as !== null && as !== void 0 ? as : importInSpec;
|
|
754
|
+
const isDirective = importInSpec.charAt(0) === "@";
|
|
755
|
+
const nameInSchema = isDirective
|
|
756
|
+
? importInSchema.slice(1)
|
|
757
|
+
: importInSchema;
|
|
758
|
+
this.byImportName.delete(importInSchema);
|
|
759
|
+
const split = CoreFeatures.splitPrefixedName(nameInSchema);
|
|
760
|
+
if (!split) {
|
|
761
|
+
continue;
|
|
762
|
+
}
|
|
763
|
+
const [splitAlias] = split;
|
|
764
|
+
if (splitAlias === alias) {
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
let conflicts = this.conflictsByAlias.get(importInSchema);
|
|
768
|
+
if (!conflicts) {
|
|
769
|
+
continue;
|
|
770
|
+
}
|
|
771
|
+
conflicts.delete(importInSchema);
|
|
772
|
+
if (conflicts.size) {
|
|
773
|
+
continue;
|
|
774
|
+
}
|
|
775
|
+
this.conflictsByAlias.delete(importInSchema);
|
|
776
|
+
}
|
|
746
777
|
}
|
|
747
778
|
}
|
|
748
779
|
maybeAddFeature(directive) {
|
|
@@ -753,10 +784,6 @@ class CoreFeatures {
|
|
|
753
784
|
const typedDirective = directive;
|
|
754
785
|
const args = typedDirective.arguments();
|
|
755
786
|
const url = this.coreDefinition.extractFeatureUrl(args);
|
|
756
|
-
const existing = this.byIdentity.get(url.identity);
|
|
757
|
-
if (existing) {
|
|
758
|
-
throw error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Duplicate inclusion of feature ${url.identity}`);
|
|
759
|
-
}
|
|
760
787
|
const imports = (0, coreSpec_1.extractCoreFeatureImports)(url, typedDirective);
|
|
761
788
|
const feature = new CoreFeature(url, (_b = args.as) !== null && _b !== void 0 ? _b : url.name, directive, imports, args.for);
|
|
762
789
|
this.add(feature);
|
|
@@ -764,44 +791,404 @@ class CoreFeatures {
|
|
|
764
791
|
return feature;
|
|
765
792
|
}
|
|
766
793
|
add(feature) {
|
|
767
|
-
|
|
768
|
-
|
|
794
|
+
var _a, _b;
|
|
795
|
+
const identity = feature.url.identity;
|
|
796
|
+
if (this.byIdentity.has(identity)) {
|
|
797
|
+
throw error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Cannot link feature "${identity}" since it has already been linked in the schema.`);
|
|
798
|
+
}
|
|
799
|
+
const alias = feature.nameInSchema;
|
|
800
|
+
if (!(identity === tagSpec_1.tagIdentity &&
|
|
801
|
+
alias === 'federation__tag' &&
|
|
802
|
+
feature.imports.length === 0) &&
|
|
803
|
+
!(identity === inaccessibleSpec_1.inaccessibleIdentity &&
|
|
804
|
+
alias === 'federation__inaccessible' &&
|
|
805
|
+
feature.imports.length === 0)) {
|
|
806
|
+
if (alias.indexOf('__') !== -1) {
|
|
807
|
+
throw error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Cannot link feature "${identity}" as "${alias}" since it contains "__". Please rename to a compliant name via "as".`);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
if (alias.charAt(alias.length - 1) === '_') {
|
|
811
|
+
throw error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Cannot link feature "${identity}" as "${alias}" since it ends in "_". Please rename to a compliant name via "as".`);
|
|
812
|
+
}
|
|
813
|
+
if (!aliasRegexp.test(alias)) {
|
|
814
|
+
throw error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Cannot link feature "${identity}" as "${alias}" since it is not a valid GraphQL name. Please rename to a compliant name via "as".`);
|
|
815
|
+
}
|
|
816
|
+
const conflicts = this.conflictsByAlias.get(alias);
|
|
817
|
+
if (conflicts) {
|
|
818
|
+
const importInSchema = (_b = (_a = conflicts === null || conflicts === void 0 ? void 0 : conflicts.values()) === null || _a === void 0 ? void 0 : _a.next()) === null || _b === void 0 ? void 0 : _b.value;
|
|
819
|
+
(0, utils_1.assert)(importInSchema !== undefined, `Unexpectedly empty conflicts set`);
|
|
820
|
+
const entry = this.byImportName.get(importInSchema);
|
|
821
|
+
(0, utils_1.assert)(entry, `Unexpectedly cannot find feature for import`);
|
|
822
|
+
const [conflictFeature, importInSpec] = entry;
|
|
823
|
+
const conflictIdentity = conflictFeature.url.identity;
|
|
824
|
+
this.checkTagInaccessibleConflict(conflictIdentity, identity);
|
|
825
|
+
const importInErrorMessage = importInSchema !== importInSpec
|
|
826
|
+
? `"${importInSpec}" as "${importInSchema}"`
|
|
827
|
+
: `"${importInSpec}"`;
|
|
828
|
+
throw error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Cannot import ${importInErrorMessage} from feature "${conflictIdentity}" since it can be confused with a namespaced name from another linked feature "${identity}". Please rename the import or feature to avoid conflicts via "as".`);
|
|
829
|
+
}
|
|
830
|
+
const importInSchema = "@" + alias;
|
|
831
|
+
const entry = this.byImportName.get(importInSchema);
|
|
832
|
+
if (entry) {
|
|
833
|
+
const [conflictFeature, importInSpec] = entry;
|
|
834
|
+
const conflictIdentity = conflictFeature.url.identity;
|
|
835
|
+
this.checkTagInaccessibleConflict(conflictIdentity, identity);
|
|
836
|
+
const importInErrorMessage = importInSchema !== importInSpec
|
|
837
|
+
? `"${importInSpec}" as "${importInSchema}"`
|
|
838
|
+
: `"${importInSpec}"`;
|
|
839
|
+
throw error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Cannot import ${importInErrorMessage} from feature "${conflictIdentity}" since it can be confused with a namespaced name from another linked feature "${identity}". Please rename the import or feature to avoid conflicts via "as".`);
|
|
840
|
+
}
|
|
841
|
+
const existingFeature = this.byAlias.get(alias);
|
|
842
|
+
if (existingFeature !== undefined) {
|
|
843
|
+
const existingIdentity = existingFeature.url.identity;
|
|
844
|
+
this.checkTagInaccessibleConflict(existingIdentity, identity);
|
|
845
|
+
throw error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Cannot link feature ${identity} as "${alias}" since another feature "${existingIdentity}" already uses that alias. Please rename the feature to avoid conflicts via "as".`);
|
|
846
|
+
}
|
|
847
|
+
const importsMap = new Map();
|
|
848
|
+
for (const { name: importInSpec, as } of feature.imports) {
|
|
849
|
+
const importInSchema = as !== null && as !== void 0 ? as : importInSpec;
|
|
850
|
+
const importInErrorMessage = importInSchema !== importInSpec
|
|
851
|
+
? `"${importInSpec}" as "${importInSchema}"`
|
|
852
|
+
: `"${importInSpec}"`;
|
|
853
|
+
const isDirective = importInSpec.charAt(0) === "@";
|
|
854
|
+
const nameInSpec = isDirective
|
|
855
|
+
? importInSpec.slice(1)
|
|
856
|
+
: importInSpec;
|
|
857
|
+
const nameInSchema = isDirective
|
|
858
|
+
? importInSchema.slice(1)
|
|
859
|
+
: importInSchema;
|
|
860
|
+
const split = CoreFeatures.splitPrefixedName(nameInSchema);
|
|
861
|
+
if (split) {
|
|
862
|
+
const [splitAlias, splitNameInSpec] = split;
|
|
863
|
+
if (splitAlias === alias) {
|
|
864
|
+
if (splitNameInSpec !== nameInSpec) {
|
|
865
|
+
const splitImportInSpec = isDirective
|
|
866
|
+
? "@" + splitNameInSpec
|
|
867
|
+
: splitNameInSpec;
|
|
868
|
+
throw error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Cannot import ${importInErrorMessage} from feature "${identity}" since it can be confused with the namespaced name for "${splitImportInSpec}". Please rename the import to avoid conflicts via "as".`);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
else {
|
|
872
|
+
const conflictFeature = this.byAlias.get(splitAlias);
|
|
873
|
+
if (conflictFeature) {
|
|
874
|
+
const conflictIdentity = conflictFeature.url.identity;
|
|
875
|
+
this.checkTagInaccessibleConflict(conflictIdentity, identity);
|
|
876
|
+
throw error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Cannot import ${importInErrorMessage} from feature "${identity}" since it can be confused with a namespaced name from another linked feature "${conflictIdentity}". Please rename the import or feature to avoid conflicts via "as".`);
|
|
877
|
+
}
|
|
878
|
+
else {
|
|
879
|
+
this.conflictsByAlias.add(splitAlias, importInSchema);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
if (isDirective) {
|
|
884
|
+
if (nameInSchema === alias) {
|
|
885
|
+
if (nameInSpec !== feature.url.name) {
|
|
886
|
+
throw error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Cannot import ${importInErrorMessage} from feature "${identity}" since it can be confused with the namespaced name for "@${feature.url.name}". Please rename the import to avoid conflicts via "as".`);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
else {
|
|
890
|
+
const conflictFeature = this.byAlias.get(nameInSchema);
|
|
891
|
+
if (conflictFeature) {
|
|
892
|
+
const conflictIdentity = conflictFeature.url.identity;
|
|
893
|
+
this.checkTagInaccessibleConflict(conflictIdentity, identity);
|
|
894
|
+
throw error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Cannot import ${importInErrorMessage} from feature "${identity}" since it can be confused with a namespaced name from another linked feature "${conflictIdentity}". Please rename the import or feature to avoid conflicts via "as".`);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
const existingImportInSchema = importsMap.get(importInSpec);
|
|
899
|
+
if (existingImportInSchema === undefined) {
|
|
900
|
+
importsMap.set(importInSpec, importInSchema);
|
|
901
|
+
}
|
|
902
|
+
else {
|
|
903
|
+
if (existingImportInSchema !== importInSchema) {
|
|
904
|
+
throw error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Cannot import ${importInErrorMessage} from feature "${identity}" since it was previously imported as "${existingImportInSchema}". Please remove one of these imports.`);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
const entry = this.byImportName.get(importInSchema);
|
|
908
|
+
if (entry === undefined) {
|
|
909
|
+
this.byImportName.set(importInSchema, [feature, importInSpec]);
|
|
910
|
+
}
|
|
911
|
+
else {
|
|
912
|
+
const [existingFeature, existingImportInSpec] = entry;
|
|
913
|
+
const existingIdentity = existingFeature.url.identity;
|
|
914
|
+
if (existingIdentity !== identity) {
|
|
915
|
+
this.checkTagInaccessibleConflict(existingIdentity, identity);
|
|
916
|
+
throw error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Cannot import ${importInErrorMessage} from feature "${identity}" since it was previously imported from feature "${existingIdentity}". Please rename the import to avoid conflicts via "as".`);
|
|
917
|
+
}
|
|
918
|
+
if (existingImportInSpec !== importInSpec) {
|
|
919
|
+
throw error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Cannot import ${importInErrorMessage} from feature "${identity}" since it was previously imported for "${existingImportInSpec}". Please rename the import to avoid conflicts via "as".`);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
this.byAlias.set(alias, feature);
|
|
924
|
+
this.byIdentity.set(identity, [feature, importsMap]);
|
|
925
|
+
}
|
|
926
|
+
isAliasValid(alias, identity, importConflictsByIdentity) {
|
|
927
|
+
if (alias.indexOf('__') !== -1) {
|
|
928
|
+
return false;
|
|
929
|
+
}
|
|
930
|
+
if (alias.charAt(alias.length - 1) === '_') {
|
|
931
|
+
return false;
|
|
932
|
+
}
|
|
933
|
+
if (!nameRegexp.test(alias)) {
|
|
934
|
+
return false;
|
|
935
|
+
}
|
|
936
|
+
for (const [otherIdentity, importConflicts] of importConflictsByIdentity.entries()) {
|
|
937
|
+
if (identity === otherIdentity) {
|
|
938
|
+
if (importConflicts.self.has(alias)) {
|
|
939
|
+
return false;
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
else {
|
|
943
|
+
if (importConflicts.other.has(alias)) {
|
|
944
|
+
return false;
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
if (this.byAlias.has(alias)) {
|
|
949
|
+
return false;
|
|
950
|
+
}
|
|
951
|
+
return true;
|
|
952
|
+
}
|
|
953
|
+
static computeAliasConflicts(specAliases, elementNames) {
|
|
954
|
+
const trieNames = elementNames;
|
|
955
|
+
const importConflictsByIdentity = new Map();
|
|
956
|
+
for (const { url, alias, imports } of specAliases) {
|
|
957
|
+
trieNames.add(alias);
|
|
958
|
+
const self = new Set();
|
|
959
|
+
const other = new Set();
|
|
960
|
+
for (const { name: importInSpec, as } of imports) {
|
|
961
|
+
const importInSchema = as !== null && as !== void 0 ? as : importInSpec;
|
|
962
|
+
const isDirective = importInSpec.charAt(0) === "@";
|
|
963
|
+
const nameInSpec = isDirective
|
|
964
|
+
? importInSpec.slice(1)
|
|
965
|
+
: importInSpec;
|
|
966
|
+
const nameInSchema = isDirective
|
|
967
|
+
? importInSchema.slice(1)
|
|
968
|
+
: importInSchema;
|
|
969
|
+
trieNames.add(nameInSchema);
|
|
970
|
+
const split = CoreFeatures.splitPrefixedName(nameInSchema);
|
|
971
|
+
if (split) {
|
|
972
|
+
const [splitAlias, splitNameInSpec] = split;
|
|
973
|
+
if (splitNameInSpec !== nameInSpec) {
|
|
974
|
+
self.add(splitAlias);
|
|
975
|
+
}
|
|
976
|
+
other.add(splitAlias);
|
|
977
|
+
}
|
|
978
|
+
if (isDirective) {
|
|
979
|
+
if (nameInSpec !== url.name) {
|
|
980
|
+
self.add(nameInSchema);
|
|
981
|
+
}
|
|
982
|
+
other.add(nameInSchema);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
importConflictsByIdentity.set(url.identity, { self, other });
|
|
986
|
+
}
|
|
987
|
+
let prefix = null;
|
|
988
|
+
let index = 0;
|
|
989
|
+
let computeUniqueAlias = (specName) => {
|
|
990
|
+
if (prefix === null) {
|
|
991
|
+
const aliasStart = [
|
|
992
|
+
'_',
|
|
993
|
+
'abcdefghijklmnopqrstuvwxyz',
|
|
994
|
+
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
|
995
|
+
].join('');
|
|
996
|
+
const aliasContinue = [
|
|
997
|
+
'abcdefghijklmnopqrstuvwxyz',
|
|
998
|
+
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
|
999
|
+
'0123456789',
|
|
1000
|
+
].join('');
|
|
1001
|
+
const root = { children: new Map(), parent: null, char: '' };
|
|
1002
|
+
for (const name of trieNames) {
|
|
1003
|
+
let node = root;
|
|
1004
|
+
for (const char of name) {
|
|
1005
|
+
let child = node.children.get(char);
|
|
1006
|
+
if (!child) {
|
|
1007
|
+
child = { children: new Map(), parent: node, char };
|
|
1008
|
+
node.children.set(char, child);
|
|
1009
|
+
}
|
|
1010
|
+
node = child;
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
const queue = [root];
|
|
1014
|
+
let head = 0;
|
|
1015
|
+
while (prefix === null) {
|
|
1016
|
+
const possibleChars = head === 0 ? aliasStart : aliasContinue;
|
|
1017
|
+
const node = queue[head++];
|
|
1018
|
+
for (const char of possibleChars) {
|
|
1019
|
+
const child = node.children.get(char);
|
|
1020
|
+
if (child) {
|
|
1021
|
+
queue.push(child);
|
|
1022
|
+
}
|
|
1023
|
+
else {
|
|
1024
|
+
const chars = [char];
|
|
1025
|
+
for (let cur = node; cur === null || cur === void 0 ? void 0 : cur.parent; cur = cur.parent) {
|
|
1026
|
+
chars.push(cur.char);
|
|
1027
|
+
}
|
|
1028
|
+
prefix = chars.reverse().join('');
|
|
1029
|
+
break;
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
const suffix = specName.replace(/[^a-zA-Z]/g, '');
|
|
1035
|
+
return `${prefix}${index++}${suffix}`;
|
|
1036
|
+
};
|
|
1037
|
+
return {
|
|
1038
|
+
importConflictsByIdentity,
|
|
1039
|
+
computeUniqueAlias,
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
1042
|
+
checkTagInaccessibleConflict(identity1, identity2) {
|
|
1043
|
+
const federationIdentity = 'https://specs.apollo.dev/federation';
|
|
1044
|
+
const identities = new Set([identity1, identity2]);
|
|
1045
|
+
if (!identities.has(federationIdentity)) {
|
|
1046
|
+
return;
|
|
1047
|
+
}
|
|
1048
|
+
const [directive, identity] = identities.has(tagSpec_1.tagIdentity)
|
|
1049
|
+
? ['tag', tagSpec_1.tagIdentity]
|
|
1050
|
+
: identities.has(inaccessibleSpec_1.inaccessibleIdentity)
|
|
1051
|
+
? ['inaccessible', inaccessibleSpec_1.inaccessibleIdentity]
|
|
1052
|
+
: [undefined, undefined];
|
|
1053
|
+
if (directive && identity) {
|
|
1054
|
+
throw error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Please import "@${directive}" from the feature "${federationIdentity}" instead of using "${identity}" to avoid potential unexpected behavior in the future.`);
|
|
1055
|
+
}
|
|
769
1056
|
}
|
|
770
1057
|
sourceFeature(element) {
|
|
771
1058
|
const isDirective = element instanceof DirectiveDefinition || element instanceof Directive;
|
|
772
|
-
const
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
1059
|
+
const importName = isDirective ? '@' + element.name : element.name;
|
|
1060
|
+
const entry = this.byImportName.get(importName);
|
|
1061
|
+
if (entry) {
|
|
1062
|
+
const [feature, importInSpec] = entry;
|
|
1063
|
+
return {
|
|
776
1064
|
feature,
|
|
777
|
-
nameInFeature:
|
|
778
|
-
isImported:
|
|
779
|
-
}
|
|
1065
|
+
nameInFeature: isDirective ? importInSpec.slice(1) : importInSpec,
|
|
1066
|
+
isImported: true,
|
|
1067
|
+
};
|
|
780
1068
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
1069
|
+
const defaultEntry = this.sourceDefaultName(isDirective, element.name);
|
|
1070
|
+
if (!defaultEntry) {
|
|
1071
|
+
return undefined;
|
|
1072
|
+
}
|
|
1073
|
+
const [feature, nameInSpec] = defaultEntry;
|
|
1074
|
+
const importInSpec = isDirective ? '@' + nameInSpec : nameInSpec;
|
|
1075
|
+
return {
|
|
1076
|
+
feature,
|
|
1077
|
+
nameInFeature: this.getImportName(feature, importInSpec) === undefined
|
|
1078
|
+
? nameInSpec
|
|
1079
|
+
: null,
|
|
1080
|
+
isImported: false,
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
validateNoShadowingImports(schema) {
|
|
1084
|
+
const errors = [];
|
|
1085
|
+
for (const element of [...schema.allTypes(), ...schema.allDirectives()]) {
|
|
1086
|
+
const shadowingImport = this.getShadowingImport(element);
|
|
1087
|
+
if (!shadowingImport) {
|
|
1088
|
+
continue;
|
|
1089
|
+
}
|
|
1090
|
+
const isUsed = element instanceof DirectiveDefinition
|
|
1091
|
+
? element.applications().size !== 0
|
|
1092
|
+
: this.getReferencingRootElements(element)
|
|
1093
|
+
.some((referencer) => {
|
|
1094
|
+
return referencer.kind === 'SchemaDefinition'
|
|
1095
|
+
? true
|
|
1096
|
+
: !this.getShadowingImport(referencer);
|
|
1097
|
+
});
|
|
1098
|
+
if (!isUsed) {
|
|
1099
|
+
continue;
|
|
1100
|
+
}
|
|
1101
|
+
const { feature, importInSpec, importInSchema } = shadowingImport;
|
|
1102
|
+
const importInErrorMessage = importInSchema !== importInSpec
|
|
1103
|
+
? `"${importInSpec}" as "${importInSchema}"`
|
|
1104
|
+
: `"${importInSpec}"`;
|
|
1105
|
+
errors.push(error_1.ERRORS.INVALID_LINK_DIRECTIVE_USAGE.err(`Cannot import ${importInErrorMessage} from feature "${feature.url.identity}" since there's a used definition for the namespaced name "${element.coordinate}". Please switch usages of the namespaced name to the import name and remove the definition.`));
|
|
1106
|
+
}
|
|
1107
|
+
return errors;
|
|
1108
|
+
}
|
|
1109
|
+
getShadowingImport(element) {
|
|
1110
|
+
const isDirective = element instanceof DirectiveDefinition || element instanceof Directive;
|
|
1111
|
+
const defaultEntry = this.sourceDefaultName(isDirective, element.name);
|
|
1112
|
+
if (!defaultEntry) {
|
|
1113
|
+
return undefined;
|
|
1114
|
+
}
|
|
1115
|
+
const importName = isDirective ? '@' + element.name : element.name;
|
|
1116
|
+
const [feature, nameInSpec] = defaultEntry;
|
|
1117
|
+
const importInSpec = isDirective ? '@' + nameInSpec : nameInSpec;
|
|
1118
|
+
const importInSchema = this.getImportName(feature, importInSpec);
|
|
1119
|
+
return importInSchema !== undefined && importInSchema !== importName
|
|
1120
|
+
? {
|
|
1121
|
+
feature,
|
|
1122
|
+
importInSpec,
|
|
1123
|
+
importInSchema,
|
|
1124
|
+
}
|
|
1125
|
+
: undefined;
|
|
1126
|
+
}
|
|
1127
|
+
getReferencingRootElements(element) {
|
|
1128
|
+
const referencers = [];
|
|
1129
|
+
for (const referencer of element.referencers()) {
|
|
1130
|
+
switch (referencer.kind) {
|
|
1131
|
+
case 'ObjectType':
|
|
1132
|
+
referencers.push(referencer);
|
|
1133
|
+
break;
|
|
1134
|
+
case 'InterfaceType':
|
|
1135
|
+
referencers.push(referencer);
|
|
1136
|
+
break;
|
|
1137
|
+
case 'UnionType':
|
|
1138
|
+
referencers.push(referencer);
|
|
1139
|
+
break;
|
|
1140
|
+
case 'SchemaDefinition':
|
|
1141
|
+
referencers.push(referencer);
|
|
1142
|
+
break;
|
|
1143
|
+
case 'FieldDefinition':
|
|
1144
|
+
referencers.push(referencer.parent);
|
|
1145
|
+
break;
|
|
1146
|
+
case 'InputFieldDefinition':
|
|
1147
|
+
referencers.push(referencer.parent);
|
|
1148
|
+
break;
|
|
1149
|
+
case 'ArgumentDefinition':
|
|
1150
|
+
const parent = referencer.parent;
|
|
1151
|
+
switch (parent.kind) {
|
|
1152
|
+
case 'DirectiveDefinition':
|
|
1153
|
+
referencers.push(parent);
|
|
1154
|
+
break;
|
|
1155
|
+
case 'FieldDefinition':
|
|
1156
|
+
referencers.push(parent.parent);
|
|
1157
|
+
break;
|
|
1158
|
+
default:
|
|
1159
|
+
(0, utils_1.assertUnreachable)(parent);
|
|
792
1160
|
}
|
|
793
|
-
|
|
1161
|
+
break;
|
|
1162
|
+
default:
|
|
1163
|
+
(0, utils_1.assertUnreachable)(referencer);
|
|
794
1164
|
}
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
1165
|
+
}
|
|
1166
|
+
return referencers;
|
|
1167
|
+
}
|
|
1168
|
+
getImportName(feature, importInSpec) {
|
|
1169
|
+
var _a, _b;
|
|
1170
|
+
return (_b = (_a = this.byIdentity.get(feature.url.identity)) === null || _a === void 0 ? void 0 : _a[1]) === null || _b === void 0 ? void 0 : _b.get(importInSpec);
|
|
1171
|
+
}
|
|
1172
|
+
sourceDefaultName(isDirective, name) {
|
|
1173
|
+
const split = CoreFeatures.splitPrefixedName(name);
|
|
1174
|
+
if (split) {
|
|
1175
|
+
const [alias, nameInSpec] = split;
|
|
1176
|
+
const feature = this.byAlias.get(alias);
|
|
1177
|
+
if (feature) {
|
|
1178
|
+
return [feature, nameInSpec];
|
|
802
1179
|
}
|
|
1180
|
+
}
|
|
1181
|
+
if (!isDirective) {
|
|
803
1182
|
return undefined;
|
|
804
1183
|
}
|
|
1184
|
+
const feature = this.byAlias.get(name);
|
|
1185
|
+
return feature ? [feature, feature.url.name] : undefined;
|
|
1186
|
+
}
|
|
1187
|
+
static splitPrefixedName(name) {
|
|
1188
|
+
const splitIndex = name.indexOf('__');
|
|
1189
|
+
return splitIndex !== -1
|
|
1190
|
+
? [name.slice(0, splitIndex), name.slice(splitIndex + 2)]
|
|
1191
|
+
: undefined;
|
|
805
1192
|
}
|
|
806
1193
|
}
|
|
807
1194
|
exports.CoreFeatures = CoreFeatures;
|
|
@@ -846,6 +1233,8 @@ const graphQLBuiltInDirectivesSpecifications = [
|
|
|
846
1233
|
],
|
|
847
1234
|
}),
|
|
848
1235
|
];
|
|
1236
|
+
const aliasRegexp = /^[_A-Za-z][_0-9A-Za-z.-]*$/;
|
|
1237
|
+
const nameRegexp = /^[_A-Za-z][_0-9A-Za-z]*$/;
|
|
849
1238
|
const coordinateRegexp = /^@?[_A-Za-z][_0-9A-Za-z]*(\.[_A-Za-z][_0-9A-Za-z]*)?(\([_A-Za-z][_0-9A-Za-z]*:\))?$/;
|
|
850
1239
|
class Schema {
|
|
851
1240
|
constructor(blueprint = exports.defaultSchemaBlueprint, config = {}) {
|
|
@@ -1148,6 +1537,7 @@ class Schema {
|
|
|
1148
1537
|
this.isValidated = true;
|
|
1149
1538
|
}
|
|
1150
1539
|
validate() {
|
|
1540
|
+
var _a, _b;
|
|
1151
1541
|
if (this.isValidated) {
|
|
1152
1542
|
return;
|
|
1153
1543
|
}
|
|
@@ -1156,6 +1546,7 @@ class Schema {
|
|
|
1156
1546
|
});
|
|
1157
1547
|
let errors = (0, validate_1.validateSDL)(this.toAST(), undefined, this.blueprint.validationRules()).map((e) => this.blueprint.onGraphQLJSValidationError(this, e));
|
|
1158
1548
|
errors = errors.concat((0, validate_2.validateSchema)(this));
|
|
1549
|
+
errors = errors.concat((_b = (_a = this.coreFeatures) === null || _a === void 0 ? void 0 : _a.validateNoShadowingImports(this)) !== null && _b !== void 0 ? _b : []);
|
|
1159
1550
|
if (errors.length === 0) {
|
|
1160
1551
|
this.runWithBuiltInModificationAllowed(() => {
|
|
1161
1552
|
errors = this.blueprint.onValidation(this);
|