@book000/twitterts 0.26.1 → 0.28.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/converter.d.ts +2 -2
- package/dist/converter.d.ts.map +1 -1
- package/dist/converter.js +4 -4
- package/dist/converter.js.map +1 -1
- package/dist/generate-types/custom-types-generator.d.ts +53 -0
- package/dist/generate-types/custom-types-generator.d.ts.map +1 -0
- package/dist/generate-types/custom-types-generator.js +394 -0
- package/dist/generate-types/custom-types-generator.js.map +1 -0
- package/dist/generate-types/endpoint-type-generator.d.ts +66 -0
- package/dist/generate-types/endpoint-type-generator.d.ts.map +1 -0
- package/dist/generate-types/endpoint-type-generator.js +187 -0
- package/dist/generate-types/endpoint-type-generator.js.map +1 -0
- package/dist/generate-types/types-generator.d.ts +49 -0
- package/dist/generate-types/types-generator.d.ts.map +1 -0
- package/dist/generate-types/types-generator.js +89 -0
- package/dist/generate-types/types-generator.js.map +1 -0
- package/dist/generate-types/utils.d.ts +95 -0
- package/dist/generate-types/utils.d.ts.map +1 -0
- package/dist/generate-types/utils.js +160 -0
- package/dist/generate-types/utils.js.map +1 -0
- package/dist/generate-types.js +41 -741
- package/dist/generate-types.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/models/responses/custom/custom-search-timeline-entry.d.ts +2 -2
- package/dist/models/responses/custom/custom-search-timeline-entry.d.ts.map +1 -1
- package/dist/models/responses/custom/custom-timeline-tweet-entry.d.ts +42 -8
- package/dist/models/responses/custom/custom-timeline-tweet-entry.d.ts.map +1 -1
- package/dist/models/responses/custom/custom-tweet-legacy-object.d.ts +1 -0
- package/dist/models/responses/custom/custom-tweet-legacy-object.d.ts.map +1 -1
- package/dist/models/responses/custom/custom-tweet-object.d.ts +60 -17
- package/dist/models/responses/custom/custom-tweet-object.d.ts.map +1 -1
- package/dist/models/responses/custom/custom-user-legacy-object.d.ts +55 -0
- package/dist/models/responses/custom/custom-user-legacy-object.d.ts.map +1 -0
- package/dist/models/responses/custom/custom-user-legacy-object.js +4 -0
- package/dist/models/responses/custom/custom-user-legacy-object.js.map +1 -0
- package/dist/models/responses/custom/custom-user-like-tweet-entry.d.ts +103 -2
- package/dist/models/responses/custom/custom-user-like-tweet-entry.d.ts.map +1 -1
- package/dist/models/responses/custom/custom-user-tweet-entry.d.ts +1 -0
- package/dist/models/responses/custom/custom-user-tweet-entry.d.ts.map +1 -1
- package/dist/models/responses/endpoints.d.ts +5 -2
- package/dist/models/responses/endpoints.d.ts.map +1 -1
- package/dist/models/responses/graphql/get/audio-space-by-id-success.d.ts +4 -4
- package/dist/models/responses/graphql/get/audio-space-by-id-success.d.ts.map +1 -1
- package/dist/models/responses/graphql/get/follow-host-button-query-success.d.ts +19 -0
- package/dist/models/responses/graphql/get/follow-host-button-query-success.d.ts.map +1 -0
- package/dist/models/responses/graphql/get/follow-host-button-query-success.js +4 -0
- package/dist/models/responses/graphql/get/follow-host-button-query-success.js.map +1 -0
- package/dist/models/responses/graphql/get/home-latest-timeline-success.d.ts +27 -3
- package/dist/models/responses/graphql/get/home-latest-timeline-success.d.ts.map +1 -1
- package/dist/models/responses/graphql/get/home-timeline-success.d.ts +283 -13
- package/dist/models/responses/graphql/get/home-timeline-success.d.ts.map +1 -1
- package/dist/models/responses/graphql/get/likes-success.d.ts +103 -2
- package/dist/models/responses/graphql/get/likes-success.d.ts.map +1 -1
- package/dist/models/responses/graphql/get/search-timeline-success.d.ts +2 -2
- package/dist/models/responses/graphql/get/search-timeline-success.d.ts.map +1 -1
- package/dist/models/responses/graphql/get/user-tweets-success.d.ts +1 -0
- package/dist/models/responses/graphql/get/user-tweets-success.d.ts.map +1 -1
- package/dist/models/responses/graphql/post/home-latest-timeline-success.d.ts +11 -2
- package/dist/models/responses/graphql/post/home-latest-timeline-success.d.ts.map +1 -1
- package/dist/models/responses/graphql/post/home-timeline-success.d.ts +508 -32
- package/dist/models/responses/graphql/post/home-timeline-success.d.ts.map +1 -1
- package/dist/parser/home-timeline-parser.d.ts.map +1 -1
- package/dist/parser/search-timeline.d.ts.map +1 -1
- package/dist/parser/user-like-tweets.d.ts.map +1 -1
- package/dist/parser/user-tweets.d.ts.map +1 -1
- package/dist/scraper.d.ts.map +1 -1
- package/dist/scraper.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/twitter.d.ts +13 -9
- package/dist/twitter.d.ts.map +1 -1
- package/dist/twitter.js +2 -1
- package/dist/twitter.js.map +1 -1
- package/package.json +1 -1
package/dist/generate-types.js
CHANGED
|
@@ -1,755 +1,55 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
7
|
-
const json_schema_to_typescript_1 = require("json-schema-to-typescript");
|
|
8
3
|
const node_utils_1 = require("@book000/node-utils");
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* ユーティリティ
|
|
36
|
-
*/
|
|
37
|
-
const Utils = {
|
|
38
|
-
/**
|
|
39
|
-
* レスポンスの型定義名を取得する
|
|
40
|
-
*
|
|
41
|
-
* @param rawType リクエストの種別(graphql または rest)
|
|
42
|
-
* @param rawName レスポンスの名前
|
|
43
|
-
* @param rawMethod レスポンスの HTTP メソッド
|
|
44
|
-
* @param rawStatus レスポンスのステータスコード
|
|
45
|
-
* @returns 型定義名
|
|
46
|
-
*/
|
|
47
|
-
getName(rawType, rawName, rawMethod, rawStatus) {
|
|
48
|
-
const type = rawType.toLocaleLowerCase() === 'graphql'
|
|
49
|
-
? 'GraphQL'
|
|
50
|
-
: rawType.toLocaleLowerCase() === 'rest'
|
|
51
|
-
? 'REST'
|
|
52
|
-
: null;
|
|
53
|
-
if (!type) {
|
|
54
|
-
throw new Error(`Invalid type: ${rawType}`);
|
|
55
|
-
}
|
|
56
|
-
const method = this.toCamelCase(rawMethod);
|
|
57
|
-
const name = this.capitalize(rawName);
|
|
58
|
-
const status = rawStatus === null ? '' : rawStatus.startsWith('2') ? 'Success' : 'Error';
|
|
59
|
-
return `${type}${method}${name}${status}Response`;
|
|
60
|
-
},
|
|
61
|
-
/**
|
|
62
|
-
* キャメルケースに変換する
|
|
63
|
-
*
|
|
64
|
-
* @param string 変換する文字列
|
|
65
|
-
* @returns キャメルケース変換後の文字列
|
|
66
|
-
*/
|
|
67
|
-
toCamelCase(string) {
|
|
68
|
-
return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
|
|
69
|
-
},
|
|
70
|
-
/**
|
|
71
|
-
* 先頭文字を大文字に変換する
|
|
72
|
-
*
|
|
73
|
-
* @param string 変換する文字列
|
|
74
|
-
* @returns 変換後の文字列
|
|
75
|
-
*/
|
|
76
|
-
capitalize(string) {
|
|
77
|
-
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
78
|
-
},
|
|
79
|
-
/**
|
|
80
|
-
* ファイル名を取得する
|
|
81
|
-
*
|
|
82
|
-
* @param rawType リクエストの種別(graphql または rest)
|
|
83
|
-
* @param rawName レスポンスの名前
|
|
84
|
-
* @param rawMethod レスポンスの HTTP メソッド
|
|
85
|
-
* @param rawStatus レスポンスのステータスコード
|
|
86
|
-
* @returns ファイル名
|
|
87
|
-
*/
|
|
88
|
-
getFilename(rawType, rawName, rawMethod, rawStatus) {
|
|
89
|
-
const type = rawType.toLowerCase();
|
|
90
|
-
const method = rawMethod.toLowerCase();
|
|
91
|
-
const name = rawName.replaceAll(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
|
92
|
-
const status = rawStatus.startsWith('2') ? '-success' : '-error';
|
|
93
|
-
return `${type}/${method}/${name}${status}`;
|
|
94
|
-
},
|
|
95
|
-
};
|
|
96
|
-
/**
|
|
97
|
-
* 型定義生成クラス
|
|
98
|
-
*/
|
|
99
|
-
class TwitterTypesGenerator {
|
|
100
|
-
/**
|
|
101
|
-
* @param options 型定義生成クラスのオプション
|
|
102
|
-
*/
|
|
103
|
-
constructor(options) {
|
|
104
|
-
this.options = options;
|
|
105
|
-
}
|
|
106
|
-
/**
|
|
107
|
-
* ディレクトリ内にあるディレクトリ群を取得する
|
|
108
|
-
*
|
|
109
|
-
* @param baseDirectories ディレクトリを取得するディレクトリパス
|
|
110
|
-
* @returns ディレクトリ群
|
|
111
|
-
*/
|
|
112
|
-
getDirectories(baseDirectories = []) {
|
|
113
|
-
const baseDirectory = (0, node_path_1.join)(this.options.debugOutputDirectory, ...baseDirectories);
|
|
114
|
-
return node_fs_1.default
|
|
115
|
-
.readdirSync(baseDirectory)
|
|
116
|
-
.filter((directory) => !['.', '..'].includes(directory) &&
|
|
117
|
-
node_fs_1.default.statSync(`${baseDirectory}/${directory}`).isDirectory());
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* ディレクトリ内にある JSON ファイル群を取得する
|
|
121
|
-
*
|
|
122
|
-
* @param baseDirectories ファイルを取得するディレクトリパス
|
|
123
|
-
* @returns JSON ファイル群
|
|
124
|
-
*/
|
|
125
|
-
getJSONFiles(baseDirectories = []) {
|
|
126
|
-
const baseDirectory = (0, node_path_1.join)(this.options.debugOutputDirectory, ...baseDirectories);
|
|
127
|
-
return node_fs_1.default
|
|
128
|
-
.readdirSync(baseDirectory)
|
|
129
|
-
.filter((file) => !['.', '..'].includes(file) &&
|
|
130
|
-
node_fs_1.default.statSync((0, node_path_1.join)(baseDirectory, file)).isFile() &&
|
|
131
|
-
file.endsWith('.json'))
|
|
132
|
-
.map((file) => (0, node_path_1.join)(baseDirectory, file));
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* レスポンスデバッグ出力 JSON ファイルを元に、エンドポイントごとの情報をまとめて取得する
|
|
136
|
-
*
|
|
137
|
-
* @returns エンドポイントごとの情報
|
|
138
|
-
*/
|
|
139
|
-
get() {
|
|
140
|
-
const results = [];
|
|
141
|
-
for (const type of this.getDirectories()) {
|
|
142
|
-
for (const name of this.getDirectories([type])) {
|
|
143
|
-
for (const method of this.getDirectories([type, name])) {
|
|
144
|
-
for (const statusCode of this.getDirectories([type, name, method])) {
|
|
145
|
-
results.push({
|
|
146
|
-
type,
|
|
147
|
-
name,
|
|
148
|
-
method,
|
|
149
|
-
statusCode,
|
|
150
|
-
paths: this.getJSONFiles([type, name, method, statusCode]),
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
return results;
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* エンドポイントの型定義を生成する
|
|
160
|
-
*
|
|
161
|
-
* @param options 単一の型定義生成オプション
|
|
162
|
-
* @param result エンドポイントごとのレスポンス情報
|
|
163
|
-
*/
|
|
164
|
-
async generateType(options, result) {
|
|
165
|
-
const logger = node_utils_1.Logger.configure('TwitterGenerateTypes.generateType');
|
|
166
|
-
if (result.paths.length === 0) {
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
logger.info(`🔍 Generating: ${options.name}`);
|
|
170
|
-
let schema;
|
|
171
|
-
for (const path of result.paths) {
|
|
172
|
-
const data = JSON.parse(node_fs_1.default.readFileSync(path, 'utf8'));
|
|
173
|
-
const fileSchema = (0, genson_js_1.createSchema)(data);
|
|
174
|
-
schema = schema ? (0, genson_js_1.mergeSchemas)([schema, fileSchema]) : fileSchema;
|
|
175
|
-
}
|
|
176
|
-
if (!schema) {
|
|
177
|
-
throw new Error('No schema found');
|
|
178
|
-
}
|
|
179
|
-
node_fs_1.default.mkdirSync((0, node_path_1.dirname)(options.path.schema), { recursive: true });
|
|
180
|
-
node_fs_1.default.writeFileSync(options.path.schema, JSON.stringify(schema, null, 2));
|
|
181
|
-
node_fs_1.default.mkdirSync((0, node_path_1.dirname)(options.path.types), { recursive: true });
|
|
182
|
-
const types = await (0, json_schema_to_typescript_1.compile)(schema, options.name, getCompileOptions(options.tsDocument));
|
|
183
|
-
node_fs_1.default.writeFileSync(options.path.types, types);
|
|
184
|
-
logger.info(`📝 Successful: ${options.name} (from ${result.paths.length} files)`);
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* 保存されたデバッグレスポンスを元に、全てのエンドポイントの型定義を生成する。
|
|
188
|
-
* カスタム型定義の生成(CustomTypeGenerator)や、エンドポイントのまとめ型定義も生成(EndPointTypeGenerator)する。
|
|
189
|
-
*
|
|
190
|
-
* @param options 型定義生成オプション
|
|
191
|
-
*/
|
|
192
|
-
async generateTypes(options) {
|
|
193
|
-
const results = this.get();
|
|
194
|
-
for (const result of results) {
|
|
195
|
-
const name = Utils.getName(result.type, result.name, result.method, result.statusCode);
|
|
196
|
-
const filename = Utils.getFilename(result.type, result.name, result.method, result.statusCode);
|
|
197
|
-
const schemaPath = `${options.directory.schema}/${filename}.json`;
|
|
198
|
-
const typesPath = `${options.directory.types}/${filename}.ts`;
|
|
199
|
-
const type = result.type === 'graphql'
|
|
200
|
-
? 'GraphQL'
|
|
201
|
-
: result.type === 'rest'
|
|
202
|
-
? 'REST'
|
|
203
|
-
: null;
|
|
204
|
-
await this.generateType({
|
|
205
|
-
path: {
|
|
206
|
-
schema: schemaPath,
|
|
207
|
-
types: typesPath,
|
|
208
|
-
},
|
|
209
|
-
name,
|
|
210
|
-
tsDocument: `${type} ${result.method} ${result.name} ${result.statusCode.startsWith('2') ? '成功' : '失敗'}レスポンスモデル`,
|
|
211
|
-
}, result);
|
|
212
|
-
}
|
|
213
|
-
await new CustomTypeGenerator(results, options.directory.schema, options.directory.types).generate();
|
|
214
|
-
new EndPointTypeGenerator(results, options.directory.types).generate();
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* デバッグレスポンスを元に、型定義を生成するメイン関数
|
|
218
|
-
*/
|
|
219
|
-
static async main() {
|
|
4
|
+
const types_generator_1 = require("./generate-types/types-generator");
|
|
5
|
+
const custom_types_generator_1 = require("./generate-types/custom-types-generator");
|
|
6
|
+
const endpoint_type_generator_1 = require("./generate-types/endpoint-type-generator");
|
|
7
|
+
const utils_1 = require("./generate-types/utils");
|
|
8
|
+
class GenerateTypes {
|
|
9
|
+
calculateTime(name, runner) {
|
|
10
|
+
const logger = node_utils_1.Logger.configure('GenerateTypes:calculateTime');
|
|
11
|
+
const startTime = Date.now();
|
|
12
|
+
const result = runner();
|
|
13
|
+
const endTime = Date.now();
|
|
14
|
+
const time = endTime - startTime;
|
|
15
|
+
logger.info(`🕐 ${name}: ${time}ms`);
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
async awaitCalculateTime(name, runner) {
|
|
19
|
+
const logger = node_utils_1.Logger.configure('GenerateTypes:awaitCalculateTime');
|
|
20
|
+
const startTime = Date.now();
|
|
21
|
+
const result = await runner();
|
|
22
|
+
const endTime = Date.now();
|
|
23
|
+
const time = endTime - startTime;
|
|
24
|
+
logger.info(`🕐 ${name}: ${time}ms`);
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
async run() {
|
|
28
|
+
const logger = node_utils_1.Logger.configure('GenerateTypes:run');
|
|
220
29
|
const debugOutputDirectory = process.env.DEBUG_OUTPUT_DIRECTORY || './data/responses';
|
|
221
30
|
const schemaDirectory = process.env.SCHEMA_DIRECTORY || './data/schema';
|
|
222
31
|
const typesDirectory = process.env.TYPES_DIRECTORY || './src/models/responses';
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
*/
|
|
237
|
-
class CustomTypeGenerator {
|
|
238
|
-
/**
|
|
239
|
-
* @param results エンドポイントごとのレスポンス情報
|
|
240
|
-
* @param schemaDirectory スキーマ保存ディレクトリ
|
|
241
|
-
* @param typesDirectory 型定義保存ディレクトリ
|
|
242
|
-
*/
|
|
243
|
-
constructor(results, schemaDirectory, typesDirectory) {
|
|
244
|
-
this.results = results;
|
|
245
|
-
this.schemaDirectory = schemaDirectory;
|
|
246
|
-
this.typesDirectory = typesDirectory;
|
|
247
|
-
}
|
|
248
|
-
/**
|
|
249
|
-
* 検索タイムラインツイートモデル(CustomSearchTimelineEntry)のカスタム型定義を生成する
|
|
250
|
-
*/
|
|
251
|
-
async runGraphQLSearchTimeline() {
|
|
252
|
-
const results = this.results.filter((result) => result.type === 'graphql' &&
|
|
253
|
-
result.name === 'SearchTimeline' &&
|
|
254
|
-
result.method === 'GET' &&
|
|
255
|
-
result.statusCode === '200');
|
|
256
|
-
if (results.length === 0) {
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
const paths = results.flatMap((result) => result.paths);
|
|
260
|
-
let schema;
|
|
261
|
-
for (const path of paths) {
|
|
262
|
-
const response = JSON.parse(node_fs_1.default.readFileSync(path, 'utf8'));
|
|
263
|
-
const entries = response.data.search_by_raw_query.search_timeline.timeline.instructions
|
|
264
|
-
.filter((instruction) => instruction.type === 'TimelineAddEntries' && instruction.entries)
|
|
265
|
-
.flatMap((instruction) => instruction.entries?.filter((entry) => entry.entryId.startsWith('tweet-')));
|
|
266
|
-
const fileSchema = (0, genson_js_1.createCompoundSchema)(entries);
|
|
267
|
-
schema = schema ? (0, genson_js_1.mergeSchemas)([schema, fileSchema]) : fileSchema;
|
|
268
|
-
}
|
|
269
|
-
if (!schema) {
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
await this.generateTypeFromSchema(schema, 'CustomSearchTimelineEntry', '検索タイムラインツイートモデル');
|
|
273
|
-
}
|
|
274
|
-
/**
|
|
275
|
-
* ユーザーツイートモデル(CustomUserTweetEntry)のカスタム型定義を生成する
|
|
276
|
-
*/
|
|
277
|
-
async runGraphQLUserTweets() {
|
|
278
|
-
const results = this.results.filter((result) => result.type === 'graphql' &&
|
|
279
|
-
result.name === 'UserTweets' &&
|
|
280
|
-
result.method === 'GET' &&
|
|
281
|
-
result.statusCode === '200');
|
|
282
|
-
if (results.length === 0) {
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
const paths = results.flatMap((result) => result.paths);
|
|
286
|
-
let schema;
|
|
287
|
-
for (const path of paths) {
|
|
288
|
-
const response = JSON.parse(node_fs_1.default.readFileSync(path, 'utf8'));
|
|
289
|
-
const entries = response.data.user.result.timeline_v2.timeline.instructions
|
|
290
|
-
.filter((instruction) => instruction.type === 'TimelineAddEntries' && instruction.entries)
|
|
291
|
-
.flatMap((instruction) => instruction.entries?.filter((entry) => entry.entryId.startsWith('tweet-')));
|
|
292
|
-
const fileSchema = (0, genson_js_1.createCompoundSchema)(entries);
|
|
293
|
-
schema = schema ? (0, genson_js_1.mergeSchemas)([schema, fileSchema]) : fileSchema;
|
|
294
|
-
}
|
|
295
|
-
if (!schema) {
|
|
296
|
-
return;
|
|
297
|
-
}
|
|
298
|
-
await this.generateTypeFromSchema(schema, 'CustomUserTweetEntry', 'ユーザーツイートモデル');
|
|
299
|
-
}
|
|
300
|
-
/**
|
|
301
|
-
* ユーザーいいねツイートモデル(CustomUserLikeTweetEntry)のカスタム型定義を生成する
|
|
302
|
-
*/
|
|
303
|
-
async runGraphQLUserLikeTweets() {
|
|
304
|
-
const results = this.results.filter((result) => result.type === 'graphql' &&
|
|
305
|
-
result.name === 'Likes' &&
|
|
306
|
-
result.method === 'GET' &&
|
|
307
|
-
result.statusCode === '200');
|
|
308
|
-
if (results.length === 0) {
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
const paths = results.flatMap((result) => result.paths);
|
|
312
|
-
let schema;
|
|
313
|
-
for (const path of paths) {
|
|
314
|
-
const response = JSON.parse(node_fs_1.default.readFileSync(path, 'utf8'));
|
|
315
|
-
const entries = response.data.user.result.timeline_v2.timeline.instructions
|
|
316
|
-
.filter((instruction) => instruction.type === 'TimelineAddEntries' && instruction.entries)
|
|
317
|
-
.flatMap((instruction) => instruction.entries?.filter((entry) => entry.entryId.startsWith('tweet-')));
|
|
318
|
-
const fileSchema = (0, genson_js_1.createCompoundSchema)(entries);
|
|
319
|
-
schema = schema ? (0, genson_js_1.mergeSchemas)([schema, fileSchema]) : fileSchema;
|
|
320
|
-
}
|
|
321
|
-
if (!schema) {
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
|
-
await this.generateTypeFromSchema(schema, 'CustomUserLikeTweetEntry', 'ユーザーいいねツイートエントリモデル');
|
|
325
|
-
}
|
|
326
|
-
async runGraphQLTimelineInstruction() {
|
|
327
|
-
const homeTimelineResults = this.results.filter((result) => result.type === 'graphql' &&
|
|
328
|
-
result.name === 'HomeTimeline' &&
|
|
329
|
-
result.method === 'GET' &&
|
|
330
|
-
result.statusCode === '200');
|
|
331
|
-
const homeLatestTimelineResults = this.results.filter((result) => result.type === 'graphql' &&
|
|
332
|
-
result.name === 'HomeLatestTimeline' &&
|
|
333
|
-
result.method === 'GET' &&
|
|
334
|
-
result.statusCode === '200');
|
|
335
|
-
if (homeTimelineResults.length === 0 &&
|
|
336
|
-
homeLatestTimelineResults.length === 0) {
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
const hometimelinePaths = homeTimelineResults.flatMap((result) => result.paths);
|
|
340
|
-
const homeLatestTimelinePaths = homeLatestTimelineResults.flatMap((result) => result.paths);
|
|
341
|
-
let schema;
|
|
342
|
-
for (const path of hometimelinePaths) {
|
|
343
|
-
const response = JSON.parse(node_fs_1.default.readFileSync(path, 'utf8'));
|
|
344
|
-
const entries = response.data.home.home_timeline_urt.instructions
|
|
345
|
-
.filter((instruction) => instruction.type === 'TimelineAddEntries' && instruction.entries)
|
|
346
|
-
.flatMap((instruction) => instruction.entries?.filter((entry) => entry.entryId.startsWith('tweet-')));
|
|
347
|
-
const fileSchema = (0, genson_js_1.createCompoundSchema)(entries);
|
|
348
|
-
schema = schema ? (0, genson_js_1.mergeSchemas)([schema, fileSchema]) : fileSchema;
|
|
349
|
-
}
|
|
350
|
-
for (const path of homeLatestTimelinePaths) {
|
|
351
|
-
const response = JSON.parse(node_fs_1.default.readFileSync(path, 'utf8'));
|
|
352
|
-
const instructions = response.data.home.home_timeline_urt.instructions
|
|
353
|
-
.filter((instruction) => instruction.type === 'TimelineAddEntries' && instruction.entries)
|
|
354
|
-
.flatMap((instruction) => instruction.entries?.filter((entry) => entry.entryId.startsWith('tweet-')));
|
|
355
|
-
const fileSchema = (0, genson_js_1.createCompoundSchema)(instructions);
|
|
356
|
-
schema = schema ? (0, genson_js_1.mergeSchemas)([schema, fileSchema]) : fileSchema;
|
|
357
|
-
}
|
|
358
|
-
if (!schema) {
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
361
|
-
await this.generateTypeFromSchema(schema, 'CustomTimelineTweetEntry', 'ホームタイムラインツイートエントリモデル');
|
|
362
|
-
}
|
|
363
|
-
// --- twitter-d 変換用オブジェクト
|
|
364
|
-
/**
|
|
365
|
-
* レスポンスツイートオブジェクト(CustomTweetObject)のカスタム型定義を生成する
|
|
366
|
-
*/
|
|
367
|
-
async runTweetObject() {
|
|
368
|
-
// 各レスポンスからツイートオブジェクトを抽出
|
|
369
|
-
const schemas = [
|
|
370
|
-
// HomeTimeline
|
|
371
|
-
this.results
|
|
372
|
-
.filter((result) => result.type === 'graphql' &&
|
|
373
|
-
result.name === 'HomeTimeline' &&
|
|
374
|
-
result.method === 'GET' &&
|
|
375
|
-
result.statusCode === '200')
|
|
376
|
-
.flatMap((result) => result.paths)
|
|
377
|
-
.flatMap((path) => {
|
|
378
|
-
const response = JSON.parse(node_fs_1.default.readFileSync(path, 'utf8'));
|
|
379
|
-
return response.data.home.home_timeline_urt.instructions
|
|
380
|
-
.filter((instruction) => instruction.type === 'TimelineAddEntries' && instruction.entries)
|
|
381
|
-
.flatMap((instruction) => instruction.entries?.filter((entry) => entry.entryId.startsWith('tweet-')));
|
|
382
|
-
})
|
|
383
|
-
.map((entry) => {
|
|
384
|
-
return entry.content.itemContent
|
|
385
|
-
.tweet_results.result;
|
|
386
|
-
})
|
|
387
|
-
.filter((entry) => !!entry)
|
|
388
|
-
.map((entry) => (0, genson_js_1.createSchema)(entry)),
|
|
389
|
-
// HomeLatestTimeline
|
|
390
|
-
this.results
|
|
391
|
-
.filter((result) => result.type === 'graphql' &&
|
|
392
|
-
result.name === 'HomeLatestTimeline' &&
|
|
393
|
-
result.method === 'GET' &&
|
|
394
|
-
result.statusCode === '200')
|
|
395
|
-
.flatMap((result) => result.paths)
|
|
396
|
-
.flatMap((path) => {
|
|
397
|
-
const response = JSON.parse(node_fs_1.default.readFileSync(path, 'utf8'));
|
|
398
|
-
return response.data.home.home_timeline_urt.instructions
|
|
399
|
-
.filter((instruction) => instruction.type === 'TimelineAddEntries' && instruction.entries)
|
|
400
|
-
.flatMap((instruction) => instruction.entries?.filter((entry) => entry.entryId.startsWith('tweet-')));
|
|
401
|
-
})
|
|
402
|
-
.map((entry) => {
|
|
403
|
-
return entry.content.itemContent
|
|
404
|
-
.tweet_results.result;
|
|
405
|
-
})
|
|
406
|
-
.filter((entry) => !!entry)
|
|
407
|
-
.map((entry) => (0, genson_js_1.createSchema)(entry)),
|
|
408
|
-
// SearchTimeline
|
|
409
|
-
this.results
|
|
410
|
-
.filter((result) => result.type === 'graphql' &&
|
|
411
|
-
result.name === 'SearchTimeline' &&
|
|
412
|
-
result.method === 'GET' &&
|
|
413
|
-
result.statusCode === '200')
|
|
414
|
-
.flatMap((result) => result.paths)
|
|
415
|
-
.flatMap((path) => {
|
|
416
|
-
const response = JSON.parse(node_fs_1.default.readFileSync(path, 'utf8'));
|
|
417
|
-
return response.data.search_by_raw_query.search_timeline.timeline.instructions
|
|
418
|
-
.filter((instruction) => instruction.type === 'TimelineAddEntries' && instruction.entries)
|
|
419
|
-
.flatMap((instruction) => instruction.entries?.filter((entry) => entry.entryId.startsWith('tweet-')));
|
|
420
|
-
})
|
|
421
|
-
.map((entry) => {
|
|
422
|
-
return entry.content.itemContent
|
|
423
|
-
.tweet_results.result;
|
|
424
|
-
})
|
|
425
|
-
.filter((entry) => !!entry)
|
|
426
|
-
.map((entry) => (0, genson_js_1.createSchema)(entry)),
|
|
427
|
-
// UserTweets
|
|
428
|
-
this.results
|
|
429
|
-
.filter((result) => result.type === 'graphql' &&
|
|
430
|
-
result.name === 'UserTweets' &&
|
|
431
|
-
result.method === 'GET' &&
|
|
432
|
-
result.statusCode === '200')
|
|
433
|
-
.flatMap((result) => result.paths)
|
|
434
|
-
.flatMap((path) => {
|
|
435
|
-
const response = JSON.parse(node_fs_1.default.readFileSync(path, 'utf8'));
|
|
436
|
-
return response.data.user.result.timeline_v2.timeline.instructions
|
|
437
|
-
.filter((instruction) => instruction.type === 'TimelineAddEntries' && instruction.entries)
|
|
438
|
-
.flatMap((instruction) => instruction.entries?.filter((entry) => entry.entryId.startsWith('tweet-')));
|
|
439
|
-
})
|
|
440
|
-
.map((entry) => {
|
|
441
|
-
return entry.content.itemContent
|
|
442
|
-
.tweet_results.result;
|
|
443
|
-
})
|
|
444
|
-
.filter((entry) => !!entry)
|
|
445
|
-
.map((entry) => (0, genson_js_1.createSchema)(entry)),
|
|
446
|
-
// Likes
|
|
447
|
-
this.results
|
|
448
|
-
.filter((result) => result.type === 'graphql' &&
|
|
449
|
-
result.name === 'Likes' &&
|
|
450
|
-
result.method === 'GET' &&
|
|
451
|
-
result.statusCode === '200')
|
|
452
|
-
.flatMap((result) => result.paths)
|
|
453
|
-
.flatMap((path) => {
|
|
454
|
-
const response = JSON.parse(node_fs_1.default.readFileSync(path, 'utf8'));
|
|
455
|
-
return response.data.user.result.timeline_v2.timeline.instructions
|
|
456
|
-
.filter((instruction) => instruction.type === 'TimelineAddEntries' && instruction.entries)
|
|
457
|
-
.flatMap((instruction) => instruction.entries?.filter((entry) => entry.entryId.startsWith('tweet-')));
|
|
458
|
-
})
|
|
459
|
-
.map((entry) => {
|
|
460
|
-
return entry.content.itemContent
|
|
461
|
-
.tweet_results.result;
|
|
462
|
-
})
|
|
463
|
-
.filter((entry) => !!entry)
|
|
464
|
-
.map((entry) => (0, genson_js_1.createSchema)(entry)),
|
|
465
|
-
].flat();
|
|
466
|
-
await this.generateTypeFromSchema((0, genson_js_1.mergeSchemas)(schemas), 'CustomTweetObject', 'レスポンスツイートオブジェクト');
|
|
467
|
-
}
|
|
468
|
-
/**
|
|
469
|
-
* レスポンスツイートレガシーオブジェクト(CustomTweetLegacyObject)のカスタム型定義を生成する
|
|
470
|
-
*/
|
|
471
|
-
async runTweetLegacyObject() {
|
|
472
|
-
// 各レスポンスからレガシーツイートオブジェクトを抽出
|
|
473
|
-
const schemas = [
|
|
474
|
-
// SearchTimeline
|
|
475
|
-
this.results
|
|
476
|
-
.filter((result) => result.type === 'graphql' &&
|
|
477
|
-
result.name === 'SearchTimeline' &&
|
|
478
|
-
result.method === 'GET' &&
|
|
479
|
-
result.statusCode === '200')
|
|
480
|
-
.flatMap((result) => result.paths)
|
|
481
|
-
.flatMap((path) => {
|
|
482
|
-
const response = JSON.parse(node_fs_1.default.readFileSync(path, 'utf8'));
|
|
483
|
-
return response.data.search_by_raw_query.search_timeline.timeline.instructions
|
|
484
|
-
.filter((instruction) => instruction.type === 'TimelineAddEntries' && instruction.entries)
|
|
485
|
-
.flatMap((instruction) => instruction.entries?.filter((entry) => entry.entryId.startsWith('tweet-')));
|
|
486
|
-
})
|
|
487
|
-
.map((entry) => {
|
|
488
|
-
return entry.content.itemContent
|
|
489
|
-
.tweet_results.result.legacy;
|
|
490
|
-
})
|
|
491
|
-
.map((entry) => (0, genson_js_1.createSchema)(entry)),
|
|
492
|
-
// UserTweets
|
|
493
|
-
this.results
|
|
494
|
-
.filter((result) => result.type === 'graphql' &&
|
|
495
|
-
result.name === 'UserTweets' &&
|
|
496
|
-
result.method === 'GET' &&
|
|
497
|
-
result.statusCode === '200')
|
|
498
|
-
.flatMap((result) => result.paths)
|
|
499
|
-
.flatMap((path) => {
|
|
500
|
-
const response = JSON.parse(node_fs_1.default.readFileSync(path, 'utf8'));
|
|
501
|
-
return response.data.user.result.timeline_v2.timeline.instructions
|
|
502
|
-
.filter((instruction) => instruction.type === 'TimelineAddEntries' && instruction.entries)
|
|
503
|
-
.flatMap((instruction) => instruction.entries?.filter((entry) => entry.entryId.startsWith('tweet-')));
|
|
504
|
-
})
|
|
505
|
-
.filter((entry) => entry.content.itemContent.tweet_results
|
|
506
|
-
.result.legacy !== undefined)
|
|
507
|
-
.map((entry) => {
|
|
508
|
-
return entry.content.itemContent
|
|
509
|
-
.tweet_results.result.legacy;
|
|
510
|
-
})
|
|
511
|
-
.map((entry) => (0, genson_js_1.createSchema)(entry)),
|
|
512
|
-
this.results
|
|
513
|
-
.filter((result) => result.type === 'graphql' &&
|
|
514
|
-
result.name === 'UserTweets' &&
|
|
515
|
-
result.method === 'GET' &&
|
|
516
|
-
result.statusCode === '200')
|
|
517
|
-
.flatMap((result) => result.paths)
|
|
518
|
-
.flatMap((path) => {
|
|
519
|
-
const response = JSON.parse(node_fs_1.default.readFileSync(path, 'utf8'));
|
|
520
|
-
return response.data.user.result.timeline_v2.timeline.instructions
|
|
521
|
-
.filter((instruction) => instruction.type === 'TimelineAddEntries' && instruction.entries)
|
|
522
|
-
.flatMap((instruction) => instruction.entries?.filter((entry) => entry.entryId.startsWith('tweet-')));
|
|
523
|
-
})
|
|
524
|
-
.filter((entry) => entry.content.itemContent.tweet_results
|
|
525
|
-
.result.tweet?.legacy !== undefined)
|
|
526
|
-
.map((entry) => {
|
|
527
|
-
return entry.content.itemContent
|
|
528
|
-
.tweet_results.result.tweet?.legacy;
|
|
529
|
-
})
|
|
530
|
-
.map((entry) => (0, genson_js_1.createSchema)(entry)),
|
|
531
|
-
].flat();
|
|
532
|
-
await this.generateTypeFromSchema((0, genson_js_1.mergeSchemas)(schemas), 'CustomTweetLegacyObject', 'レスポンスツイートレガシーオブジェクト');
|
|
533
|
-
}
|
|
534
|
-
/**
|
|
535
|
-
* カスタム型定義を、スキーマを元に生成する
|
|
536
|
-
*
|
|
537
|
-
* @param schema スキーマ
|
|
538
|
-
* @param name 型名
|
|
539
|
-
* @param tsDocument 型定義の tsdoc(1 行で記述)
|
|
540
|
-
*/
|
|
541
|
-
async generateTypeFromSchema(schema, name, tsDocument) {
|
|
542
|
-
const logger = node_utils_1.Logger.configure('CustomTypeGenerator.generateTypeFromSchema');
|
|
543
|
-
if (!schema) {
|
|
544
|
-
throw new Error('No schema found');
|
|
545
|
-
}
|
|
546
|
-
const kebabName = name.replaceAll(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
|
547
|
-
const schemaPath = (0, node_path_1.join)(this.schemaDirectory, 'custom', `${kebabName}.json`);
|
|
548
|
-
const typesPath = (0, node_path_1.join)(this.typesDirectory, 'custom', `${kebabName}.ts`);
|
|
549
|
-
node_fs_1.default.mkdirSync((0, node_path_1.dirname)(schemaPath), { recursive: true });
|
|
550
|
-
node_fs_1.default.writeFileSync(schemaPath, JSON.stringify(schema, null, 2));
|
|
551
|
-
node_fs_1.default.mkdirSync((0, node_path_1.dirname)(typesPath), { recursive: true });
|
|
552
|
-
const types = await (0, json_schema_to_typescript_1.compile)(schema, name, getCompileOptions(tsDocument));
|
|
553
|
-
node_fs_1.default.writeFileSync(typesPath, types);
|
|
554
|
-
logger.info(`📝 ${name}`);
|
|
555
|
-
}
|
|
556
|
-
/**
|
|
557
|
-
* カスタム型定義を生成する
|
|
558
|
-
*/
|
|
559
|
-
async generate() {
|
|
560
|
-
await this.runGraphQLSearchTimeline();
|
|
561
|
-
await this.runGraphQLUserTweets();
|
|
562
|
-
await this.runGraphQLUserLikeTweets();
|
|
563
|
-
await this.runGraphQLTimelineInstruction();
|
|
564
|
-
await this.runTweetObject();
|
|
565
|
-
// twitter-d 変換用オブジェクト
|
|
566
|
-
await this.runTweetLegacyObject();
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
/**
|
|
570
|
-
* エンドポイントのまとめ型定義(src/models/responses/endpoints.ts)を生成するクラス
|
|
571
|
-
*/
|
|
572
|
-
class EndPointTypeGenerator {
|
|
573
|
-
/**
|
|
574
|
-
* @param results エンドポイントごとのレスポンス情報
|
|
575
|
-
* @param typesDirectory 型定義の出力先ディレクトリ
|
|
576
|
-
*/
|
|
577
|
-
constructor(results, typesDirectory) {
|
|
578
|
-
this.results = results;
|
|
579
|
-
this.typesDirectory = typesDirectory;
|
|
580
|
-
}
|
|
581
|
-
/**
|
|
582
|
-
* TypeScript インポート文群を生成する
|
|
583
|
-
*
|
|
584
|
-
* @returns インポート文群
|
|
585
|
-
*/
|
|
586
|
-
generateImport() {
|
|
587
|
-
// import { GraphQLGetUserTweetsResponse } from './graphql/get/user-tweets'
|
|
588
|
-
return this.results
|
|
589
|
-
.map((result) => {
|
|
590
|
-
const name = Utils.getName(result.type, result.name, result.method, result.statusCode);
|
|
591
|
-
const filename = Utils.getFilename(result.type, result.name, result.method, result.statusCode);
|
|
592
|
-
return `import { ${name} } from './${filename}'`;
|
|
593
|
-
})
|
|
594
|
-
.filter((value, index, self) => self.indexOf(value) === index)
|
|
595
|
-
.join('\n');
|
|
596
|
-
}
|
|
597
|
-
/**
|
|
598
|
-
* メソッド名の配列を取得する
|
|
599
|
-
*
|
|
600
|
-
* @param type エンドポイントの種類
|
|
601
|
-
* @returns メソッド名の配列
|
|
602
|
-
*/
|
|
603
|
-
getMethods(type) {
|
|
604
|
-
return this.results
|
|
605
|
-
.filter((result) => result.type === type.toLowerCase())
|
|
606
|
-
.map((result) => result.method)
|
|
607
|
-
.filter((value, index, self) => self.indexOf(value) === index);
|
|
608
|
-
}
|
|
609
|
-
/**
|
|
610
|
-
* エンドポイント名群(<TYPE><METHOD>Endpoint)の定義を生成する
|
|
611
|
-
*
|
|
612
|
-
* @param type エンドポイントの種類
|
|
613
|
-
* @param method メソッド名
|
|
614
|
-
* @returns エンドポイント名群の定義
|
|
615
|
-
*/
|
|
616
|
-
generateEndPointType(type, method) {
|
|
617
|
-
const head = `export type ${type}${method}Endpoint =`;
|
|
618
|
-
const types = this.results
|
|
619
|
-
.filter((result) => result.type === type.toLowerCase() && result.method === method)
|
|
620
|
-
.filter((value, index, self) => self.findIndex((v) => v.name === value.name) === index)
|
|
621
|
-
.map((result) => {
|
|
622
|
-
return ` | '${result.name}'`;
|
|
623
|
-
});
|
|
624
|
-
if (types.length === 0) {
|
|
625
|
-
return null;
|
|
626
|
-
}
|
|
627
|
-
return `${head}\n${types.join('\n')}`;
|
|
628
|
-
}
|
|
629
|
-
/**
|
|
630
|
-
* エンドポイント名を元に、成功・失敗のレスポンス型定義をまとめる型定義(<TYPE><METHOD>Response)を生成する。
|
|
631
|
-
*
|
|
632
|
-
* @param type エンドポイントの種類
|
|
633
|
-
* @param method メソッド名
|
|
634
|
-
*/
|
|
635
|
-
generateResponseMergeType(type, method) {
|
|
636
|
-
const names = this.results
|
|
637
|
-
.filter((result) => result.type === type.toLowerCase())
|
|
638
|
-
.map((result) => result.name)
|
|
639
|
-
.filter((value, index, self) => self.indexOf(value) === index);
|
|
640
|
-
const types = names.map((name) => {
|
|
641
|
-
const successType = Utils.getName(type, name, method, '200');
|
|
642
|
-
const errorType = Utils.getName(type, name, method, '400');
|
|
643
|
-
const responseType = Utils.getName(type, name, method, null);
|
|
644
|
-
const isExistsSuccess = this.results.some((result) => result.type === type.toLowerCase() &&
|
|
645
|
-
result.name === name &&
|
|
646
|
-
result.method === method &&
|
|
647
|
-
result.statusCode.startsWith('2'));
|
|
648
|
-
const isExistsError = this.results.some((result) => result.type === type.toLowerCase() &&
|
|
649
|
-
result.name === name &&
|
|
650
|
-
result.method === method &&
|
|
651
|
-
!result.statusCode.startsWith('2'));
|
|
652
|
-
const tsDocument = `/** ${type} ${name} ${method} レスポンスモデル */`;
|
|
653
|
-
if (isExistsSuccess && isExistsError) {
|
|
654
|
-
return `${tsDocument}\nexport type ${responseType} = ${successType} | ${errorType}`;
|
|
655
|
-
}
|
|
656
|
-
if (isExistsSuccess) {
|
|
657
|
-
return `${tsDocument}\nexport type ${responseType} = ${successType}`;
|
|
658
|
-
}
|
|
659
|
-
if (isExistsError) {
|
|
660
|
-
return `${tsDocument}\nexport type ${responseType} = ${errorType}`;
|
|
661
|
-
}
|
|
662
|
-
return '';
|
|
663
|
-
});
|
|
664
|
-
return types.filter((type) => type !== '').join('\n');
|
|
665
|
-
}
|
|
666
|
-
/**
|
|
667
|
-
* エンドポイント名を元に、レスポンス型定義を紐づけるような型定義(<TYPE><METHOD>EndPointResponseType)を生成する。
|
|
668
|
-
*
|
|
669
|
-
* @param type エンドポイントの種類
|
|
670
|
-
* @param method メソッド名
|
|
671
|
-
* @returns レスポンス型定義を紐づけるような型定義
|
|
672
|
-
*/
|
|
673
|
-
generateResponseType(type, method) {
|
|
674
|
-
const head = `export type ${type}${method}EndPointResponseType<T extends ${type}${method}Endpoint> =`;
|
|
675
|
-
const types = this.results
|
|
676
|
-
.filter((result) => result.type === type.toLowerCase() && result.method === method)
|
|
677
|
-
.filter((value, index, self) => self.findIndex((v) => v.name === value.name) === index)
|
|
678
|
-
.map((result) => {
|
|
679
|
-
const name = Utils.getName(result.type, result.name, result.method, null);
|
|
680
|
-
return ` T extends '${result.name}' ? ${name} :`;
|
|
681
|
-
});
|
|
682
|
-
return `${head}\n${types.join('\n')}\n never`;
|
|
683
|
-
}
|
|
684
|
-
/**
|
|
685
|
-
* エンドポイントの種類と HTTP メソッドを元に、「レスポンス型定義を紐づけるような型定義」を生成する。
|
|
686
|
-
*
|
|
687
|
-
* @param types エンドポイントの種類の配列
|
|
688
|
-
* @returns レスポンス型定義を紐づけるような型定義
|
|
689
|
-
*/
|
|
690
|
-
generateEndpointResponseType(types) {
|
|
691
|
-
const head = 'export type EndPointResponseType<M extends HttpMethod, T extends RequestType, N extends GraphQLEndpoint | RESTEndpoint> = ';
|
|
692
|
-
const results = [];
|
|
693
|
-
for (const type of types) {
|
|
694
|
-
const methods = this.getMethods(type);
|
|
695
|
-
if (methods.length === 0) {
|
|
696
|
-
continue;
|
|
697
|
-
}
|
|
698
|
-
if (types.at(0) !== type) {
|
|
699
|
-
results.push(':');
|
|
700
|
-
}
|
|
701
|
-
results.push(`T extends '${type.toUpperCase()}' ?`);
|
|
702
|
-
for (const method of methods) {
|
|
703
|
-
// 最後以外は : をつける
|
|
704
|
-
if (methods.at(0) !== method) {
|
|
705
|
-
results.push(':');
|
|
706
|
-
}
|
|
707
|
-
results.push(`M extends '${method}' ?`, ` N extends ${type}${method}Endpoint ?`, ` ${type}${method}EndPointResponseType<N> :`, ' never');
|
|
708
|
-
}
|
|
709
|
-
results.push(' : never');
|
|
32
|
+
const isParallel = process.env.IS_PARALLEL === 'true';
|
|
33
|
+
try {
|
|
34
|
+
// msで計測
|
|
35
|
+
const results = this.calculateTime('GetEndPointResponses', () => utils_1.Utils.getEndPointResponses(debugOutputDirectory));
|
|
36
|
+
await this.awaitCalculateTime('TwitterTypesGenerator', () => new types_generator_1.TwitterTypesGenerator(results).generateTypes({
|
|
37
|
+
directory: {
|
|
38
|
+
schema: schemaDirectory,
|
|
39
|
+
types: typesDirectory,
|
|
40
|
+
},
|
|
41
|
+
parallel: isParallel,
|
|
42
|
+
}));
|
|
43
|
+
await this.awaitCalculateTime('CustomTypesGenerator', async () => await new custom_types_generator_1.CustomTypesGenerator(results, schemaDirectory, typesDirectory).generate(isParallel));
|
|
44
|
+
this.calculateTime('EndPointTypeGenerator', () => new endpoint_type_generator_1.EndPointTypeGenerator(results, typesDirectory).generate());
|
|
710
45
|
}
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
/**
|
|
714
|
-
* エンドポイントのまとめ型定義(src/models/responses/endpoints.ts)を生成する
|
|
715
|
-
*/
|
|
716
|
-
generate() {
|
|
717
|
-
const logger = node_utils_1.Logger.configure('EndPointTypeGenerator.generate');
|
|
718
|
-
const types = ['GraphQL', 'REST'];
|
|
719
|
-
const data = [];
|
|
720
|
-
const imports = this.generateImport();
|
|
721
|
-
data.push(imports, "import { HttpMethod, RequestType } from '../../scraper'");
|
|
722
|
-
for (const type of types) {
|
|
723
|
-
const unionTypes = [];
|
|
724
|
-
const methods = this.getMethods(type);
|
|
725
|
-
for (const method of methods) {
|
|
726
|
-
const mergeTypes = this.generateResponseMergeType(type, method);
|
|
727
|
-
const endpointType = this.generateEndPointType(type, method);
|
|
728
|
-
const responseType = this.generateResponseType(type, method);
|
|
729
|
-
if (!endpointType || !responseType) {
|
|
730
|
-
continue;
|
|
731
|
-
}
|
|
732
|
-
data.push(mergeTypes, endpointType, responseType);
|
|
733
|
-
unionTypes.push(` | ${type}${method}Endpoint`);
|
|
734
|
-
}
|
|
735
|
-
if (unionTypes.length === 0) {
|
|
736
|
-
unionTypes.push(' | never');
|
|
737
|
-
}
|
|
738
|
-
data.push(`export type ${type}Endpoint =\n${unionTypes.join('\n')}\n`);
|
|
46
|
+
catch (error) {
|
|
47
|
+
logger.error('An error occurred while generating types', error);
|
|
739
48
|
}
|
|
740
|
-
data.push(this.generateEndpointResponseType(types));
|
|
741
|
-
node_fs_1.default.writeFileSync(`${this.typesDirectory}/endpoints.ts`, data.map((d) => d.trim()).join('\n\n'));
|
|
742
|
-
logger.info(`📝 ${this.typesDirectory}/endpoints.ts`);
|
|
743
49
|
}
|
|
744
50
|
}
|
|
745
51
|
;
|
|
746
52
|
(async () => {
|
|
747
|
-
|
|
748
|
-
try {
|
|
749
|
-
await TwitterTypesGenerator.main();
|
|
750
|
-
}
|
|
751
|
-
catch (error) {
|
|
752
|
-
logger.error('An error occurred while generating types', error);
|
|
753
|
-
}
|
|
53
|
+
new GenerateTypes().run();
|
|
754
54
|
})();
|
|
755
55
|
//# sourceMappingURL=generate-types.js.map
|