@nielspeter/eess-ts 0.1.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/LICENSE +21 -0
- package/README.md +364 -0
- package/dist/builders/call-rule-builder.d.ts +199 -0
- package/dist/builders/call-rule-builder.d.ts.map +1 -0
- package/dist/builders/call-rule-builder.js +254 -0
- package/dist/builders/call-rule-builder.js.map +1 -0
- package/dist/builders/class-rule-builder.d.ts +136 -0
- package/dist/builders/class-rule-builder.d.ts.map +1 -0
- package/dist/builders/class-rule-builder.js +253 -0
- package/dist/builders/class-rule-builder.js.map +1 -0
- package/dist/builders/cross-layer-builder.d.ts +96 -0
- package/dist/builders/cross-layer-builder.d.ts.map +1 -0
- package/dist/builders/cross-layer-builder.js +172 -0
- package/dist/builders/cross-layer-builder.js.map +1 -0
- package/dist/builders/function-rule-builder.d.ts +198 -0
- package/dist/builders/function-rule-builder.d.ts.map +1 -0
- package/dist/builders/function-rule-builder.js +287 -0
- package/dist/builders/function-rule-builder.js.map +1 -0
- package/dist/builders/jsx-rule-builder.d.ts +113 -0
- package/dist/builders/jsx-rule-builder.d.ts.map +1 -0
- package/dist/builders/jsx-rule-builder.js +150 -0
- package/dist/builders/jsx-rule-builder.js.map +1 -0
- package/dist/builders/module-rule-builder.d.ts +159 -0
- package/dist/builders/module-rule-builder.d.ts.map +1 -0
- package/dist/builders/module-rule-builder.js +237 -0
- package/dist/builders/module-rule-builder.js.map +1 -0
- package/dist/builders/scoped-function-rule-builder.d.ts +21 -0
- package/dist/builders/scoped-function-rule-builder.d.ts.map +1 -0
- package/dist/builders/scoped-function-rule-builder.js +26 -0
- package/dist/builders/scoped-function-rule-builder.js.map +1 -0
- package/dist/builders/slice-rule-builder.d.ts +85 -0
- package/dist/builders/slice-rule-builder.d.ts.map +1 -0
- package/dist/builders/slice-rule-builder.js +134 -0
- package/dist/builders/slice-rule-builder.js.map +1 -0
- package/dist/builders/type-rule-builder.d.ts +103 -0
- package/dist/builders/type-rule-builder.d.ts.map +1 -0
- package/dist/builders/type-rule-builder.js +170 -0
- package/dist/builders/type-rule-builder.js.map +1 -0
- package/dist/cli/bin.d.ts +3 -0
- package/dist/cli/bin.d.ts.map +1 -0
- package/dist/cli/bin.js +4 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/commands/baseline.d.ts +11 -0
- package/dist/cli/commands/baseline.d.ts.map +1 -0
- package/dist/cli/commands/baseline.js +16 -0
- package/dist/cli/commands/baseline.js.map +1 -0
- package/dist/cli/commands/check.d.ts +21 -0
- package/dist/cli/commands/check.d.ts.map +1 -0
- package/dist/cli/commands/check.js +94 -0
- package/dist/cli/commands/check.js.map +1 -0
- package/dist/cli/commands/explain.d.ts +9 -0
- package/dist/cli/commands/explain.d.ts.map +1 -0
- package/dist/cli/commands/explain.js +49 -0
- package/dist/cli/commands/explain.js.map +1 -0
- package/dist/cli/config.d.ts +31 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +20 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/index.d.ts +21 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +168 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/load-rules.d.ts +20 -0
- package/dist/cli/load-rules.d.ts.map +1 -0
- package/dist/cli/load-rules.js +97 -0
- package/dist/cli/load-rules.js.map +1 -0
- package/dist/cli/resolve-config.d.ts +11 -0
- package/dist/cli/resolve-config.d.ts.map +1 -0
- package/dist/cli/resolve-config.js +61 -0
- package/dist/cli/resolve-config.js.map +1 -0
- package/dist/cli/watch.d.ts +49 -0
- package/dist/cli/watch.d.ts.map +1 -0
- package/dist/cli/watch.js +138 -0
- package/dist/cli/watch.js.map +1 -0
- package/dist/conditions/body-analysis-function.d.ts +23 -0
- package/dist/conditions/body-analysis-function.d.ts.map +1 -0
- package/dist/conditions/body-analysis-function.js +103 -0
- package/dist/conditions/body-analysis-function.js.map +1 -0
- package/dist/conditions/body-analysis-module.d.ts +27 -0
- package/dist/conditions/body-analysis-module.d.ts.map +1 -0
- package/dist/conditions/body-analysis-module.js +99 -0
- package/dist/conditions/body-analysis-module.js.map +1 -0
- package/dist/conditions/body-analysis.d.ts +34 -0
- package/dist/conditions/body-analysis.d.ts.map +1 -0
- package/dist/conditions/body-analysis.js +95 -0
- package/dist/conditions/body-analysis.js.map +1 -0
- package/dist/conditions/call.d.ts +62 -0
- package/dist/conditions/call.d.ts.map +1 -0
- package/dist/conditions/call.js +267 -0
- package/dist/conditions/call.js.map +1 -0
- package/dist/conditions/catch-analysis.d.ts +31 -0
- package/dist/conditions/catch-analysis.d.ts.map +1 -0
- package/dist/conditions/catch-analysis.js +78 -0
- package/dist/conditions/catch-analysis.js.map +1 -0
- package/dist/conditions/class.d.ts +33 -0
- package/dist/conditions/class.d.ts.map +1 -0
- package/dist/conditions/class.js +110 -0
- package/dist/conditions/class.js.map +1 -0
- package/dist/conditions/cross-layer.d.ts +28 -0
- package/dist/conditions/cross-layer.d.ts.map +1 -0
- package/dist/conditions/cross-layer.js +105 -0
- package/dist/conditions/cross-layer.js.map +1 -0
- package/dist/conditions/dependency.d.ts +73 -0
- package/dist/conditions/dependency.d.ts.map +1 -0
- package/dist/conditions/dependency.js +177 -0
- package/dist/conditions/dependency.js.map +1 -0
- package/dist/conditions/exports.d.ts +33 -0
- package/dist/conditions/exports.d.ts.map +1 -0
- package/dist/conditions/exports.js +101 -0
- package/dist/conditions/exports.js.map +1 -0
- package/dist/conditions/function.d.ts +79 -0
- package/dist/conditions/function.d.ts.map +1 -0
- package/dist/conditions/function.js +167 -0
- package/dist/conditions/function.js.map +1 -0
- package/dist/conditions/helpers.d.ts +14 -0
- package/dist/conditions/helpers.d.ts.map +1 -0
- package/dist/conditions/helpers.js +26 -0
- package/dist/conditions/helpers.js.map +1 -0
- package/dist/conditions/jsx.d.ts +40 -0
- package/dist/conditions/jsx.d.ts.map +1 -0
- package/dist/conditions/jsx.js +133 -0
- package/dist/conditions/jsx.js.map +1 -0
- package/dist/conditions/members.d.ts +74 -0
- package/dist/conditions/members.d.ts.map +1 -0
- package/dist/conditions/members.js +224 -0
- package/dist/conditions/members.js.map +1 -0
- package/dist/conditions/pattern.d.ts +20 -0
- package/dist/conditions/pattern.d.ts.map +1 -0
- package/dist/conditions/pattern.js +108 -0
- package/dist/conditions/pattern.js.map +1 -0
- package/dist/conditions/reverse-dependency.d.ts +28 -0
- package/dist/conditions/reverse-dependency.d.ts.map +1 -0
- package/dist/conditions/reverse-dependency.js +275 -0
- package/dist/conditions/reverse-dependency.js.map +1 -0
- package/dist/conditions/slice.d.ts +49 -0
- package/dist/conditions/slice.d.ts.map +1 -0
- package/dist/conditions/slice.js +153 -0
- package/dist/conditions/slice.js.map +1 -0
- package/dist/conditions/structural.d.ts +58 -0
- package/dist/conditions/structural.d.ts.map +1 -0
- package/dist/conditions/structural.js +102 -0
- package/dist/conditions/structural.js.map +1 -0
- package/dist/conditions/type-level.d.ts +29 -0
- package/dist/conditions/type-level.d.ts.map +1 -0
- package/dist/conditions/type-level.js +48 -0
- package/dist/conditions/type-level.js.map +1 -0
- package/dist/core/import-options.d.ts +32 -0
- package/dist/core/import-options.d.ts.map +1 -0
- package/dist/core/import-options.js +29 -0
- package/dist/core/import-options.js.map +1 -0
- package/dist/core/module-dependencies.d.ts +28 -0
- package/dist/core/module-dependencies.d.ts.map +1 -0
- package/dist/core/module-dependencies.js +35 -0
- package/dist/core/module-dependencies.js.map +1 -0
- package/dist/core/pair-condition.d.ts +10 -0
- package/dist/core/pair-condition.d.ts.map +1 -0
- package/dist/core/pair-condition.js +2 -0
- package/dist/core/pair-condition.js.map +1 -0
- package/dist/core/project.d.ts +68 -0
- package/dist/core/project.d.ts.map +1 -0
- package/dist/core/project.js +127 -0
- package/dist/core/project.js.map +1 -0
- package/dist/core/type-matcher.d.ts +10 -0
- package/dist/core/type-matcher.d.ts.map +1 -0
- package/dist/core/type-matcher.js +2 -0
- package/dist/core/type-matcher.js.map +1 -0
- package/dist/core/violation.d.ts +38 -0
- package/dist/core/violation.d.ts.map +1 -0
- package/dist/core/violation.js +130 -0
- package/dist/core/violation.js.map +1 -0
- package/dist/graphql/index.d.ts +76 -0
- package/dist/graphql/index.d.ts.map +1 -0
- package/dist/graphql/index.js +108 -0
- package/dist/graphql/index.js.map +1 -0
- package/dist/graphql/resolver-rule-builder.d.ts +75 -0
- package/dist/graphql/resolver-rule-builder.d.ts.map +1 -0
- package/dist/graphql/resolver-rule-builder.js +146 -0
- package/dist/graphql/resolver-rule-builder.js.map +1 -0
- package/dist/graphql/schema-conditions.d.ts +31 -0
- package/dist/graphql/schema-conditions.d.ts.map +1 -0
- package/dist/graphql/schema-conditions.js +119 -0
- package/dist/graphql/schema-conditions.js.map +1 -0
- package/dist/graphql/schema-loader.d.ts +75 -0
- package/dist/graphql/schema-loader.d.ts.map +1 -0
- package/dist/graphql/schema-loader.js +113 -0
- package/dist/graphql/schema-loader.js.map +1 -0
- package/dist/graphql/schema-predicates.d.ts +42 -0
- package/dist/graphql/schema-predicates.d.ts.map +1 -0
- package/dist/graphql/schema-predicates.js +74 -0
- package/dist/graphql/schema-predicates.js.map +1 -0
- package/dist/graphql/schema-rule-builder.d.ts +74 -0
- package/dist/graphql/schema-rule-builder.d.ts.map +1 -0
- package/dist/graphql/schema-rule-builder.js +188 -0
- package/dist/graphql/schema-rule-builder.js.map +1 -0
- package/dist/helpers/body-traversal.d.ts +58 -0
- package/dist/helpers/body-traversal.d.ts.map +1 -0
- package/dist/helpers/body-traversal.js +180 -0
- package/dist/helpers/body-traversal.js.map +1 -0
- package/dist/helpers/callback-extractor.d.ts +28 -0
- package/dist/helpers/callback-extractor.d.ts.map +1 -0
- package/dist/helpers/callback-extractor.js +159 -0
- package/dist/helpers/callback-extractor.js.map +1 -0
- package/dist/helpers/complexity.d.ts +26 -0
- package/dist/helpers/complexity.d.ts.map +1 -0
- package/dist/helpers/complexity.js +64 -0
- package/dist/helpers/complexity.js.map +1 -0
- package/dist/helpers/matchers.d.ts +206 -0
- package/dist/helpers/matchers.d.ts.map +1 -0
- package/dist/helpers/matchers.js +470 -0
- package/dist/helpers/matchers.js.map +1 -0
- package/dist/helpers/pattern.d.ts +37 -0
- package/dist/helpers/pattern.d.ts.map +1 -0
- package/dist/helpers/pattern.js +22 -0
- package/dist/helpers/pattern.js.map +1 -0
- package/dist/helpers/slice-graph.d.ts +32 -0
- package/dist/helpers/slice-graph.d.ts.map +1 -0
- package/dist/helpers/slice-graph.js +89 -0
- package/dist/helpers/slice-graph.js.map +1 -0
- package/dist/helpers/tarjan.d.ts +21 -0
- package/dist/helpers/tarjan.d.ts.map +1 -0
- package/dist/helpers/tarjan.js +71 -0
- package/dist/helpers/tarjan.js.map +1 -0
- package/dist/helpers/type-matchers.d.ts +67 -0
- package/dist/helpers/type-matchers.d.ts.map +1 -0
- package/dist/helpers/type-matchers.js +108 -0
- package/dist/helpers/type-matchers.js.map +1 -0
- package/dist/helpers/within.d.ts +41 -0
- package/dist/helpers/within.d.ts.map +1 -0
- package/dist/helpers/within.js +32 -0
- package/dist/helpers/within.js.map +1 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +116 -0
- package/dist/index.js.map +1 -0
- package/dist/models/arch-call.d.ts +83 -0
- package/dist/models/arch-call.d.ts.map +1 -0
- package/dist/models/arch-call.js +90 -0
- package/dist/models/arch-call.js.map +1 -0
- package/dist/models/arch-function.d.ts +76 -0
- package/dist/models/arch-function.d.ts.map +1 -0
- package/dist/models/arch-function.js +122 -0
- package/dist/models/arch-function.js.map +1 -0
- package/dist/models/arch-jsx-element.d.ts +75 -0
- package/dist/models/arch-jsx-element.d.ts.map +1 -0
- package/dist/models/arch-jsx-element.js +231 -0
- package/dist/models/arch-jsx-element.js.map +1 -0
- package/dist/models/cross-layer.d.ts +15 -0
- package/dist/models/cross-layer.d.ts.map +1 -0
- package/dist/models/cross-layer.js +2 -0
- package/dist/models/cross-layer.js.map +1 -0
- package/dist/models/slice.d.ts +60 -0
- package/dist/models/slice.d.ts.map +1 -0
- package/dist/models/slice.js +89 -0
- package/dist/models/slice.js.map +1 -0
- package/dist/predicates/call.d.ts +49 -0
- package/dist/predicates/call.d.ts.map +1 -0
- package/dist/predicates/call.js +115 -0
- package/dist/predicates/call.js.map +1 -0
- package/dist/predicates/class.d.ts +42 -0
- package/dist/predicates/class.d.ts.map +1 -0
- package/dist/predicates/class.js +83 -0
- package/dist/predicates/class.js.map +1 -0
- package/dist/predicates/function.d.ts +81 -0
- package/dist/predicates/function.d.ts.map +1 -0
- package/dist/predicates/function.js +157 -0
- package/dist/predicates/function.js.map +1 -0
- package/dist/predicates/identity.d.ts +55 -0
- package/dist/predicates/identity.d.ts.map +1 -0
- package/dist/predicates/identity.js +96 -0
- package/dist/predicates/identity.js.map +1 -0
- package/dist/predicates/index.d.ts +4 -0
- package/dist/predicates/index.d.ts.map +1 -0
- package/dist/predicates/index.js +3 -0
- package/dist/predicates/index.js.map +1 -0
- package/dist/predicates/jsx.d.ts +41 -0
- package/dist/predicates/jsx.d.ts.map +1 -0
- package/dist/predicates/jsx.js +84 -0
- package/dist/predicates/jsx.js.map +1 -0
- package/dist/predicates/metrics.d.ts +30 -0
- package/dist/predicates/metrics.d.ts.map +1 -0
- package/dist/predicates/metrics.js +65 -0
- package/dist/predicates/metrics.js.map +1 -0
- package/dist/predicates/module.d.ts +44 -0
- package/dist/predicates/module.d.ts.map +1 -0
- package/dist/predicates/module.js +70 -0
- package/dist/predicates/module.js.map +1 -0
- package/dist/predicates/type.d.ts +48 -0
- package/dist/predicates/type.d.ts.map +1 -0
- package/dist/predicates/type.js +107 -0
- package/dist/predicates/type.js.map +1 -0
- package/dist/presets/boundaries.d.ts +19 -0
- package/dist/presets/boundaries.d.ts.map +1 -0
- package/dist/presets/boundaries.js +93 -0
- package/dist/presets/boundaries.js.map +1 -0
- package/dist/presets/data-layer.d.ts +20 -0
- package/dist/presets/data-layer.d.ts.map +1 -0
- package/dist/presets/data-layer.js +30 -0
- package/dist/presets/data-layer.js.map +1 -0
- package/dist/presets/index.d.ts +9 -0
- package/dist/presets/index.d.ts.map +1 -0
- package/dist/presets/index.js +5 -0
- package/dist/presets/index.js.map +1 -0
- package/dist/presets/layered.d.ts +21 -0
- package/dist/presets/layered.d.ts.map +1 -0
- package/dist/presets/layered.js +103 -0
- package/dist/presets/layered.js.map +1 -0
- package/dist/presets/shared.d.ts +3 -0
- package/dist/presets/shared.d.ts.map +1 -0
- package/dist/presets/shared.js +5 -0
- package/dist/presets/shared.js.map +1 -0
- package/dist/rules/architecture.d.ts +10 -0
- package/dist/rules/architecture.d.ts.map +1 -0
- package/dist/rules/architecture.js +14 -0
- package/dist/rules/architecture.js.map +1 -0
- package/dist/rules/code-quality.d.ts +55 -0
- package/dist/rules/code-quality.d.ts.map +1 -0
- package/dist/rules/code-quality.js +116 -0
- package/dist/rules/code-quality.js.map +1 -0
- package/dist/rules/dependencies.d.ts +32 -0
- package/dist/rules/dependencies.d.ts.map +1 -0
- package/dist/rules/dependencies.js +37 -0
- package/dist/rules/dependencies.js.map +1 -0
- package/dist/rules/errors.d.ts +31 -0
- package/dist/rules/errors.d.ts.map +1 -0
- package/dist/rules/errors.js +97 -0
- package/dist/rules/errors.js.map +1 -0
- package/dist/rules/hygiene.d.ts +54 -0
- package/dist/rules/hygiene.d.ts.map +1 -0
- package/dist/rules/hygiene.js +62 -0
- package/dist/rules/hygiene.js.map +1 -0
- package/dist/rules/metrics-function.d.ts +45 -0
- package/dist/rules/metrics-function.d.ts.map +1 -0
- package/dist/rules/metrics-function.js +87 -0
- package/dist/rules/metrics-function.js.map +1 -0
- package/dist/rules/metrics.d.ts +64 -0
- package/dist/rules/metrics.d.ts.map +1 -0
- package/dist/rules/metrics.js +157 -0
- package/dist/rules/metrics.js.map +1 -0
- package/dist/rules/naming.d.ts +24 -0
- package/dist/rules/naming.d.ts.map +1 -0
- package/dist/rules/naming.js +51 -0
- package/dist/rules/naming.js.map +1 -0
- package/dist/rules/security.d.ts +59 -0
- package/dist/rules/security.d.ts.map +1 -0
- package/dist/rules/security.js +92 -0
- package/dist/rules/security.js.map +1 -0
- package/dist/rules/typescript.d.ts +73 -0
- package/dist/rules/typescript.d.ts.map +1 -0
- package/dist/rules/typescript.js +105 -0
- package/dist/rules/typescript.js.map +1 -0
- package/dist/smells/duplicate-bodies.d.ts +24 -0
- package/dist/smells/duplicate-bodies.d.ts.map +1 -0
- package/dist/smells/duplicate-bodies.js +131 -0
- package/dist/smells/duplicate-bodies.js.map +1 -0
- package/dist/smells/fingerprint.d.ts +27 -0
- package/dist/smells/fingerprint.d.ts.map +1 -0
- package/dist/smells/fingerprint.js +50 -0
- package/dist/smells/fingerprint.js.map +1 -0
- package/dist/smells/inconsistent-siblings.d.ts +21 -0
- package/dist/smells/inconsistent-siblings.d.ts.map +1 -0
- package/dist/smells/inconsistent-siblings.js +135 -0
- package/dist/smells/inconsistent-siblings.js.map +1 -0
- package/dist/smells/index.d.ts +12 -0
- package/dist/smells/index.d.ts.map +1 -0
- package/dist/smells/index.js +15 -0
- package/dist/smells/index.js.map +1 -0
- package/dist/smells/smell-builder.d.ts +37 -0
- package/dist/smells/smell-builder.d.ts.map +1 -0
- package/dist/smells/smell-builder.js +51 -0
- package/dist/smells/smell-builder.js.map +1 -0
- package/package.json +121 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assert that a type has all listed fields.
|
|
3
|
+
*
|
|
4
|
+
* When applied to a type-level SchemaElement, checks that the object type
|
|
5
|
+
* defines all the named fields. When applied to a field-level element,
|
|
6
|
+
* checks the parent type.
|
|
7
|
+
*
|
|
8
|
+
* @param names - Field names that must exist on the type
|
|
9
|
+
*/
|
|
10
|
+
export function haveFields(...names) {
|
|
11
|
+
return {
|
|
12
|
+
description: 'have fields ' + names.map((n) => `"${n}"`).join(', '),
|
|
13
|
+
evaluate(elements, context) {
|
|
14
|
+
const violations = [];
|
|
15
|
+
for (const element of elements) {
|
|
16
|
+
const fields = element.objectType.getFields();
|
|
17
|
+
const fieldNames = Object.keys(fields);
|
|
18
|
+
for (const name of names) {
|
|
19
|
+
if (!fieldNames.includes(name)) {
|
|
20
|
+
violations.push({
|
|
21
|
+
rule: context.rule,
|
|
22
|
+
ruleId: context.ruleId,
|
|
23
|
+
element: element.typeName,
|
|
24
|
+
file: element.filePath ?? '<schema>',
|
|
25
|
+
line: 1,
|
|
26
|
+
message: `Type "${element.typeName}" is missing field "${name}"`,
|
|
27
|
+
because: context.because,
|
|
28
|
+
suggestion: context.suggestion,
|
|
29
|
+
docs: context.docs,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return violations;
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Assert that a field accepts all listed arguments.
|
|
40
|
+
*
|
|
41
|
+
* Only applies to field-level SchemaElements. Type-level elements are skipped.
|
|
42
|
+
*
|
|
43
|
+
* @param names - Argument names that must exist on the field
|
|
44
|
+
*/
|
|
45
|
+
export function acceptArgs(...names) {
|
|
46
|
+
return {
|
|
47
|
+
description: 'accept args ' + names.map((n) => `"${n}"`).join(', '),
|
|
48
|
+
evaluate(elements, context) {
|
|
49
|
+
const violations = [];
|
|
50
|
+
for (const element of elements) {
|
|
51
|
+
if (!element.field)
|
|
52
|
+
continue;
|
|
53
|
+
const argNames = element.field.args.map((a) => a.name);
|
|
54
|
+
for (const name of names) {
|
|
55
|
+
if (!argNames.includes(name)) {
|
|
56
|
+
violations.push({
|
|
57
|
+
rule: context.rule,
|
|
58
|
+
ruleId: context.ruleId,
|
|
59
|
+
element: `${element.typeName}.${element.fieldName ?? element.field.name}`,
|
|
60
|
+
file: element.filePath ?? '<schema>',
|
|
61
|
+
line: 1,
|
|
62
|
+
message: `Field "${element.typeName}.${element.fieldName ?? element.field.name}" is missing argument "${name}"`,
|
|
63
|
+
because: context.because,
|
|
64
|
+
suggestion: context.suggestion,
|
|
65
|
+
docs: context.docs,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return violations;
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Assert that each schema field has a matching resolver export.
|
|
76
|
+
*
|
|
77
|
+
* Cross-references schema fields with TypeScript resolver files.
|
|
78
|
+
* A field "users" on type "Query" is matched if any resolver file exports
|
|
79
|
+
* a function/variable named "users" or contains a property assignment "Query.users".
|
|
80
|
+
*
|
|
81
|
+
* @param resolverFileTexts - Map of file paths to their source text (for matching)
|
|
82
|
+
*/
|
|
83
|
+
export function haveMatchingResolver(resolverFileTexts) {
|
|
84
|
+
return {
|
|
85
|
+
description: 'have matching resolver',
|
|
86
|
+
evaluate(elements, context) {
|
|
87
|
+
const violations = [];
|
|
88
|
+
const allText = [...resolverFileTexts.values()].join('\n');
|
|
89
|
+
for (const element of elements) {
|
|
90
|
+
if (!element.field)
|
|
91
|
+
continue;
|
|
92
|
+
const fieldName = element.fieldName ?? element.field.name;
|
|
93
|
+
// Check if any resolver file references this field name
|
|
94
|
+
// Look for: export function fieldName, export const fieldName,
|
|
95
|
+
// or TypeName.fieldName patterns
|
|
96
|
+
const patterns = [
|
|
97
|
+
new RegExp(`\\b${fieldName}\\b`),
|
|
98
|
+
new RegExp(`${element.typeName}\\.${fieldName}`),
|
|
99
|
+
];
|
|
100
|
+
const hasResolver = patterns.some((p) => p.test(allText));
|
|
101
|
+
if (!hasResolver) {
|
|
102
|
+
violations.push({
|
|
103
|
+
rule: context.rule,
|
|
104
|
+
ruleId: context.ruleId,
|
|
105
|
+
element: `${element.typeName}.${fieldName}`,
|
|
106
|
+
file: element.filePath ?? '<schema>',
|
|
107
|
+
line: 1,
|
|
108
|
+
message: `Field "${element.typeName}.${fieldName}" has no matching resolver`,
|
|
109
|
+
because: context.because,
|
|
110
|
+
suggestion: context.suggestion,
|
|
111
|
+
docs: context.docs,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return violations;
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=schema-conditions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-conditions.js","sourceRoot":"","sources":["../../src/graphql/schema-conditions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A parsed GraphQL schema with per-file document tracking.
|
|
3
|
+
*
|
|
4
|
+
* The schema is the merged result of all matched .graphql files.
|
|
5
|
+
* Documents preserve per-file source information for violation reporting.
|
|
6
|
+
*/
|
|
7
|
+
export interface LoadedSchema {
|
|
8
|
+
/** The merged GraphQL schema object (from `graphql` package's buildSchema) */
|
|
9
|
+
readonly schema: GraphQLSchemaLike;
|
|
10
|
+
/** Per-file parsed documents with source location info */
|
|
11
|
+
readonly documents: ReadonlyArray<{
|
|
12
|
+
readonly filePath: string;
|
|
13
|
+
readonly sdl: string;
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Minimal interface for the parts of GraphQLSchema we use.
|
|
18
|
+
* Avoids importing graphql types at the module level (optional peer dep).
|
|
19
|
+
*/
|
|
20
|
+
export interface GraphQLSchemaLike {
|
|
21
|
+
getQueryType(): GraphQLObjectTypeLike | undefined | null;
|
|
22
|
+
getMutationType(): GraphQLObjectTypeLike | undefined | null;
|
|
23
|
+
getTypeMap(): Record<string, GraphQLTypeLike>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Minimal interface for GraphQL object types.
|
|
27
|
+
*/
|
|
28
|
+
export interface GraphQLObjectTypeLike {
|
|
29
|
+
readonly name: string;
|
|
30
|
+
getFields(): Record<string, GraphQLFieldLike>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Minimal interface for GraphQL fields.
|
|
34
|
+
*/
|
|
35
|
+
export interface GraphQLFieldLike {
|
|
36
|
+
readonly name: string;
|
|
37
|
+
readonly type: GraphQLTypeLike;
|
|
38
|
+
readonly args: ReadonlyArray<GraphQLArgumentLike>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Minimal interface for GraphQL arguments.
|
|
42
|
+
*/
|
|
43
|
+
export interface GraphQLArgumentLike {
|
|
44
|
+
readonly name: string;
|
|
45
|
+
readonly type: GraphQLTypeLike;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Minimal interface for GraphQL types.
|
|
49
|
+
*/
|
|
50
|
+
export interface GraphQLTypeLike {
|
|
51
|
+
readonly toString: () => string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Load and parse .graphql files matching a glob pattern relative to a root directory.
|
|
55
|
+
*
|
|
56
|
+
* @param rootDir - The root directory to resolve the glob against
|
|
57
|
+
* @param glob - Glob pattern for .graphql files (e.g. 'schema/*.graphql')
|
|
58
|
+
* @returns A LoadedSchema with the merged schema and per-file documents
|
|
59
|
+
* @throws If no .graphql files are found or if SDL is invalid
|
|
60
|
+
*/
|
|
61
|
+
export declare function loadSchemaFromGlob(rootDir: string, glob: string): LoadedSchema;
|
|
62
|
+
/**
|
|
63
|
+
* Load a schema from a raw SDL string.
|
|
64
|
+
*
|
|
65
|
+
* @param sdl - GraphQL Schema Definition Language string
|
|
66
|
+
* @param sourcePath - Optional file path for error reporting
|
|
67
|
+
* @returns A LoadedSchema
|
|
68
|
+
*/
|
|
69
|
+
export declare function loadSchemaFromSDL(sdl: string, sourcePath?: string): LoadedSchema;
|
|
70
|
+
/**
|
|
71
|
+
* Check whether the graphql package is available.
|
|
72
|
+
* Used by the runtime guard in the barrel export.
|
|
73
|
+
*/
|
|
74
|
+
export declare function isGraphQLAvailable(): boolean;
|
|
75
|
+
//# sourceMappingURL=schema-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-loader.d.ts","sourceRoot":"","sources":["../../src/graphql/schema-loader.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAA;IAClC,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC;QAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;QACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KACrB,CAAC,CAAA;CACH;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,YAAY,IAAI,qBAAqB,GAAG,SAAS,GAAG,IAAI,CAAA;IACxD,eAAe,IAAI,qBAAqB,GAAG,SAAS,GAAG,IAAI,CAAA;IAC3D,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;CAC9C;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;CAC9C;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;IAC9B,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAA;CAClD;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,MAAM,CAAA;CAChC;AAkCD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,CAsB9E;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,YAAY,CAGhF;AAgDD;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAQ5C"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import picomatch from 'picomatch';
|
|
5
|
+
// Cached reference to the graphql package
|
|
6
|
+
let cachedGraphQL;
|
|
7
|
+
/**
|
|
8
|
+
* Load the graphql package synchronously. Throws a clear error if not installed.
|
|
9
|
+
*
|
|
10
|
+
* Uses createRequire for synchronous loading since schema loading is synchronous.
|
|
11
|
+
*/
|
|
12
|
+
function requireGraphQL() {
|
|
13
|
+
if (cachedGraphQL)
|
|
14
|
+
return cachedGraphQL;
|
|
15
|
+
try {
|
|
16
|
+
const esmRequire = createRequire(import.meta.url);
|
|
17
|
+
// eess-exclude eess/adr005-no-type-assertions: runtime require() of the optional 'graphql' peer dependency; its module shape is not statically known at this JS-interop boundary
|
|
18
|
+
cachedGraphQL = esmRequire('graphql');
|
|
19
|
+
return cachedGraphQL;
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
throw new Error('[eess/graphql] The "graphql" package is required but not installed.\n' +
|
|
23
|
+
'Install it with: npm install graphql', { cause: err });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Load and parse .graphql files matching a glob pattern relative to a root directory.
|
|
28
|
+
*
|
|
29
|
+
* @param rootDir - The root directory to resolve the glob against
|
|
30
|
+
* @param glob - Glob pattern for .graphql files (e.g. 'schema/*.graphql')
|
|
31
|
+
* @returns A LoadedSchema with the merged schema and per-file documents
|
|
32
|
+
* @throws If no .graphql files are found or if SDL is invalid
|
|
33
|
+
*/
|
|
34
|
+
export function loadSchemaFromGlob(rootDir, glob) {
|
|
35
|
+
const resolvedRoot = path.resolve(rootDir);
|
|
36
|
+
const matcher = picomatch(glob);
|
|
37
|
+
// Find all .graphql files matching the glob
|
|
38
|
+
const graphqlFiles = findGraphqlFiles(resolvedRoot, matcher);
|
|
39
|
+
if (graphqlFiles.length === 0) {
|
|
40
|
+
throw new Error(`[eess/graphql] No .graphql files found matching "${glob}" in ${resolvedRoot}`);
|
|
41
|
+
}
|
|
42
|
+
// Read all files and collect SDL
|
|
43
|
+
const documents = [];
|
|
44
|
+
const sdlParts = [];
|
|
45
|
+
for (const filePath of graphqlFiles) {
|
|
46
|
+
const sdl = fs.readFileSync(filePath, 'utf-8');
|
|
47
|
+
documents.push({ filePath, sdl });
|
|
48
|
+
sdlParts.push(sdl);
|
|
49
|
+
}
|
|
50
|
+
return buildLoadedSchema(sdlParts.join('\n'), documents);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Load a schema from a raw SDL string.
|
|
54
|
+
*
|
|
55
|
+
* @param sdl - GraphQL Schema Definition Language string
|
|
56
|
+
* @param sourcePath - Optional file path for error reporting
|
|
57
|
+
* @returns A LoadedSchema
|
|
58
|
+
*/
|
|
59
|
+
export function loadSchemaFromSDL(sdl, sourcePath) {
|
|
60
|
+
const documents = [{ filePath: sourcePath ?? '<inline>', sdl }];
|
|
61
|
+
return buildLoadedSchema(sdl, documents);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Build a LoadedSchema from concatenated SDL and per-file document list.
|
|
65
|
+
*/
|
|
66
|
+
function buildLoadedSchema(sdl, documents) {
|
|
67
|
+
const gql = requireGraphQL();
|
|
68
|
+
const schema = gql.buildSchema(sdl);
|
|
69
|
+
return { schema, documents };
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Recursively find .graphql files in a directory that match the given predicate.
|
|
73
|
+
*/
|
|
74
|
+
function findGraphqlFiles(dir, matcher, rootDir) {
|
|
75
|
+
const root = rootDir ?? dir;
|
|
76
|
+
const results = [];
|
|
77
|
+
let entries;
|
|
78
|
+
try {
|
|
79
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
void err; // unreadable dir — deliberately skipped
|
|
83
|
+
return results;
|
|
84
|
+
}
|
|
85
|
+
for (const entry of entries) {
|
|
86
|
+
const fullPath = path.join(dir, entry.name);
|
|
87
|
+
if (entry.isDirectory()) {
|
|
88
|
+
results.push(...findGraphqlFiles(fullPath, matcher, root));
|
|
89
|
+
}
|
|
90
|
+
else if (entry.name.endsWith('.graphql')) {
|
|
91
|
+
const relativePath = path.relative(root, fullPath);
|
|
92
|
+
if (matcher(relativePath)) {
|
|
93
|
+
results.push(fullPath);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return results.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Check whether the graphql package is available.
|
|
101
|
+
* Used by the runtime guard in the barrel export.
|
|
102
|
+
*/
|
|
103
|
+
export function isGraphQLAvailable() {
|
|
104
|
+
try {
|
|
105
|
+
requireGraphQL();
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
void err; // probe: "not available" IS the answer
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=schema-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-loader.js","sourceRoot":"","sources":["../../src/graphql/schema-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Predicate } from '@nielspeter/eess';
|
|
2
|
+
import type { GraphQLFieldLike, GraphQLObjectTypeLike } from './schema-loader.js';
|
|
3
|
+
/**
|
|
4
|
+
* A schema element that predicates and conditions operate on.
|
|
5
|
+
*
|
|
6
|
+
* Represents either an object type or a field within a type.
|
|
7
|
+
*/
|
|
8
|
+
export interface SchemaElement {
|
|
9
|
+
/** The type this element belongs to (or is) */
|
|
10
|
+
readonly typeName: string;
|
|
11
|
+
/** The field name (undefined if the element is a type itself) */
|
|
12
|
+
readonly fieldName?: string;
|
|
13
|
+
/** The GraphQL object type */
|
|
14
|
+
readonly objectType: GraphQLObjectTypeLike;
|
|
15
|
+
/** The GraphQL field (present when element is a field) */
|
|
16
|
+
readonly field?: GraphQLFieldLike;
|
|
17
|
+
/** Source file path (for violation reporting) */
|
|
18
|
+
readonly filePath?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Filter to only Query root type fields.
|
|
22
|
+
*/
|
|
23
|
+
export declare function queries(): Predicate<SchemaElement>;
|
|
24
|
+
/**
|
|
25
|
+
* Filter to only Mutation root type fields.
|
|
26
|
+
*/
|
|
27
|
+
export declare function mutations(): Predicate<SchemaElement>;
|
|
28
|
+
/**
|
|
29
|
+
* Filter to object types whose name matches the given pattern.
|
|
30
|
+
*
|
|
31
|
+
* @param pattern - Regex or exact string to match type names
|
|
32
|
+
*/
|
|
33
|
+
export declare function typesNamed(pattern: RegExp | string): Predicate<SchemaElement>;
|
|
34
|
+
/**
|
|
35
|
+
* Filter to fields whose return type is a list of the given type.
|
|
36
|
+
*
|
|
37
|
+
* Matches GraphQL return types like `[User]`, `[User!]`, `[User!]!`.
|
|
38
|
+
*
|
|
39
|
+
* @param typeName - The inner type name (exact string or regex)
|
|
40
|
+
*/
|
|
41
|
+
export declare function returnListOf(typeName: string | RegExp): Predicate<SchemaElement>;
|
|
42
|
+
//# sourceMappingURL=schema-predicates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-predicates.d.ts","sourceRoot":"","sources":["../../src/graphql/schema-predicates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAEjF;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,+CAA+C;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,iEAAiE;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,8BAA8B;IAC9B,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAA;IAC1C,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACjC,iDAAiD;IACjD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED;;GAEG;AACH,wBAAgB,OAAO,IAAI,SAAS,CAAC,aAAa,CAAC,CAOlD;AAED;;GAEG;AACH,wBAAgB,SAAS,IAAI,SAAS,CAAC,aAAa,CAAC,CAOpD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,aAAa,CAAC,CAgB7E;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,aAAa,CAAC,CAkBhF"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filter to only Query root type fields.
|
|
3
|
+
*/
|
|
4
|
+
export function queries() {
|
|
5
|
+
return {
|
|
6
|
+
description: 'are queries',
|
|
7
|
+
test(element) {
|
|
8
|
+
return element.typeName === 'Query' && element.field !== undefined;
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Filter to only Mutation root type fields.
|
|
14
|
+
*/
|
|
15
|
+
export function mutations() {
|
|
16
|
+
return {
|
|
17
|
+
description: 'are mutations',
|
|
18
|
+
test(element) {
|
|
19
|
+
return element.typeName === 'Mutation' && element.field !== undefined;
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Filter to object types whose name matches the given pattern.
|
|
25
|
+
*
|
|
26
|
+
* @param pattern - Regex or exact string to match type names
|
|
27
|
+
*/
|
|
28
|
+
export function typesNamed(pattern) {
|
|
29
|
+
const desc = typeof pattern === 'string' ? `"${pattern}"` : String(pattern);
|
|
30
|
+
if (typeof pattern === 'string') {
|
|
31
|
+
return {
|
|
32
|
+
description: `types named ${desc}`,
|
|
33
|
+
test(element) {
|
|
34
|
+
return element.field === undefined && element.typeName === pattern;
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
description: `types named ${desc}`,
|
|
40
|
+
test(element) {
|
|
41
|
+
return element.field === undefined && pattern.test(element.typeName);
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Filter to fields whose return type is a list of the given type.
|
|
47
|
+
*
|
|
48
|
+
* Matches GraphQL return types like `[User]`, `[User!]`, `[User!]!`.
|
|
49
|
+
*
|
|
50
|
+
* @param typeName - The inner type name (exact string or regex)
|
|
51
|
+
*/
|
|
52
|
+
export function returnListOf(typeName) {
|
|
53
|
+
const desc = typeof typeName === 'string' ? `"${typeName}"` : String(typeName);
|
|
54
|
+
return {
|
|
55
|
+
description: `return list of ${desc}`,
|
|
56
|
+
test(element) {
|
|
57
|
+
if (!element.field)
|
|
58
|
+
return false;
|
|
59
|
+
const typeStr = element.field.type.toString();
|
|
60
|
+
// Match [TypeName], [TypeName!], [TypeName!]!, [TypeName]!
|
|
61
|
+
const listMatch = /^\[(.+?)!?\]!?$/.exec(typeStr);
|
|
62
|
+
if (!listMatch)
|
|
63
|
+
return false;
|
|
64
|
+
const innerType = listMatch[1];
|
|
65
|
+
if (innerType === undefined)
|
|
66
|
+
return false;
|
|
67
|
+
if (typeof typeName === 'string') {
|
|
68
|
+
return innerType === typeName;
|
|
69
|
+
}
|
|
70
|
+
return typeName.test(innerType);
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=schema-predicates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-predicates.js","sourceRoot":"","sources":["../../src/graphql/schema-predicates.ts"],"names":[],"mappings":"AAqBA;;GAEG;AACH,MAAM,UAAU,OAAO;IACrB,OAAO;QACL,WAAW,EAAE,aAAa;QAC1B,IAAI,CAAC,OAAsB;YACzB,OAAO,OAAO,CAAC,QAAQ,KAAK,OAAO,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,CAAA;QACpE,CAAC;KACF,CAAA;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS;IACvB,OAAO;QACL,WAAW,EAAE,eAAe;QAC5B,IAAI,CAAC,OAAsB;YACzB,OAAO,OAAO,CAAC,QAAQ,KAAK,UAAU,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,CAAA;QACvE,CAAC;KACF,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,OAAwB;IACjD,MAAM,IAAI,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;IAC3E,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,OAAO;YACL,WAAW,EAAE,eAAe,IAAI,EAAE;YAClC,IAAI,CAAC,OAAsB;gBACzB,OAAO,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAA;YACpE,CAAC;SACF,CAAA;IACH,CAAC;IACD,OAAO;QACL,WAAW,EAAE,eAAe,IAAI,EAAE;QAClC,IAAI,CAAC,OAAsB;YACzB,OAAO,OAAO,CAAC,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QACtE,CAAC;KACF,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,QAAyB;IACpD,MAAM,IAAI,GAAG,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IAC9E,OAAO;QACL,WAAW,EAAE,kBAAkB,IAAI,EAAE;QACrC,IAAI,CAAC,OAAsB;YACzB,IAAI,CAAC,OAAO,CAAC,KAAK;gBAAE,OAAO,KAAK,CAAA;YAChC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAA;YAC7C,2DAA2D;YAC3D,MAAM,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YACjD,IAAI,CAAC,SAAS;gBAAE,OAAO,KAAK,CAAA;YAC5B,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;YAC9B,IAAI,SAAS,KAAK,SAAS;gBAAE,OAAO,KAAK,CAAA;YACzC,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBACjC,OAAO,SAAS,KAAK,QAAQ,CAAA;YAC/B,CAAC;YACD,OAAO,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QACjC,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { ArchViolation } from '../core/violation.js';
|
|
2
|
+
import { TerminalBuilder } from '@nielspeter/eess';
|
|
3
|
+
import type { LoadedSchema } from './schema-loader.js';
|
|
4
|
+
/**
|
|
5
|
+
* Fluent rule builder for GraphQL schema architecture rules.
|
|
6
|
+
*
|
|
7
|
+
* Operates on SchemaElements extracted from .graphql files.
|
|
8
|
+
* Follows the same builder pattern as SliceRuleBuilder (standalone, not extending RuleBuilder).
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* schema(p, 'src/schema/*.graphql')
|
|
13
|
+
* .typesNamed(/Collection$/)
|
|
14
|
+
* .should()
|
|
15
|
+
* .haveFields('total', 'skip', 'limit', 'items')
|
|
16
|
+
* .check()
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare class SchemaRuleBuilder extends TerminalBuilder {
|
|
20
|
+
private readonly loaded;
|
|
21
|
+
private readonly _predicates;
|
|
22
|
+
private readonly _conditions;
|
|
23
|
+
constructor(loaded: LoadedSchema);
|
|
24
|
+
/**
|
|
25
|
+
* Filter to only Query root type fields.
|
|
26
|
+
*/
|
|
27
|
+
queries(): this;
|
|
28
|
+
/**
|
|
29
|
+
* Filter to only Mutation root type fields.
|
|
30
|
+
*/
|
|
31
|
+
mutations(): this;
|
|
32
|
+
/**
|
|
33
|
+
* Filter to object types matching the given name pattern.
|
|
34
|
+
*/
|
|
35
|
+
typesNamed(pattern: RegExp | string): this;
|
|
36
|
+
/**
|
|
37
|
+
* Filter to fields returning a list of the given type.
|
|
38
|
+
*/
|
|
39
|
+
returnListOf(typeName: string | RegExp): this;
|
|
40
|
+
/**
|
|
41
|
+
* Begin the predicate phase. Purely a readability marker.
|
|
42
|
+
*/
|
|
43
|
+
that(): this;
|
|
44
|
+
/**
|
|
45
|
+
* Add another predicate (AND).
|
|
46
|
+
*/
|
|
47
|
+
and(): this;
|
|
48
|
+
/**
|
|
49
|
+
* Begin the condition phase.
|
|
50
|
+
*/
|
|
51
|
+
should(): this;
|
|
52
|
+
/**
|
|
53
|
+
* Add another condition (AND).
|
|
54
|
+
*/
|
|
55
|
+
andShould(): this;
|
|
56
|
+
/**
|
|
57
|
+
* Assert that types have all listed fields.
|
|
58
|
+
*/
|
|
59
|
+
haveFields(...names: string[]): this;
|
|
60
|
+
/**
|
|
61
|
+
* Assert that fields accept all listed arguments.
|
|
62
|
+
*/
|
|
63
|
+
acceptArgs(...names: string[]): this;
|
|
64
|
+
/**
|
|
65
|
+
* Assert that schema fields have matching resolver implementations.
|
|
66
|
+
*
|
|
67
|
+
* @param resolverFileTexts - Map of file paths to source text
|
|
68
|
+
*/
|
|
69
|
+
haveMatchingResolver(resolverFileTexts: ReadonlyMap<string, string>): this;
|
|
70
|
+
protected collectViolations(): ArchViolation[];
|
|
71
|
+
private getElements;
|
|
72
|
+
private buildRuleDescription;
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=schema-rule-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema-rule-builder.d.ts","sourceRoot":"","sources":["../../src/graphql/schema-rule-builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEzD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAElD,OAAO,KAAK,EAAE,YAAY,EAA0C,MAAM,oBAAoB,CAAA;AA2B9F;;;;;;;;;;;;;;GAcG;AACH,qBAAa,iBAAkB,SAAQ,eAAe;IAIxC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAiC;IAC7D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAiC;gBAEhC,MAAM,EAAE,YAAY;IAMjD;;OAEG;IACH,OAAO,IAAI,IAAI;IAKf;;OAEG;IACH,SAAS,IAAI,IAAI;IAKjB;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAK1C;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAO7C;;OAEG;IACH,IAAI,IAAI,IAAI;IAIZ;;OAEG;IACH,GAAG,IAAI,IAAI;IAIX;;OAEG;IACH,MAAM,IAAI,IAAI;IAId;;OAEG;IACH,SAAS,IAAI,IAAI;IAMjB;;OAEG;IACH,UAAU,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;IAKpC;;OAEG;IACH,UAAU,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;IAKpC;;;;OAIG;IACH,oBAAoB,CAAC,iBAAiB,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAO1E,SAAS,CAAC,iBAAiB,IAAI,aAAa,EAAE;IAmC9C,OAAO,CAAC,WAAW;IAqCnB,OAAO,CAAC,oBAAoB;CAQ7B"}
|