-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.ts
More file actions
486 lines (398 loc) · 10.1 KB
/
client.ts
File metadata and controls
486 lines (398 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
// Reference: https://support.nii.ac.jp/ja/cir/r_opensearch#query
import { DateTime } from "./deps.ts";
import { CiNiiEnv, CiNiiFormatDate, CiNIiiURL, CiNiiResult } from "./mod.ts";
export type SearchType =
| "all"
| "data"
| "articles"
| "books"
| "dissertations"
| "projects";
export type DataSourceType =
| "KAKEN"
| "JALC"
| "IRDB"
| "CROSSREF"
| "DATACITE"
| "CID"
| "CIB"
| "NINJAL"
| "IDR"
| "DBPEDIA"
| "RUDA";
export type ResourceType =
| "conference paper"
| "data paper"
| "departmental bulletin paper"
| "editorial"
| "journal article"
| "newspaper"
| "periodical"
| "review article"
| "software paper"
| "article"
| "journal_article"
| "book"
| "Audiovisual"
| "Collection"
| "Dataset"
| "Event"
| "Image"
| "InteractiveResource"
| "Model"
| "PhysicalObject"
| "Service"
| "Software"
| "Sound"
| "Text"
| "Workflow"
| "Other"
| "journal";
export type SortOrder = "newest" | "oldest" | "relevance" | "citations";
type SortOrderNumber = 0 | 1 | 4 | 10;
const convertSortOrder = (
sortOrder: SortOrder | undefined,
): SortOrderNumber | undefined => {
switch (sortOrder) {
case "newest": {
return 0;
}
case "oldest": {
return 1;
}
case "relevance": {
return 4;
}
case "citations": {
return 10;
}
default: {
return undefined;
}
}
};
export type FormatType = "html" | "rss" | "atom" | "json";
interface CiNiiResearchQuery {
appId: string;
format: FormatType;
lang?: "ja" | "en";
sortorder?: SortOrderNumber;
count?: number;
start?: number;
q?: string;
creator?: string;
from?: string;
until?: string;
datasetFormat?: string;
hasLinkToFullText?: boolean;
title?: string;
isFullTitle?: boolean;
researcherId?: string;
affiliation?: string;
publicationTitle?: string;
issn?: string;
volume?: string;
number?: string;
pages?: string;
isbn?: string;
ncid?: string;
category?: string;
description?: string;
awardInstitution?: string;
degree?: string;
awardYear?: string;
publisher?: string;
projectId?: string;
doi?: string;
dataSourceType?: string;
languageType?: string;
resourceType?: string;
}
export interface CiNiiResearchQueryOptions {
/**
* 出力フォーマットの記載言語指定
* デフォルトは `ja`
*/
lang?: "ja" | "en";
/**
* 出力時のソート順。
* newest:出版年、学位授与年、研究開始年:新しい順、
* oldest:出版年、学位授与年、研究開始年:古い順、
* relevance:関連度順(デフォルト)、
* citations:被引用件数:多い順(論文のみ)
*/
sortOrder?: SortOrder;
/**
* ページ当たり表示件数
* デフォルト=**20**、1〜200の自然数。自然数でない、または、0以下は、**20**、201以上は、200。
* format=htmlの場合、**1ページあたりの表示件数**を換算。
* 1ページあたりの表示件数は、**20**、**50**、**100**、**200**に切り上げ。
* 201以上は、**200**
*/
count?: number;
/**
* 検索結果一覧の開始番号
* 自然数。それ以外は、デフォルト=1。
* format=htmlの場合、画面のページ数に換算。
* start ÷ (1ページあたりの表示件数)。
* あまりがある場合 + 1
*/
start?: number;
/**
* フリーワード
*/
q?: string;
/**
* 人物名
*/
creator?: string;
/**
* 開始年
* `YYYY` または `YYYYMM` に変換される。
* そのため、指定できるのは年、月のみ。
* `DateTime` の使用を推奨。
*/
from?: Date | DateTime;
/**
* 終了年
* `YYYY` または `YYYYMM` に変換される。
* そのため、指定できるのは年、月のみ。
* `DateTime` の使用を推奨。
*/
until?: Date | DateTime;
/**
* 実データの提供フォーマット
*/
datasetFormat?: string;
/**
* 本文あり検索
* 本文あり検索をしたい場合はtrueを指定してください。
*/
hasLinkToFullText?: boolean;
/**
* タイトル・研究課題名
*/
title?: string;
/**
* タイトル完全一致
* タイトル完全一致検索をしたい場合はtrueを指定してください
*/
exactTitleMatch?: boolean;
/**
* 著者ID
*/
researcherId?: string;
/**
* 所属機関
*/
affiliation?: string;
/**
* 刊行物名
*/
publicationTitle?: string;
/**
* ISSN
*/
issn?: string;
/**
* 巻
*/
volume?: string;
/**
* 号
*/
number?: string;
/**
* ページ
* `start` と `end` が指定された場合、"開始ページ == start" **OR** "終了ページ == end" として検索します。
* 一つの数字のみが指定された場合、開始ページ または 終了ページ がそれに該当するものを検索します
*/
pages?: number | {
start: number;
end: number;
};
/**
* ISBN
*/
isbn?: string;
/**
* NCID
*/
ncid?: string;
/**
* 分類
*/
category?: string;
/**
* 注記・抄録
*/
description?: string;
/**
* 学位授与大学名
*/
awardInstitution?: string;
/**
* 取得学位
*/
degree?: string;
/**
* 学位授与年
* `YYYY` または `YYYYMM` に変換される。
* そのため、指定できるのは年、月のみ。
* `DateTime` の使用を推奨。
*/
awardYear?: Date | DateTime;
/**
* 公開者、出版者
*/
publisher?: string;
/**
* 研究課題/領域番号
*/
projectId?: string;
/**
* DOI
*/
doi?: string;
/**
* データソース種別
* KAKEN(KAKEN)
* JALC(ジャパンリンクセンター)
* IRDB(学術機関リポジトリデータベース)
* CROSSREF(Crossref)
* DATACITE(DataCite)
* CID(CiNii Dissertations)
* CIB(CiNii Books)
* SSJDA(SSJデータアーカイブ)
* NINJAL(国立国語研究所)
* IDR(情報学研究データリポジトリ)
* DBPEDIA(DBpedia)
* RUDA(立教大学 社会調査データアーカイブ)
*/
dataSourceType?: DataSourceType | DataSourceType[];
// TODO: ISO-639-1の型をサポートする
/**
* 言語種別
* ISO-639-1で指定する
* 例)日本語・英語・中国語で検索する場合
* languageType=["ja","en","zh"]
*/
languageType?: string | string[];
/**
* 資源種別
* conference paper(会議発表資料)
* data paper(データ論文)
* departmental bulletin paper(紀要論文)
* editorial(エディトリアル)
* journal article(学術雑誌論文)
* newspaper(新聞)
* periodical(逐次刊行物)
* review article(レビュー論文)
* software paper(ソフトウェア論文)
* article(記事)
* journal_article(雑誌論文)
* book(図書)
* Audiovisual(視聴覚雑誌)
* Collection(コレクション)
* Dataset(データセット)
* Event(イベント)
* Image(画像)
* InteractiveResource(インタラクティブリソース)
* Model(モデル)
* PhysicalObject(物理オブジェクト)
* Service(サービス)
* Software(ソフトウェア)
* Sound(音声)
* Text(テキスト)
* Workflow(ワークフロー)
* Other(その他)
* journal(雑誌)
*/
resourceType?: ResourceType | ResourceType[];
}
export class CiNiiClient {
private appId: string;
constructor(options: { appId?: string }) {
this.appId = options.appId ?? CiNiiEnv.APP_ID;
}
async all(options: CiNiiResearchQueryOptions): Promise<CiNiiResult> {
const res = await this.get("all", "json", options);
const json = await res.json();
return json;
}
async data(options: CiNiiResearchQueryOptions): Promise<CiNiiResult> {
const res = await this.get("data", "json", options);
const json = await res.json();
return json;
}
async articles(options: CiNiiResearchQueryOptions): Promise<CiNiiResult> {
const res = await this.get("articles", "json", options);
const json = await res.json();
return json;
}
async books(options: CiNiiResearchQueryOptions): Promise<CiNiiResult> {
const res = await this.get("books", "json", options);
const json = await res.json();
return json;
}
async dissertations(
options: CiNiiResearchQueryOptions,
): Promise<CiNiiResult> {
const res = await this.get("dissertations", "json", options);
const json = await res.json();
return json;
}
async projects(options: CiNiiResearchQueryOptions): Promise<CiNiiResult> {
const res = await this.get("projects", "json", options);
const json = await res.json();
return json;
}
async get(
searchType: SearchType,
format: FormatType,
options: CiNiiResearchQueryOptions,
): Promise<Response> {
const searchQuery = this.buildSearchQuery(format, options);
const url = new URL(`${CiNIiiURL.OpenSearch}/${searchType}`);
Object.entries(searchQuery).forEach(([key, value]) => {
if (value !== undefined) {
url.searchParams.append(key, value);
}
});
// console.log(url.href);
const res = await fetch(url);
return res;
}
private buildSearchQuery(
format: FormatType,
options: CiNiiResearchQueryOptions,
): CiNiiResearchQuery {
const query: CiNiiResearchQuery = {
...options,
appId: this.appId,
format: format,
sortorder: convertSortOrder(options.sortOrder),
from: CiNiiFormatDate(options.from),
until: CiNiiFormatDate(options.until),
pages: options.pages instanceof Object
? `${options.pages.start}-${options.pages.end}`
: options.pages !== undefined
? String(options.pages)
: undefined,
awardYear: CiNiiFormatDate(options.awardYear),
dataSourceType: this.joinArray(options.dataSourceType),
languageType: this.joinArray(options.languageType),
resourceType: this.joinArray(options.resourceType),
};
return query;
}
private joinArray(array?: unknown | unknown[]): string | undefined {
if (array instanceof Array) {
return array.join(",");
} else if (typeof array === "string") {
return array;
} else {
return undefined;
}
}
}