@manot40/genql-cli 1.0.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.
@@ -0,0 +1,133 @@
1
+ import type {
2
+ CompressedType,
3
+ CompressedTypeMap,
4
+ LinkedArgMap,
5
+ LinkedField,
6
+ LinkedType,
7
+ LinkedTypeMap,
8
+ } from './types';
9
+
10
+ export interface PartialLinkedFieldMap {
11
+ [field: string]: {
12
+ type: string;
13
+ args?: LinkedArgMap;
14
+ };
15
+ }
16
+
17
+ export const linkTypeMap = (typeMap: CompressedTypeMap<number>): LinkedTypeMap => {
18
+ const indexToName: Record<number, string> = Object.assign(
19
+ {},
20
+ ...Object.keys(typeMap.types).map((k, i) => ({ [i]: k }))
21
+ );
22
+
23
+ let intermediaryTypeMap = Object.assign(
24
+ {},
25
+ ...Object.keys(typeMap.types || {}).map((k): Record<string, LinkedType> => {
26
+ const type: CompressedType = typeMap.types[k]!;
27
+ const fields = type || {};
28
+ return {
29
+ [k]: {
30
+ name: k,
31
+ // type scalar properties
32
+ scalar: Object.keys(fields).filter((f) => {
33
+ const [type] = fields[f] || [];
34
+
35
+ const isScalar = type && typeMap.scalars.includes(type);
36
+ if (!isScalar) {
37
+ return false;
38
+ }
39
+ const args = fields[f]?.[1];
40
+ const argTypes = Object.values(args || {})
41
+ .map((x) => x?.[1])
42
+ .filter(Boolean);
43
+
44
+ const hasRequiredArgs = argTypes.some((str) => str && str.endsWith('!'));
45
+ if (hasRequiredArgs) {
46
+ return false;
47
+ }
48
+ return true;
49
+ }),
50
+ // fields with corresponding `type` and `args`
51
+ fields: Object.assign(
52
+ {},
53
+ ...Object.keys(fields).map((f): PartialLinkedFieldMap => {
54
+ const [typeIndex, args] = fields[f] || [];
55
+ if (typeIndex == null) {
56
+ return {};
57
+ }
58
+ return {
59
+ [f]: {
60
+ // replace index with type name
61
+ type: indexToName[typeIndex],
62
+ args: Object.assign(
63
+ {},
64
+ ...Object.keys(args || {}).map((k) => {
65
+ // if argTypeString == argTypeName, argTypeString is missing, need to readd it
66
+ if (!args || !args[k]) {
67
+ return;
68
+ }
69
+ const [argTypeName, argTypeString] = args[k] as any;
70
+ return {
71
+ [k]: [indexToName[argTypeName], argTypeString || indexToName[argTypeName]],
72
+ };
73
+ })
74
+ ),
75
+ },
76
+ };
77
+ })
78
+ ),
79
+ },
80
+ };
81
+ })
82
+ );
83
+ const res = resolveConcreteTypes(intermediaryTypeMap);
84
+ return res;
85
+ };
86
+
87
+ // replace typename with concrete type
88
+ export const resolveConcreteTypes = (linkedTypeMap: LinkedTypeMap) => {
89
+ Object.keys(linkedTypeMap).forEach((typeNameFromKey) => {
90
+ const type: LinkedType = linkedTypeMap[typeNameFromKey]!;
91
+ // type.name = typeNameFromKey
92
+ if (!type.fields) {
93
+ return;
94
+ }
95
+
96
+ const fields = type.fields;
97
+
98
+ Object.keys(fields).forEach((f) => {
99
+ const field: LinkedField = fields[f]!;
100
+
101
+ if (field.args) {
102
+ const args = field.args;
103
+ Object.keys(args).forEach((key) => {
104
+ const arg = args[key];
105
+
106
+ if (arg) {
107
+ const [typeName] = arg;
108
+
109
+ if (typeof typeName === 'string') {
110
+ if (!linkedTypeMap[typeName]) {
111
+ linkedTypeMap[typeName] = { name: typeName };
112
+ }
113
+
114
+ arg[0] = linkedTypeMap[typeName]!;
115
+ }
116
+ }
117
+ });
118
+ }
119
+
120
+ const typeName = field.type as LinkedType | string;
121
+
122
+ if (typeof typeName === 'string') {
123
+ if (!linkedTypeMap[typeName]) {
124
+ linkedTypeMap[typeName] = { name: typeName };
125
+ }
126
+
127
+ field.type = linkedTypeMap[typeName]!;
128
+ }
129
+ });
130
+ });
131
+
132
+ return linkedTypeMap;
133
+ };
@@ -0,0 +1,86 @@
1
+ //////////////////////////////////////////////////
2
+
3
+ // SOME THINGS TO KNOW BEFORE DIVING IN
4
+ /*
5
+ 0. DST is the request type, SRC is the response type
6
+
7
+ 1. FieldsSelection uses an object because currently is impossible to make recursive types
8
+
9
+ 2. FieldsSelection is a recursive type that makes a type based on request type and fields
10
+
11
+ 3. HandleObject handles object types
12
+
13
+ 4. Handle__scalar adds all scalar properties excluding non scalar props
14
+ */
15
+
16
+ export type FieldsSelection<SRC extends Anify<DST> | undefined, DST> = {
17
+ scalar: SRC;
18
+ union: Handle__isUnion<SRC, DST>;
19
+ object: HandleObject<SRC, DST>;
20
+ array: SRC extends Nil ? never : SRC extends Array<infer T | null> ? Array<FieldsSelection<T, DST>> : never;
21
+ __scalar: Handle__scalar<SRC, DST>;
22
+ never: never;
23
+ }[DST extends Nil
24
+ ? 'never'
25
+ : DST extends false | 0
26
+ ? 'never'
27
+ : SRC extends Scalar
28
+ ? 'scalar'
29
+ : SRC extends any[]
30
+ ? 'array'
31
+ : SRC extends { __isUnion?: any }
32
+ ? 'union'
33
+ : DST extends { __scalar?: any }
34
+ ? '__scalar'
35
+ : DST extends {}
36
+ ? 'object'
37
+ : 'never'];
38
+
39
+ type HandleObject<SRC extends Anify<DST>, DST> = DST extends boolean
40
+ ? SRC
41
+ : SRC extends Nil
42
+ ? never
43
+ : Pick<
44
+ {
45
+ // using keyof SRC to maintain ?: relations of SRC type
46
+ [Key in keyof SRC]: Key extends keyof DST
47
+ ? FieldsSelection<SRC[Key], NonNullable<DST[Key]>>
48
+ : SRC[Key];
49
+ },
50
+ Exclude<keyof DST, FieldsToRemove>
51
+ // {
52
+ // // remove falsy values
53
+ // [Key in keyof DST]: DST[Key] extends false | 0 ? never : Key
54
+ // }[keyof DST]
55
+ >;
56
+
57
+ type Handle__scalar<SRC extends Anify<DST>, DST> = SRC extends Nil
58
+ ? never
59
+ : Pick<
60
+ // continue processing fields that are in DST, directly pass SRC type if not in DST
61
+ {
62
+ [Key in keyof SRC]: Key extends keyof DST ? FieldsSelection<SRC[Key], DST[Key]> : SRC[Key];
63
+ },
64
+ // remove fields that are not scalars or are not in DST
65
+ {
66
+ [Key in keyof SRC]: SRC[Key] extends Nil
67
+ ? never
68
+ : Key extends FieldsToRemove
69
+ ? never
70
+ : SRC[Key] extends Scalar
71
+ ? Key
72
+ : Key extends keyof DST
73
+ ? Key
74
+ : never;
75
+ }[keyof SRC]
76
+ >;
77
+
78
+ type Handle__isUnion<SRC extends Anify<DST>, DST> = SRC extends Nil ? never : Omit<SRC, FieldsToRemove>; // just return the union type
79
+
80
+ type Scalar = string | number | Date | boolean | null | undefined;
81
+
82
+ type Anify<T> = { [P in keyof T]?: any };
83
+
84
+ type FieldsToRemove = '__isUnion' | '__scalar' | '__name' | '__args';
85
+
86
+ type Nil = undefined | null;
@@ -0,0 +1,64 @@
1
+ export interface ExecutionResult<TData = { [key: string]: any }> {
2
+ errors?: Array<Error>;
3
+ data?: TData | null;
4
+ }
5
+
6
+ export interface ArgMap<keyType = number> {
7
+ [arg: string]: [keyType, string] | [keyType] | undefined;
8
+ }
9
+
10
+ export type CompressedField<keyType = number> = [type: keyType, args?: ArgMap<keyType>];
11
+
12
+ export interface CompressedFieldMap<keyType = number> {
13
+ [field: string]: CompressedField<keyType> | undefined;
14
+ }
15
+
16
+ export type CompressedType<keyType = number> = CompressedFieldMap<keyType>;
17
+
18
+ export interface CompressedTypeMap<keyType = number> {
19
+ scalars: Array<keyType>;
20
+ types: {
21
+ [type: string]: CompressedType<keyType> | undefined;
22
+ };
23
+ }
24
+
25
+ // normal types
26
+ export type Field<keyType = number> = {
27
+ type: keyType;
28
+ args?: ArgMap<keyType>;
29
+ };
30
+
31
+ export interface FieldMap<keyType = number> {
32
+ [field: string]: Field<keyType> | undefined;
33
+ }
34
+
35
+ export type Type<keyType = number> = FieldMap<keyType>;
36
+
37
+ export interface TypeMap<keyType = number> {
38
+ scalars: Array<keyType>;
39
+ types: {
40
+ [type: string]: Type<keyType> | undefined;
41
+ };
42
+ }
43
+
44
+ export interface LinkedArgMap {
45
+ [arg: string]: [LinkedType, string] | undefined;
46
+ }
47
+ export interface LinkedField {
48
+ type: LinkedType;
49
+ args?: LinkedArgMap;
50
+ }
51
+
52
+ export interface LinkedFieldMap {
53
+ [field: string]: LinkedField | undefined;
54
+ }
55
+
56
+ export interface LinkedType {
57
+ name: string;
58
+ fields?: LinkedFieldMap;
59
+ scalar?: string[];
60
+ }
61
+
62
+ export interface LinkedTypeMap {
63
+ [type: string]: LinkedType | undefined;
64
+ }
package/package.json ADDED
@@ -0,0 +1,96 @@
1
+ {
2
+ "type": "module",
3
+ "name": "@manot40/genql-cli",
4
+ "author": "Tommaso De Rossi, morse <beats.by.morse@gmail.com>",
5
+ "license": "MIT",
6
+ "version": "1.0.0",
7
+ "homepage": "https://genql.dev",
8
+ "description": "Generate a TypeScript SDK for any GraphQl API",
9
+ "keywords": [
10
+ "genql",
11
+ "graphql",
12
+ "sdk",
13
+ "typescript"
14
+ ],
15
+ "repository": {
16
+ "url": "https://github.com/manot40/genql"
17
+ },
18
+ "bin": {
19
+ "genql": "./cli.mjs"
20
+ },
21
+ "exports": {
22
+ ".": "./dist/index.mjs",
23
+ "./cli": "./dist/cli.mjs",
24
+ "./package.json": "./package.json"
25
+ },
26
+ "files": [
27
+ "dist"
28
+ ],
29
+ "scripts": {
30
+ "build": "rm -rf dist esm *.tsbuildinfo && tsdown",
31
+ "test": "jest"
32
+ },
33
+ "devDependencies": {
34
+ "@types/common-tags": "^1.8.1",
35
+ "@types/fs-extra": "^11.0.1",
36
+ "@types/jest": "^30.0.0",
37
+ "@types/lodash-es": "^4.17.12",
38
+ "@types/mkdirp": "^2.0.0",
39
+ "@types/node": "^18.19.130",
40
+ "@types/prettier": "^3.0.0",
41
+ "@types/rimraf": "^4.0.5",
42
+ "@types/yargs": "^17.0.35",
43
+ "changelogen": "^0.6.2",
44
+ "common-tags": "^1.8.2",
45
+ "jest": "^29.3.1",
46
+ "prettier": "^3.7.4",
47
+ "pretty-quick": "^3.1.3",
48
+ "ts-jest": "^29.4.6",
49
+ "tsdown": "^0.19.0-beta.3"
50
+ },
51
+ "dependencies": {
52
+ "@graphql-tools/graphql-file-loader": "^8.1.9",
53
+ "@graphql-tools/load": "^8.1.8",
54
+ "fs-extra": "^11.3.3",
55
+ "graphql": "^16.12.0",
56
+ "kleur": "^4.1.5",
57
+ "listr2": "^9.0.5",
58
+ "lodash-es": "^4.17.22",
59
+ "mkdirp": "^3.0.1",
60
+ "rimraf": "^6.1.2",
61
+ "ufo": "^1.6.2",
62
+ "undici": "^7.18.2",
63
+ "yargs": "^18.0.0"
64
+ },
65
+ "peerDependencies": {
66
+ "prettier": "3.x"
67
+ },
68
+ "jest": {
69
+ "transform": {
70
+ ".(js|jsx|ts|tsx)": "@sucrase/jest-plugin"
71
+ },
72
+ "roots": [
73
+ "<rootDir>/src"
74
+ ],
75
+ "moduleFileExtensions": [
76
+ "ts",
77
+ "tsx",
78
+ "js",
79
+ "jsx",
80
+ "json",
81
+ "node"
82
+ ],
83
+ "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
84
+ "testEnvironment": "node",
85
+ "collectCoverageFrom": [
86
+ "src/**/*.ts",
87
+ "!**/node_modules/**",
88
+ "!src/_old/**",
89
+ "!**/*.case.ts",
90
+ "!src/testHelpers/**/*.ts"
91
+ ],
92
+ "coverageReporters": [
93
+ "text"
94
+ ]
95
+ }
96
+ }