@adisuper94/nih-reporter 0.0.1
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/.prettierrc +10 -0
- package/README.md +4 -0
- package/dist/lib/index.d.ts +3 -0
- package/dist/lib/index.js +2 -0
- package/dist/lib/project.d.ts +23 -0
- package/dist/lib/project.js +108 -0
- package/dist/lib/types.d.ts +65 -0
- package/dist/lib/types.js +73 -0
- package/dist/test/projects.test.d.ts +1 -0
- package/dist/test/projects.test.js +29 -0
- package/lib/index.ts +3 -0
- package/lib/project.ts +125 -0
- package/lib/types.ts +150 -0
- package/package.json +27 -0
- package/test/projects.test.ts +32 -0
- package/tsconfig.json +15 -0
package/.prettierrc
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { NIHProject, NIHProjectFields } from "./types.js";
|
|
2
|
+
declare class NIHProjectQuery {
|
|
3
|
+
private useRelavance;
|
|
4
|
+
private fiscalYears;
|
|
5
|
+
private includeActiveProjects;
|
|
6
|
+
private piProfileIds;
|
|
7
|
+
private excludeFields;
|
|
8
|
+
private offset;
|
|
9
|
+
private limit;
|
|
10
|
+
constructor();
|
|
11
|
+
setPIProfileIds(piProfileIds: number[]): NIHProjectQuery;
|
|
12
|
+
setFiscalYears(fiscalYears: number[]): NIHProjectQuery;
|
|
13
|
+
setUseRelevance(useRelevance: boolean): NIHProjectQuery;
|
|
14
|
+
setIncludeActiveProjects(includeActiveProjects: boolean): NIHProjectQuery;
|
|
15
|
+
setExcludeFields(excludeFields: NIHProjectFields[]): NIHProjectQuery;
|
|
16
|
+
addExcludeField(excludeField: NIHProjectFields): NIHProjectQuery;
|
|
17
|
+
removeExcludeField(excludeField: string): NIHProjectQuery;
|
|
18
|
+
setLimit(limit: number): NIHProjectQuery;
|
|
19
|
+
setOffset(offset: number): NIHProjectQuery;
|
|
20
|
+
execute(): Promise<NIHProject[]>;
|
|
21
|
+
iterator(): AsyncGenerator<NIHProject, void, unknown>;
|
|
22
|
+
}
|
|
23
|
+
export { NIHProjectQuery, NIHProject };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { parseNIHProject } from "./types.js";
|
|
2
|
+
class NIHProjectQuery {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.useRelavance = false;
|
|
5
|
+
this.fiscalYears = [];
|
|
6
|
+
this.includeActiveProjects = true;
|
|
7
|
+
this.piProfileIds = [];
|
|
8
|
+
this.excludeFields = [];
|
|
9
|
+
this.offset = 0;
|
|
10
|
+
this.limit = 50;
|
|
11
|
+
}
|
|
12
|
+
setPIProfileIds(piProfileIds) {
|
|
13
|
+
this.piProfileIds = piProfileIds;
|
|
14
|
+
return this;
|
|
15
|
+
}
|
|
16
|
+
setFiscalYears(fiscalYears) {
|
|
17
|
+
this.fiscalYears = fiscalYears;
|
|
18
|
+
return this;
|
|
19
|
+
}
|
|
20
|
+
setUseRelevance(useRelevance) {
|
|
21
|
+
this.useRelavance = useRelevance;
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
setIncludeActiveProjects(includeActiveProjects) {
|
|
25
|
+
this.includeActiveProjects = includeActiveProjects;
|
|
26
|
+
return this;
|
|
27
|
+
}
|
|
28
|
+
setExcludeFields(excludeFields) {
|
|
29
|
+
this.excludeFields = excludeFields;
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
addExcludeField(excludeField) {
|
|
33
|
+
if (!this.excludeFields.includes(excludeField)) {
|
|
34
|
+
this.excludeFields.push(excludeField);
|
|
35
|
+
}
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
removeExcludeField(excludeField) {
|
|
39
|
+
this.excludeFields = this.excludeFields.filter((field) => field !== excludeField);
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
setLimit(limit) {
|
|
43
|
+
if (limit <= 0) {
|
|
44
|
+
this.limit = 50;
|
|
45
|
+
}
|
|
46
|
+
else if (limit > 14999) {
|
|
47
|
+
this.limit = 14999;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
this.limit = limit;
|
|
51
|
+
}
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
setOffset(offset) {
|
|
55
|
+
if (offset < 0) {
|
|
56
|
+
this.offset = 0;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
this.offset = offset;
|
|
60
|
+
}
|
|
61
|
+
return this;
|
|
62
|
+
}
|
|
63
|
+
async execute() {
|
|
64
|
+
const resp = await fetch("https://api.reporter.nih.gov/v2/projects/search", {
|
|
65
|
+
method: "POST",
|
|
66
|
+
headers: {
|
|
67
|
+
Accept: "application/json",
|
|
68
|
+
"Content-Type": "application/json",
|
|
69
|
+
},
|
|
70
|
+
body: JSON.stringify({
|
|
71
|
+
criteria: {
|
|
72
|
+
use_relevance: this.useRelavance,
|
|
73
|
+
fiscal_years: this.fiscalYears,
|
|
74
|
+
include_active_projects: this.includeActiveProjects,
|
|
75
|
+
pi_profile_ids: this.piProfileIds,
|
|
76
|
+
},
|
|
77
|
+
exclude_fields: this.excludeFields,
|
|
78
|
+
offset: this.offset,
|
|
79
|
+
limit: this.limit,
|
|
80
|
+
}),
|
|
81
|
+
});
|
|
82
|
+
const data = await resp.json();
|
|
83
|
+
const results = data.results;
|
|
84
|
+
if (typeof results != "object") {
|
|
85
|
+
const errMsg = data[0];
|
|
86
|
+
throw new Error(`NIH API err_msg: ${errMsg}`);
|
|
87
|
+
}
|
|
88
|
+
const projects = results.map((raw) => parseNIHProject(raw));
|
|
89
|
+
return projects;
|
|
90
|
+
}
|
|
91
|
+
async *iterator() {
|
|
92
|
+
let buffer = [];
|
|
93
|
+
let idx = 0;
|
|
94
|
+
while (true) {
|
|
95
|
+
if (idx >= buffer.length) {
|
|
96
|
+
const projects = await this.execute();
|
|
97
|
+
this.setOffset(this.offset + this.limit);
|
|
98
|
+
buffer = projects;
|
|
99
|
+
idx = 0;
|
|
100
|
+
}
|
|
101
|
+
if (idx >= buffer.length) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
yield buffer[idx++];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
export { NIHProjectQuery };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
type NIHProject = {
|
|
2
|
+
applId: number;
|
|
3
|
+
subProjectId?: string;
|
|
4
|
+
fiscalYear: number;
|
|
5
|
+
projectNum: string;
|
|
6
|
+
projectSerialNum: string;
|
|
7
|
+
awardType: string;
|
|
8
|
+
activityCode: string;
|
|
9
|
+
awardAmount: number;
|
|
10
|
+
directCost: number;
|
|
11
|
+
indirectCost: number;
|
|
12
|
+
isActive: boolean;
|
|
13
|
+
congDistrict: string;
|
|
14
|
+
projectStartDate: Date;
|
|
15
|
+
projectEndDate: Date;
|
|
16
|
+
budgetStartDate: Date;
|
|
17
|
+
budgetEndDate: Date;
|
|
18
|
+
principalInvestigators: NIHPerson[];
|
|
19
|
+
dateAdded: Date;
|
|
20
|
+
agencyCode: string;
|
|
21
|
+
arraFunded: string;
|
|
22
|
+
oppurtunityNumber: string;
|
|
23
|
+
isNew: boolean;
|
|
24
|
+
coreProjectNum: string;
|
|
25
|
+
mechanismCodeDc: string;
|
|
26
|
+
projectTitle: string;
|
|
27
|
+
covidResponse?: string;
|
|
28
|
+
cfdaCode: string;
|
|
29
|
+
org: NIHOrg;
|
|
30
|
+
spendingCategories?: number[];
|
|
31
|
+
terms?: string[];
|
|
32
|
+
prefTerms?: string[];
|
|
33
|
+
abstractText?: string;
|
|
34
|
+
};
|
|
35
|
+
type NIHPerson = {
|
|
36
|
+
eraId: number;
|
|
37
|
+
firstName: string;
|
|
38
|
+
lastName: string;
|
|
39
|
+
middleName: string;
|
|
40
|
+
fullName: string;
|
|
41
|
+
isContactPI: boolean;
|
|
42
|
+
title?: string;
|
|
43
|
+
};
|
|
44
|
+
type NIHOrg = {
|
|
45
|
+
orgName: string;
|
|
46
|
+
city?: string;
|
|
47
|
+
country?: string;
|
|
48
|
+
orgCity: string;
|
|
49
|
+
orgState: string;
|
|
50
|
+
orgCountry?: string;
|
|
51
|
+
orgStateName?: string;
|
|
52
|
+
orgZipCode: string;
|
|
53
|
+
orgFips: string;
|
|
54
|
+
orgIPFCode: string;
|
|
55
|
+
externalOrgId: string;
|
|
56
|
+
deptType: string;
|
|
57
|
+
fipsCountyCode?: string;
|
|
58
|
+
orgDuns: string[];
|
|
59
|
+
orgUeis: string[];
|
|
60
|
+
primaryDuns: string;
|
|
61
|
+
primaryUei: string;
|
|
62
|
+
};
|
|
63
|
+
declare function parseNIHProject(raw: any): NIHProject;
|
|
64
|
+
type NIHProjectFields = "SpendingCategories" | "SpendingCategoriesDesc" | "ProgramOfficers" | "AbstractText" | "Terms" | "PrefTerms" | "CovidResponse" | "SubprojectId";
|
|
65
|
+
export { parseNIHProject, NIHProjectFields, NIHProject };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
function parseNIHPerson(raw) {
|
|
2
|
+
return {
|
|
3
|
+
eraId: raw.profile_id,
|
|
4
|
+
firstName: raw.first_name,
|
|
5
|
+
lastName: raw.last_name,
|
|
6
|
+
middleName: raw.middle_name,
|
|
7
|
+
fullName: raw.full_name,
|
|
8
|
+
isContactPI: raw.is_contact_pi,
|
|
9
|
+
title: raw.title || undefined,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function parseNIHOrg(raw) {
|
|
13
|
+
return {
|
|
14
|
+
orgName: raw.org_name,
|
|
15
|
+
city: raw.city ?? undefined,
|
|
16
|
+
country: raw.country ?? undefined,
|
|
17
|
+
orgCity: raw.org_city,
|
|
18
|
+
orgState: raw.org_state,
|
|
19
|
+
orgCountry: raw.org_country ?? undefined,
|
|
20
|
+
orgStateName: raw.org_state_name ?? undefined,
|
|
21
|
+
deptType: raw.dept_type,
|
|
22
|
+
orgDuns: raw.org_duns,
|
|
23
|
+
orgUeis: raw.org_ueis,
|
|
24
|
+
primaryDuns: raw.primary_duns,
|
|
25
|
+
primaryUei: raw.primary_uei,
|
|
26
|
+
orgFips: raw.org_fips,
|
|
27
|
+
orgIPFCode: raw.org_ipf_code,
|
|
28
|
+
orgZipCode: raw.org_zipcode,
|
|
29
|
+
externalOrgId: raw.external_org_id,
|
|
30
|
+
fipsCountyCode: raw.fips_county_code ?? undefined,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function parseNIHProject(raw) {
|
|
34
|
+
let pis = [];
|
|
35
|
+
if (raw.principal_investigators) {
|
|
36
|
+
pis = raw.principal_investigators.map((pi) => parseNIHPerson(pi));
|
|
37
|
+
}
|
|
38
|
+
const org = parseNIHOrg(raw.organization);
|
|
39
|
+
return {
|
|
40
|
+
applId: Number(raw.appl_id),
|
|
41
|
+
subProjectId: raw.subproject_id ?? undefined,
|
|
42
|
+
fiscalYear: Number(raw.fiscal_year),
|
|
43
|
+
projectNum: raw.project_num,
|
|
44
|
+
projectSerialNum: raw.project_serial_num,
|
|
45
|
+
awardType: raw.award_type,
|
|
46
|
+
activityCode: raw.activity_code,
|
|
47
|
+
awardAmount: Number(raw.award_amount),
|
|
48
|
+
isActive: Boolean(raw.is_active),
|
|
49
|
+
congDistrict: raw.cong_district,
|
|
50
|
+
projectStartDate: new Date(raw.project_start_date),
|
|
51
|
+
projectEndDate: new Date(raw.project_end_date),
|
|
52
|
+
principalInvestigators: pis,
|
|
53
|
+
budgetStartDate: new Date(raw.budget_start),
|
|
54
|
+
budgetEndDate: new Date(raw.budget_end),
|
|
55
|
+
directCost: Number(raw.direct_cost_amt),
|
|
56
|
+
indirectCost: Number(raw.indirect_cost_amt),
|
|
57
|
+
agencyCode: raw.agency_code,
|
|
58
|
+
arraFunded: raw.arra_funded,
|
|
59
|
+
dateAdded: new Date(raw.date_added),
|
|
60
|
+
coreProjectNum: raw.core_project_num,
|
|
61
|
+
oppurtunityNumber: raw.opportunity_number,
|
|
62
|
+
isNew: Boolean(raw.is_new),
|
|
63
|
+
mechanismCodeDc: raw.mechanism_code_dc,
|
|
64
|
+
projectTitle: raw.project_title,
|
|
65
|
+
covidResponse: raw.covid_response ?? undefined,
|
|
66
|
+
org: org,
|
|
67
|
+
cfdaCode: raw.cfda_code,
|
|
68
|
+
prefTerms: raw.pref_terms ? raw.pref_terms.split(";") : undefined,
|
|
69
|
+
terms: raw.terms ? raw.terms.match(/<([^>]+)>/g)?.map((tag) => tag.slice(1, -1)) || [] : undefined,
|
|
70
|
+
spendingCategories: raw.spending_categories ? raw.spending_categories.map((cat) => Number(cat)) : undefined,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export { parseNIHProject };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { describe, it, before } from "node:test";
|
|
2
|
+
import assert from "node:assert";
|
|
3
|
+
import { NIHProjectQuery } from "../lib/index.js";
|
|
4
|
+
describe("Project: Pinaki 2020", async () => {
|
|
5
|
+
let projects = [];
|
|
6
|
+
let iter;
|
|
7
|
+
before(async () => {
|
|
8
|
+
const nihProjectQuery = new NIHProjectQuery();
|
|
9
|
+
const data = await nihProjectQuery
|
|
10
|
+
.setPIProfileIds([10936793])
|
|
11
|
+
.setFiscalYears([2020, 2021])
|
|
12
|
+
.setUseRelevance(true)
|
|
13
|
+
.setExcludeFields(["PrefTerms", "Terms", "AbstractText"])
|
|
14
|
+
.execute();
|
|
15
|
+
projects = data;
|
|
16
|
+
iter = nihProjectQuery.iterator();
|
|
17
|
+
});
|
|
18
|
+
it("Award count", () => {
|
|
19
|
+
assert.equal(projects.length, 9);
|
|
20
|
+
});
|
|
21
|
+
it("Iterator test", async () => {
|
|
22
|
+
let result = await iter.next();
|
|
23
|
+
assert.equal(result.done, false);
|
|
24
|
+
assert.equal(result.value?.applId, 11049028);
|
|
25
|
+
result = await iter.next();
|
|
26
|
+
assert.equal(result.done, false);
|
|
27
|
+
assert.equal(result.value?.applId, 10228110);
|
|
28
|
+
});
|
|
29
|
+
});
|
package/lib/index.ts
ADDED
package/lib/project.ts
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { NIHProject, NIHProjectFields, parseNIHProject } from "./types.js";
|
|
2
|
+
|
|
3
|
+
class NIHProjectQuery {
|
|
4
|
+
private useRelavance: boolean;
|
|
5
|
+
private fiscalYears: number[];
|
|
6
|
+
private includeActiveProjects: boolean;
|
|
7
|
+
private piProfileIds: number[];
|
|
8
|
+
private excludeFields: NIHProjectFields[];
|
|
9
|
+
private offset: number;
|
|
10
|
+
private limit: number;
|
|
11
|
+
|
|
12
|
+
constructor() {
|
|
13
|
+
this.useRelavance = false;
|
|
14
|
+
this.fiscalYears = [];
|
|
15
|
+
this.includeActiveProjects = true;
|
|
16
|
+
this.piProfileIds = [];
|
|
17
|
+
this.excludeFields = [];
|
|
18
|
+
this.offset = 0;
|
|
19
|
+
this.limit = 50;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
setPIProfileIds(piProfileIds: number[]): NIHProjectQuery {
|
|
23
|
+
this.piProfileIds = piProfileIds;
|
|
24
|
+
return this;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
setFiscalYears(fiscalYears: number[]): NIHProjectQuery {
|
|
28
|
+
this.fiscalYears = fiscalYears;
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
setUseRelevance(useRelevance: boolean): NIHProjectQuery {
|
|
33
|
+
this.useRelavance = useRelevance;
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
setIncludeActiveProjects(includeActiveProjects: boolean): NIHProjectQuery {
|
|
38
|
+
this.includeActiveProjects = includeActiveProjects;
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
setExcludeFields(excludeFields: NIHProjectFields[]): NIHProjectQuery {
|
|
43
|
+
this.excludeFields = excludeFields;
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
addExcludeField(excludeField: NIHProjectFields): NIHProjectQuery {
|
|
48
|
+
if (!this.excludeFields.includes(excludeField)) {
|
|
49
|
+
this.excludeFields.push(excludeField);
|
|
50
|
+
}
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
removeExcludeField(excludeField: string): NIHProjectQuery {
|
|
55
|
+
this.excludeFields = this.excludeFields.filter((field) => field !== excludeField);
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
setLimit(limit: number): NIHProjectQuery {
|
|
60
|
+
if (limit <= 0) {
|
|
61
|
+
this.limit = 50;
|
|
62
|
+
} else if (limit > 14999) {
|
|
63
|
+
this.limit = 14999;
|
|
64
|
+
} else {
|
|
65
|
+
this.limit = limit;
|
|
66
|
+
}
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
setOffset(offset: number): NIHProjectQuery {
|
|
71
|
+
if (offset < 0) {
|
|
72
|
+
this.offset = 0;
|
|
73
|
+
} else {
|
|
74
|
+
this.offset = offset;
|
|
75
|
+
}
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async execute(): Promise<NIHProject[]> {
|
|
80
|
+
const resp = await fetch("https://api.reporter.nih.gov/v2/projects/search", {
|
|
81
|
+
method: "POST",
|
|
82
|
+
headers: {
|
|
83
|
+
Accept: "application/json",
|
|
84
|
+
"Content-Type": "application/json",
|
|
85
|
+
},
|
|
86
|
+
body: JSON.stringify({
|
|
87
|
+
criteria: {
|
|
88
|
+
use_relevance: this.useRelavance,
|
|
89
|
+
fiscal_years: this.fiscalYears,
|
|
90
|
+
include_active_projects: this.includeActiveProjects,
|
|
91
|
+
pi_profile_ids: this.piProfileIds,
|
|
92
|
+
},
|
|
93
|
+
exclude_fields: this.excludeFields,
|
|
94
|
+
offset: this.offset,
|
|
95
|
+
limit: this.limit,
|
|
96
|
+
}),
|
|
97
|
+
});
|
|
98
|
+
const data = await resp.json();
|
|
99
|
+
const results = data.results;
|
|
100
|
+
if (typeof results != "object") {
|
|
101
|
+
const errMsg = data[0];
|
|
102
|
+
throw new Error(`NIH API err_msg: ${errMsg}`);
|
|
103
|
+
}
|
|
104
|
+
const projects: NIHProject[] = results.map((raw: any) => parseNIHProject(raw));
|
|
105
|
+
return projects;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async *iterator() {
|
|
109
|
+
let buffer: NIHProject[] = [];
|
|
110
|
+
let idx = 0;
|
|
111
|
+
while (true) {
|
|
112
|
+
if (idx >= buffer.length) {
|
|
113
|
+
const projects = await this.execute();
|
|
114
|
+
this.setOffset(this.offset + this.limit);
|
|
115
|
+
buffer = projects;
|
|
116
|
+
idx = 0;
|
|
117
|
+
}
|
|
118
|
+
if (idx >= buffer.length) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
yield buffer[idx++];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
export { NIHProjectQuery, NIHProject };
|
package/lib/types.ts
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
type NIHProject = {
|
|
2
|
+
applId: number;
|
|
3
|
+
subProjectId?: string;
|
|
4
|
+
fiscalYear: number;
|
|
5
|
+
projectNum: string;
|
|
6
|
+
projectSerialNum: string;
|
|
7
|
+
awardType: string;
|
|
8
|
+
activityCode: string;
|
|
9
|
+
awardAmount: number;
|
|
10
|
+
directCost: number;
|
|
11
|
+
indirectCost: number;
|
|
12
|
+
isActive: boolean;
|
|
13
|
+
congDistrict: string;
|
|
14
|
+
projectStartDate: Date;
|
|
15
|
+
projectEndDate: Date;
|
|
16
|
+
budgetStartDate: Date;
|
|
17
|
+
budgetEndDate: Date;
|
|
18
|
+
principalInvestigators: NIHPerson[];
|
|
19
|
+
dateAdded: Date;
|
|
20
|
+
agencyCode: string;
|
|
21
|
+
arraFunded: string;
|
|
22
|
+
oppurtunityNumber: string;
|
|
23
|
+
isNew: boolean;
|
|
24
|
+
coreProjectNum: string;
|
|
25
|
+
mechanismCodeDc: string;
|
|
26
|
+
projectTitle: string;
|
|
27
|
+
covidResponse?: string;
|
|
28
|
+
cfdaCode: string;
|
|
29
|
+
org: NIHOrg;
|
|
30
|
+
spendingCategories?: number[];
|
|
31
|
+
terms?: string[];
|
|
32
|
+
prefTerms?: string[];
|
|
33
|
+
abstractText?: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
type NIHPerson = {
|
|
37
|
+
eraId: number;
|
|
38
|
+
firstName: string;
|
|
39
|
+
lastName: string;
|
|
40
|
+
middleName: string;
|
|
41
|
+
fullName: string;
|
|
42
|
+
isContactPI: boolean;
|
|
43
|
+
title?: string;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
type NIHOrg = {
|
|
47
|
+
orgName: string;
|
|
48
|
+
city?: string;
|
|
49
|
+
country?: string;
|
|
50
|
+
orgCity: string;
|
|
51
|
+
orgState: string;
|
|
52
|
+
orgCountry?: string;
|
|
53
|
+
orgStateName?: string;
|
|
54
|
+
orgZipCode: string;
|
|
55
|
+
orgFips: string;
|
|
56
|
+
orgIPFCode: string;
|
|
57
|
+
externalOrgId: string;
|
|
58
|
+
deptType: string;
|
|
59
|
+
fipsCountyCode?: string;
|
|
60
|
+
orgDuns: string[];
|
|
61
|
+
orgUeis: string[];
|
|
62
|
+
primaryDuns: string;
|
|
63
|
+
primaryUei: string;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
function parseNIHPerson(raw: any): NIHPerson {
|
|
67
|
+
return {
|
|
68
|
+
eraId: raw.profile_id,
|
|
69
|
+
firstName: raw.first_name,
|
|
70
|
+
lastName: raw.last_name,
|
|
71
|
+
middleName: raw.middle_name,
|
|
72
|
+
fullName: raw.full_name,
|
|
73
|
+
isContactPI: raw.is_contact_pi,
|
|
74
|
+
title: raw.title || undefined,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function parseNIHOrg(raw: any): NIHOrg {
|
|
78
|
+
return {
|
|
79
|
+
orgName: raw.org_name,
|
|
80
|
+
city: raw.city ?? undefined,
|
|
81
|
+
country: raw.country ?? undefined,
|
|
82
|
+
orgCity: raw.org_city,
|
|
83
|
+
orgState: raw.org_state,
|
|
84
|
+
orgCountry: raw.org_country ?? undefined,
|
|
85
|
+
orgStateName: raw.org_state_name ?? undefined,
|
|
86
|
+
deptType: raw.dept_type,
|
|
87
|
+
orgDuns: raw.org_duns,
|
|
88
|
+
orgUeis: raw.org_ueis,
|
|
89
|
+
primaryDuns: raw.primary_duns,
|
|
90
|
+
primaryUei: raw.primary_uei,
|
|
91
|
+
orgFips: raw.org_fips,
|
|
92
|
+
orgIPFCode: raw.org_ipf_code,
|
|
93
|
+
orgZipCode: raw.org_zipcode,
|
|
94
|
+
externalOrgId: raw.external_org_id,
|
|
95
|
+
fipsCountyCode: raw.fips_county_code ?? undefined,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function parseNIHProject(raw: any): NIHProject {
|
|
100
|
+
let pis: NIHPerson[] = [];
|
|
101
|
+
if (raw.principal_investigators) {
|
|
102
|
+
pis = raw.principal_investigators.map((pi: any) => parseNIHPerson(pi));
|
|
103
|
+
}
|
|
104
|
+
const org = parseNIHOrg(raw.organization);
|
|
105
|
+
return {
|
|
106
|
+
applId: Number(raw.appl_id),
|
|
107
|
+
subProjectId: raw.subproject_id ?? undefined,
|
|
108
|
+
fiscalYear: Number(raw.fiscal_year),
|
|
109
|
+
projectNum: raw.project_num,
|
|
110
|
+
projectSerialNum: raw.project_serial_num,
|
|
111
|
+
awardType: raw.award_type,
|
|
112
|
+
activityCode: raw.activity_code,
|
|
113
|
+
awardAmount: Number(raw.award_amount),
|
|
114
|
+
isActive: Boolean(raw.is_active),
|
|
115
|
+
congDistrict: raw.cong_district,
|
|
116
|
+
projectStartDate: new Date(raw.project_start_date),
|
|
117
|
+
projectEndDate: new Date(raw.project_end_date),
|
|
118
|
+
principalInvestigators: pis,
|
|
119
|
+
budgetStartDate: new Date(raw.budget_start),
|
|
120
|
+
budgetEndDate: new Date(raw.budget_end),
|
|
121
|
+
directCost: Number(raw.direct_cost_amt),
|
|
122
|
+
indirectCost: Number(raw.indirect_cost_amt),
|
|
123
|
+
agencyCode: raw.agency_code,
|
|
124
|
+
arraFunded: raw.arra_funded,
|
|
125
|
+
dateAdded: new Date(raw.date_added),
|
|
126
|
+
coreProjectNum: raw.core_project_num,
|
|
127
|
+
oppurtunityNumber: raw.opportunity_number,
|
|
128
|
+
isNew: Boolean(raw.is_new),
|
|
129
|
+
mechanismCodeDc: raw.mechanism_code_dc,
|
|
130
|
+
projectTitle: raw.project_title,
|
|
131
|
+
covidResponse: raw.covid_response ?? undefined,
|
|
132
|
+
org: org,
|
|
133
|
+
cfdaCode: raw.cfda_code,
|
|
134
|
+
prefTerms: raw.pref_terms ? raw.pref_terms.split(";") : undefined,
|
|
135
|
+
terms: raw.terms ? raw.terms.match(/<([^>]+)>/g)?.map((tag: string) => tag.slice(1, -1)) || [] : undefined,
|
|
136
|
+
spendingCategories: raw.spending_categories ? raw.spending_categories.map((cat: any) => Number(cat)) : undefined,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
type NIHProjectFields =
|
|
141
|
+
| "SpendingCategories"
|
|
142
|
+
| "SpendingCategoriesDesc"
|
|
143
|
+
| "ProgramOfficers"
|
|
144
|
+
| "AbstractText"
|
|
145
|
+
| "Terms"
|
|
146
|
+
| "PrefTerms"
|
|
147
|
+
| "CovidResponse"
|
|
148
|
+
| "SubprojectId";
|
|
149
|
+
|
|
150
|
+
export { parseNIHProject, NIHProjectFields, NIHProject };
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@adisuper94/nih-reporter",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/lib/index.js",
|
|
7
|
+
"types": "dist/lib/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"test": "node --loader ts-node/esm --no-warnings=ExperimentalWarning test/*"
|
|
11
|
+
},
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/adiSuper94/nih-reporter.git"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [],
|
|
17
|
+
"author": "Aditya Subramanian",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/adiSuper94/nih-reporter/issues"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://github.com/adiSuper94/nih-reporter#readme",
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^22.14.0",
|
|
24
|
+
"ts-node": "^10.9.2",
|
|
25
|
+
"typescript": "^5.8.2"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { describe, it, before } from "node:test";
|
|
2
|
+
import assert from "node:assert";
|
|
3
|
+
import { NIHProject, NIHProjectQuery } from "../lib/index.js";
|
|
4
|
+
|
|
5
|
+
describe("Project: Pinaki 2020", async () => {
|
|
6
|
+
let projects: NIHProject[] = [];
|
|
7
|
+
let iter: AsyncGenerator<NIHProject>;
|
|
8
|
+
before(async () => {
|
|
9
|
+
const nihProjectQuery = new NIHProjectQuery();
|
|
10
|
+
const data = await nihProjectQuery
|
|
11
|
+
.setPIProfileIds([10936793])
|
|
12
|
+
.setFiscalYears([2020, 2021])
|
|
13
|
+
.setUseRelevance(true)
|
|
14
|
+
.setExcludeFields(["PrefTerms", "Terms", "AbstractText"])
|
|
15
|
+
.execute();
|
|
16
|
+
projects = data;
|
|
17
|
+
iter = nihProjectQuery.iterator();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("Award count", () => {
|
|
21
|
+
assert.equal(projects.length, 9);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("Iterator test", async () => {
|
|
25
|
+
let result = await iter.next();
|
|
26
|
+
assert.equal(result.done, false);
|
|
27
|
+
assert.equal(result.value?.applId, 11049028);
|
|
28
|
+
result = await iter.next();
|
|
29
|
+
assert.equal(result.done, false);
|
|
30
|
+
assert.equal(result.value?.applId, 10228110);
|
|
31
|
+
});
|
|
32
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
/* Visit https://aka.ms/tsconfig to read more about this file */
|
|
4
|
+
"target": "es2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
|
5
|
+
"declaration": true,
|
|
6
|
+
"module": "NodeNext", /* Specify what module code is generated. */
|
|
7
|
+
"moduleResolution": "NodeNext", /* Specify how TypeScript looks up a file from a given module specifier. */
|
|
8
|
+
"outDir": "./dist", /* Specify an output folder for all emitted files. */
|
|
9
|
+
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
|
10
|
+
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
|
11
|
+
"strict": true, /* Enable all strict type-checking options. */
|
|
12
|
+
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
|
13
|
+
},
|
|
14
|
+
"include": ["lib", "test"]
|
|
15
|
+
}
|