@ca-plant-list/ca-plant-list 0.4.3 → 0.4.6
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 +1 -0
- package/README.md +27 -1
- package/data/config.json +5 -0
- package/data/inattaxonphotos.csv +6059 -0
- package/data/taxa.csv +1 -0
- package/data/text/Rosa-rubiginosa.footer.md +3 -0
- package/eslint.config.mjs +13 -0
- package/jekyll/assets/css/main.css +59 -59
- package/jekyll/index.md +3 -0
- package/lib/config.js +12 -4
- package/lib/ebook/ebook.js +178 -179
- package/lib/ebook/plantbook.js +147 -139
- package/lib/genericpage.js +3 -4
- package/lib/htmltaxon.js +118 -123
- package/lib/inat_photo.js +43 -0
- package/lib/index.d.ts +12 -9
- package/lib/markdown.js +4 -0
- package/lib/pagerenderer.js +220 -221
- package/lib/photo.js +44 -0
- package/lib/taxa.js +37 -3
- package/lib/taxon.js +13 -0
- package/lib/util.js +20 -0
- package/lib/web/pagetaxon.js +212 -181
- package/package.json +9 -6
- package/scripts/build-site.js +1 -1
- package/scripts/inattaxonphotos.js +106 -0
- package/types/classes.d.ts +55 -9
- package/.vscode/settings.json +0 -11
package/lib/index.d.ts
CHANGED
@@ -13,26 +13,29 @@ export class Config {
|
|
13
13
|
}
|
14
14
|
|
15
15
|
export class CSV {
|
16
|
-
static parseFile(dir: string, fileName: string);
|
16
|
+
static parseFile(dir: string, fileName: string): void;
|
17
17
|
}
|
18
18
|
|
19
19
|
export class ErrorLog {
|
20
20
|
constructor(fileName: string, echo?: boolean);
|
21
|
-
log(...msg: string[]);
|
21
|
+
log(...msg: string[]): void;
|
22
22
|
write(): void;
|
23
23
|
}
|
24
24
|
|
25
25
|
export class Exceptions {
|
26
26
|
constructor(dataDir: string);
|
27
|
-
hasException(name: string, cat: string, subcat: string);
|
27
|
+
hasException(name: string, cat: string, subcat: string): boolean;
|
28
28
|
}
|
29
29
|
|
30
30
|
export class Files {
|
31
31
|
static exists(fileName: string): boolean;
|
32
|
-
static
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
static fetch(
|
33
|
+
url: string | URL,
|
34
|
+
targetFileName: string | undefined
|
35
|
+
): Promise<Headers>;
|
36
|
+
static mkdir(dir: string): void;
|
37
|
+
static rmDir(dir: string): void;
|
38
|
+
static write(fileName: string, data: string, overwrite: boolean): void;
|
36
39
|
}
|
37
40
|
|
38
41
|
export class Program {
|
@@ -42,13 +45,13 @@ export class Program {
|
|
42
45
|
|
43
46
|
export class Taxa {
|
44
47
|
constructor(
|
45
|
-
inclusionList:
|
48
|
+
inclusionList: Record<string, TaxonData> | true,
|
46
49
|
errorLog: ErrorLog,
|
47
50
|
showFlowerErrors: boolean,
|
48
51
|
taxonFactory?: (td: TaxonData, g: Genera) => Taxon,
|
49
52
|
extraTaxa?: TaxonData[],
|
50
53
|
extraSynonyms?: SynonymData[]
|
51
54
|
);
|
52
|
-
getTaxon(string): Taxon;
|
55
|
+
getTaxon(name: string): Taxon;
|
53
56
|
getTaxonList(): Taxon[];
|
54
57
|
}
|
package/lib/markdown.js
CHANGED
package/lib/pagerenderer.js
CHANGED
@@ -7,260 +7,259 @@ import { HTML } from "./html.js";
|
|
7
7
|
import { HTMLTaxon, TAXA_LIST_COLS } from "./htmltaxon.js";
|
8
8
|
|
9
9
|
const ENDANGERED_COLS = [
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
TAXA_LIST_COLS.SPECIES,
|
11
|
+
TAXA_LIST_COLS.COMMON_NAME,
|
12
|
+
TAXA_LIST_COLS.CESA,
|
13
|
+
TAXA_LIST_COLS.FESA,
|
14
14
|
];
|
15
15
|
const RPI_COLUMNS = [
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
TAXA_LIST_COLS.SPECIES_BARE,
|
17
|
+
TAXA_LIST_COLS.COMMON_NAME,
|
18
|
+
TAXA_LIST_COLS.CNPS_RANK,
|
19
19
|
];
|
20
20
|
|
21
21
|
class PageRenderer extends BasePageRenderer {
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
22
|
+
/**
|
23
|
+
* @param {string} outputDir
|
24
|
+
* @param {import('./config.js').Config} config
|
25
|
+
* @param {Taxa} taxa
|
26
|
+
*/
|
27
|
+
static render(outputDir, config, taxa) {
|
28
|
+
super.renderBasePages(outputDir, taxa);
|
29
29
|
|
30
|
-
|
30
|
+
this.renderLists(outputDir, config, taxa);
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
}
|
32
|
+
const taxonList = taxa.getTaxonList();
|
33
|
+
for (const taxon of taxonList) {
|
34
|
+
new PageTaxon(outputDir, config, taxon).render();
|
36
35
|
}
|
36
|
+
}
|
37
37
|
|
38
|
+
/**
|
39
|
+
* @param {string} outputDir
|
40
|
+
* @param {Config} config
|
41
|
+
* @param {Taxa} taxa
|
42
|
+
*/
|
43
|
+
static renderLists(outputDir, config, taxa) {
|
38
44
|
/**
|
39
|
-
* @param {
|
40
|
-
* @param {
|
41
|
-
* @param {
|
45
|
+
* @param {ListInfo[]} listInfo
|
46
|
+
* @param {Object<string,string>} attributes
|
47
|
+
* @param {TaxaCol[]} [columns]
|
48
|
+
* @returns {string}
|
42
49
|
*/
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
const iNatTaxa = [];
|
56
|
-
for (const taxon of taxa.getTaxonList()) {
|
57
|
-
if (list.include(taxon)) {
|
58
|
-
listTaxa.push(taxon);
|
59
|
-
calfloraTaxa.push(taxon.getCalfloraName());
|
60
|
-
iNatTaxa.push(taxon.getINatName());
|
61
|
-
}
|
62
|
-
}
|
63
|
-
|
64
|
-
if (listTaxa.length === 0) {
|
65
|
-
continue;
|
66
|
-
}
|
67
|
-
|
68
|
-
Files.write(
|
69
|
-
outputDir + "/calflora_" + list.filename + ".txt",
|
70
|
-
calfloraTaxa.join("\n")
|
71
|
-
);
|
72
|
-
Files.write(
|
73
|
-
outputDir + "/inat_" + list.filename + ".txt",
|
74
|
-
iNatTaxa.join("\n")
|
75
|
-
);
|
76
|
-
|
77
|
-
const cols = columns ? columns : list.columns;
|
78
|
-
new PageTaxonList(outputDir, list.name, list.filename).render(
|
79
|
-
listTaxa,
|
80
|
-
cols
|
81
|
-
);
|
82
|
-
|
83
|
-
// Check for sublists.
|
84
|
-
const subListHTML = list.listInfo
|
85
|
-
? getListArray(list.listInfo, { class: "indent" }, cols)
|
86
|
-
: "";
|
87
|
-
|
88
|
-
listArray.push(
|
89
|
-
HTML.getLink("./" + list.filename + ".html", list.name) +
|
90
|
-
" (" +
|
91
|
-
listTaxa.length +
|
92
|
-
")" +
|
93
|
-
subListHTML
|
94
|
-
);
|
95
|
-
}
|
96
|
-
|
97
|
-
return renderList(listArray, attributes);
|
50
|
+
function getListArray(listInfo, attributes = {}, columns) {
|
51
|
+
const listArray = [];
|
52
|
+
for (const list of listInfo) {
|
53
|
+
const listTaxa = [];
|
54
|
+
const calfloraTaxa = [];
|
55
|
+
const iNatTaxa = [];
|
56
|
+
for (const taxon of taxa.getTaxonList()) {
|
57
|
+
if (list.include(taxon)) {
|
58
|
+
listTaxa.push(taxon);
|
59
|
+
calfloraTaxa.push(taxon.getCalfloraName());
|
60
|
+
iNatTaxa.push(taxon.getINatName());
|
61
|
+
}
|
98
62
|
}
|
99
63
|
|
100
|
-
|
101
|
-
|
102
|
-
* @param {Object<string,string>} attributes
|
103
|
-
*/
|
104
|
-
function renderList(listsHTML, attributes = {}) {
|
105
|
-
return HTML.wrap("ul", HTML.arrayToLI(listsHTML), attributes);
|
64
|
+
if (listTaxa.length === 0) {
|
65
|
+
continue;
|
106
66
|
}
|
107
67
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
html += "</div>";
|
117
|
-
return html;
|
118
|
-
}
|
68
|
+
Files.write(
|
69
|
+
outputDir + "/calflora_" + list.filename + ".txt",
|
70
|
+
calfloraTaxa.join("\n")
|
71
|
+
);
|
72
|
+
Files.write(
|
73
|
+
outputDir + "/inat_" + list.filename + ".txt",
|
74
|
+
iNatTaxa.join("\n")
|
75
|
+
);
|
119
76
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
listInfo: [
|
126
|
-
{
|
127
|
-
name: config.getLabel("native", "Native"),
|
128
|
-
filename: "list_native",
|
129
|
-
include: (t) => t.isNative(),
|
130
|
-
},
|
131
|
-
{
|
132
|
-
name: config.getLabel("introduced", "Introduced"),
|
133
|
-
filename: "list_introduced",
|
134
|
-
include: (t) => !t.isNative(),
|
135
|
-
},
|
136
|
-
{
|
137
|
-
name: "All Plants",
|
138
|
-
filename: "list_all",
|
139
|
-
include: () => true,
|
140
|
-
},
|
141
|
-
],
|
142
|
-
},
|
143
|
-
{
|
144
|
-
title: "Rare Plants",
|
145
|
-
listInfo: [
|
146
|
-
{
|
147
|
-
name: "CNPS Ranked Plants",
|
148
|
-
filename: "list_rpi",
|
149
|
-
include: (t) => t.getRPIRank() !== undefined,
|
150
|
-
columns: RPI_COLUMNS,
|
151
|
-
listInfo: [
|
152
|
-
{
|
153
|
-
name: RarePlants.getRPIRankDescription("1A"),
|
154
|
-
filename: "list_rpi_1a",
|
155
|
-
include: (t) => t.getRPIRank() === "1A",
|
156
|
-
},
|
157
|
-
{
|
158
|
-
name: RarePlants.getRPIRankDescription("1B"),
|
159
|
-
filename: "list_rpi_1b",
|
160
|
-
include: (t) => t.getRPIRank() === "1B",
|
161
|
-
},
|
162
|
-
{
|
163
|
-
name: RarePlants.getRPIRankDescription("2A"),
|
164
|
-
filename: "list_rpi_2a",
|
165
|
-
include: (t) => t.getRPIRank() === "2A",
|
166
|
-
},
|
167
|
-
{
|
168
|
-
name: RarePlants.getRPIRankDescription("2B"),
|
169
|
-
filename: "list_rpi_2b",
|
170
|
-
include: (t) => t.getRPIRank() === "2B",
|
171
|
-
},
|
172
|
-
{
|
173
|
-
name: RarePlants.getRPIRankDescription("3"),
|
174
|
-
filename: "list_rpi_3",
|
175
|
-
include: (t) => t.getRPIRank() === "3",
|
176
|
-
},
|
177
|
-
{
|
178
|
-
name: RarePlants.getRPIRankDescription("4"),
|
179
|
-
filename: "list_rpi_4",
|
180
|
-
include: (t) => t.getRPIRank() === "4",
|
181
|
-
},
|
182
|
-
],
|
183
|
-
},
|
184
|
-
{
|
185
|
-
name: "Endangered Species",
|
186
|
-
filename: "list_endangered",
|
187
|
-
include: (t) =>
|
188
|
-
t.getCESA() !== undefined ||
|
189
|
-
t.getFESA() !== undefined,
|
190
|
-
columns: ENDANGERED_COLS,
|
191
|
-
},
|
192
|
-
],
|
193
|
-
},
|
194
|
-
];
|
77
|
+
const cols = columns ? columns : list.columns;
|
78
|
+
new PageTaxonList(outputDir, list.name, list.filename).render(
|
79
|
+
listTaxa,
|
80
|
+
cols
|
81
|
+
);
|
195
82
|
|
196
|
-
|
197
|
-
|
198
|
-
|
83
|
+
// Check for sublists.
|
84
|
+
const subListHTML = list.listInfo
|
85
|
+
? getListArray(list.listInfo, { class: "indent" }, cols)
|
86
|
+
: "";
|
199
87
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
renderList([HTML.getLink("./list_families.html", "Plant Families")])
|
88
|
+
listArray.push(
|
89
|
+
HTML.getLink("./" + list.filename + ".html", list.name) +
|
90
|
+
" (" +
|
91
|
+
listTaxa.length +
|
92
|
+
")" +
|
93
|
+
subListHTML
|
207
94
|
);
|
95
|
+
}
|
208
96
|
|
209
|
-
|
210
|
-
|
211
|
-
// Write lists to includes directory so it can be inserted into pages.
|
212
|
-
Files.write(outputDir + "/_includes/plantlists.html", html);
|
97
|
+
return renderList(listArray, attributes);
|
213
98
|
}
|
214
|
-
}
|
215
99
|
|
216
|
-
class PageTaxonList extends GenericPage {
|
217
100
|
/**
|
218
|
-
* @param {string}
|
219
|
-
* @param {string}
|
220
|
-
* @param {string} baseName
|
101
|
+
* @param {string[]} listsHTML
|
102
|
+
* @param {Object<string,string>} attributes
|
221
103
|
*/
|
222
|
-
|
223
|
-
|
104
|
+
function renderList(listsHTML, attributes = {}) {
|
105
|
+
return HTML.wrap("ul", HTML.arrayToLI(listsHTML), attributes);
|
224
106
|
}
|
225
107
|
|
226
108
|
/**
|
227
|
-
*
|
228
|
-
* @param {
|
229
|
-
* @param {TaxaCol[]|undefined} columns
|
109
|
+
* @param {string} title
|
110
|
+
* @param {string} listsHTML
|
230
111
|
*/
|
231
|
-
|
232
|
-
|
112
|
+
function renderSection(title, listsHTML) {
|
113
|
+
let html = '<div class="section nobullet">';
|
114
|
+
html += HTML.textElement("h2", title);
|
115
|
+
html += listsHTML;
|
116
|
+
html += "</div>";
|
117
|
+
return html;
|
118
|
+
}
|
233
119
|
|
234
|
-
|
120
|
+
/** @typedef {{name:string,filename:string,include:function(Taxon):boolean,columns?:TaxaCol[],listInfo?:ListInfo[]}} ListInfo */
|
121
|
+
/** @type {{title:string,listInfo:ListInfo[]}[]} */
|
122
|
+
const sections = [
|
123
|
+
{
|
124
|
+
title: "All Species",
|
125
|
+
listInfo: [
|
126
|
+
{
|
127
|
+
name: config.getLabel("native", "Native"),
|
128
|
+
filename: "list_native",
|
129
|
+
include: (t) => t.isNative(),
|
130
|
+
},
|
131
|
+
{
|
132
|
+
name: config.getLabel("introduced", "Introduced"),
|
133
|
+
filename: "list_introduced",
|
134
|
+
include: (t) => !t.isNative(),
|
135
|
+
},
|
136
|
+
{
|
137
|
+
name: "All Plants",
|
138
|
+
filename: "list_all",
|
139
|
+
include: () => true,
|
140
|
+
},
|
141
|
+
],
|
142
|
+
},
|
143
|
+
{
|
144
|
+
title: "Rare Plants",
|
145
|
+
listInfo: [
|
146
|
+
{
|
147
|
+
name: "CNPS Ranked Plants",
|
148
|
+
filename: "list_rpi",
|
149
|
+
include: (t) => t.getRPIRank() !== undefined,
|
150
|
+
columns: RPI_COLUMNS,
|
151
|
+
listInfo: [
|
152
|
+
{
|
153
|
+
name: RarePlants.getRPIRankDescription("1A"),
|
154
|
+
filename: "list_rpi_1a",
|
155
|
+
include: (t) => t.getRPIRank() === "1A",
|
156
|
+
},
|
157
|
+
{
|
158
|
+
name: RarePlants.getRPIRankDescription("1B"),
|
159
|
+
filename: "list_rpi_1b",
|
160
|
+
include: (t) => t.getRPIRank() === "1B",
|
161
|
+
},
|
162
|
+
{
|
163
|
+
name: RarePlants.getRPIRankDescription("2A"),
|
164
|
+
filename: "list_rpi_2a",
|
165
|
+
include: (t) => t.getRPIRank() === "2A",
|
166
|
+
},
|
167
|
+
{
|
168
|
+
name: RarePlants.getRPIRankDescription("2B"),
|
169
|
+
filename: "list_rpi_2b",
|
170
|
+
include: (t) => t.getRPIRank() === "2B",
|
171
|
+
},
|
172
|
+
{
|
173
|
+
name: RarePlants.getRPIRankDescription("3"),
|
174
|
+
filename: "list_rpi_3",
|
175
|
+
include: (t) => t.getRPIRank() === "3",
|
176
|
+
},
|
177
|
+
{
|
178
|
+
name: RarePlants.getRPIRankDescription("4"),
|
179
|
+
filename: "list_rpi_4",
|
180
|
+
include: (t) => t.getRPIRank() === "4",
|
181
|
+
},
|
182
|
+
],
|
183
|
+
},
|
184
|
+
{
|
185
|
+
name: "Endangered Species",
|
186
|
+
filename: "list_endangered",
|
187
|
+
include: (t) =>
|
188
|
+
t.getCESA() !== undefined || t.getFESA() !== undefined,
|
189
|
+
columns: ENDANGERED_COLS,
|
190
|
+
},
|
191
|
+
],
|
192
|
+
},
|
193
|
+
];
|
235
194
|
|
236
|
-
|
237
|
-
|
238
|
-
|
195
|
+
let html = '<div class="wrapper">';
|
196
|
+
for (const section of sections) {
|
197
|
+
const listHTML = getListArray(section.listInfo);
|
239
198
|
|
240
|
-
|
241
|
-
html +=
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
) +
|
249
|
-
"</li>";
|
250
|
-
html +=
|
251
|
-
"<li>" +
|
252
|
-
HTML.getLink(
|
253
|
-
"./inat_" + this.getBaseFileName() + ".txt",
|
254
|
-
"iNaturalist List"
|
255
|
-
) +
|
256
|
-
"</li>";
|
257
|
-
html += "</ul>";
|
258
|
-
html += "</div>";
|
199
|
+
if (listHTML.length > 0) {
|
200
|
+
html += renderSection(section.title, listHTML);
|
201
|
+
}
|
202
|
+
}
|
203
|
+
html += renderSection(
|
204
|
+
"Taxonomy",
|
205
|
+
renderList([HTML.getLink("./list_families.html", "Plant Families")])
|
206
|
+
);
|
259
207
|
|
260
|
-
|
208
|
+
html += "</div>";
|
261
209
|
|
262
|
-
|
263
|
-
|
210
|
+
// Write lists to includes directory so it can be inserted into pages.
|
211
|
+
Files.write(outputDir + "/_includes/plantlists.html", html);
|
212
|
+
}
|
213
|
+
}
|
214
|
+
|
215
|
+
class PageTaxonList extends GenericPage {
|
216
|
+
/**
|
217
|
+
* @param {string} outputDir
|
218
|
+
* @param {string} title
|
219
|
+
* @param {string} baseName
|
220
|
+
*/
|
221
|
+
constructor(outputDir, title, baseName) {
|
222
|
+
super(outputDir, title, baseName);
|
223
|
+
}
|
224
|
+
|
225
|
+
/**
|
226
|
+
*
|
227
|
+
* @param {Taxon[]} taxa
|
228
|
+
* @param {TaxaCol[]|undefined} columns
|
229
|
+
*/
|
230
|
+
render(taxa, columns) {
|
231
|
+
let html = this.getDefaultIntro();
|
232
|
+
|
233
|
+
html += '<div class="wrapper">';
|
234
|
+
|
235
|
+
html += '<div class="section">';
|
236
|
+
html += HTMLTaxon.getTaxaTable(taxa, columns);
|
237
|
+
html += "</div>";
|
238
|
+
|
239
|
+
html += '<div class="section nobullet">';
|
240
|
+
html += HTML.textElement("h2", "Download");
|
241
|
+
html += "<ul>";
|
242
|
+
html +=
|
243
|
+
"<li>" +
|
244
|
+
HTML.getLink(
|
245
|
+
"./calflora_" + this.getBaseFileName() + ".txt",
|
246
|
+
"Calflora List"
|
247
|
+
) +
|
248
|
+
"</li>";
|
249
|
+
html +=
|
250
|
+
"<li>" +
|
251
|
+
HTML.getLink(
|
252
|
+
"./inat_" + this.getBaseFileName() + ".txt",
|
253
|
+
"iNaturalist List"
|
254
|
+
) +
|
255
|
+
"</li>";
|
256
|
+
html += "</ul>";
|
257
|
+
html += "</div>";
|
258
|
+
|
259
|
+
html += "</div>";
|
260
|
+
|
261
|
+
this.writeFile(html);
|
262
|
+
}
|
264
263
|
}
|
265
264
|
|
266
265
|
export { PageRenderer };
|
package/lib/photo.js
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
const CC0 = "CC0";
|
2
|
+
const CC_BY = "CC BY";
|
3
|
+
const CC_BY_NC = "CC BY-NC";
|
4
|
+
const COPYRIGHT = "C";
|
5
|
+
|
6
|
+
class Photo {
|
7
|
+
/** @type {string?} */
|
8
|
+
#url;
|
9
|
+
/** @type {string?} */
|
10
|
+
rightsHolder;
|
11
|
+
/** @type {null | typeof COPYRIGHT | typeof CC_BY | typeof CC_BY_NC | typeof CC0} */
|
12
|
+
rights;
|
13
|
+
|
14
|
+
/**
|
15
|
+
* @param {string?} url
|
16
|
+
* @param {string?} rightsHolder
|
17
|
+
* @param {null | typeof COPYRIGHT | typeof CC_BY | typeof CC_BY_NC | typeof CC0} rights
|
18
|
+
*/
|
19
|
+
constructor( url, rightsHolder, rights ) {
|
20
|
+
this.#url = url;
|
21
|
+
this.rightsHolder = rightsHolder;
|
22
|
+
this.rights = rights;
|
23
|
+
}
|
24
|
+
|
25
|
+
getUrl() {
|
26
|
+
return this.#url;
|
27
|
+
}
|
28
|
+
|
29
|
+
/**
|
30
|
+
* Return URL of page from whence this photo came
|
31
|
+
* @return {string?}
|
32
|
+
*/
|
33
|
+
getSourceUrl() {
|
34
|
+
return null;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
export {
|
39
|
+
CC0,
|
40
|
+
CC_BY,
|
41
|
+
CC_BY_NC,
|
42
|
+
COPYRIGHT,
|
43
|
+
Photo
|
44
|
+
};
|
package/lib/taxa.js
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
+
import * as fs from "node:fs";
|
2
|
+
import path from "node:path";
|
3
|
+
|
1
4
|
import { Config } from "./config.js";
|
2
5
|
import { CSV } from "./csv.js";
|
3
6
|
import { Genera } from "./genera.js";
|
4
7
|
import { Taxon } from "./taxon.js";
|
5
8
|
import { Families } from "./families.js";
|
6
9
|
import { FlowerColor } from "./flowercolor.js";
|
10
|
+
import { InatPhoto } from "./inat_photo.js";
|
7
11
|
|
8
12
|
const FLOWER_COLORS = [
|
9
13
|
{ name: "white", color: "white" },
|
@@ -35,6 +39,7 @@ class Taxa {
|
|
35
39
|
* @param {function(TaxonData,Genera):Taxon} taxonFactory
|
36
40
|
* @param {TaxonData[]} [extraTaxa=[]]
|
37
41
|
* @param {SynonymData[]} [extraSynonyms=[]]
|
42
|
+
* @param {boolean} includePhotos
|
38
43
|
*/
|
39
44
|
constructor(
|
40
45
|
inclusionList,
|
@@ -42,7 +47,8 @@ class Taxa {
|
|
42
47
|
showFlowerErrors,
|
43
48
|
taxonFactory = (td, g) => new Taxon(td, g),
|
44
49
|
extraTaxa = [],
|
45
|
-
extraSynonyms = []
|
50
|
+
extraSynonyms = [],
|
51
|
+
includePhotos = true
|
46
52
|
) {
|
47
53
|
this.#isSubset = inclusionList !== true;
|
48
54
|
|
@@ -76,11 +82,39 @@ class Taxa {
|
|
76
82
|
a.getName().localeCompare(b.getName())
|
77
83
|
);
|
78
84
|
|
85
|
+
|
86
|
+
if ( includePhotos ) {
|
87
|
+
this.#loadInatPhotos( dataDir );
|
88
|
+
}
|
89
|
+
|
79
90
|
const synCSV = CSV.parseFile(dataDir, "synonyms.csv");
|
80
91
|
this.#loadSyns(synCSV, inclusionList);
|
81
92
|
this.#loadSyns(extraSynonyms, inclusionList);
|
82
93
|
}
|
83
94
|
|
95
|
+
/**
|
96
|
+
* @param {string} dataDir
|
97
|
+
*/
|
98
|
+
#loadInatPhotos( dataDir ) {
|
99
|
+
const photosFileName = "inattaxonphotos.csv";
|
100
|
+
if ( fs.existsSync( path.join( dataDir, photosFileName ) ) ) {
|
101
|
+
/** @type {InatCsvPhoto[]} */
|
102
|
+
const csvPhotos = CSV.parseFile( dataDir, photosFileName );
|
103
|
+
for ( const csvPhoto of csvPhotos ) {
|
104
|
+
const taxon = this.getTaxon(csvPhoto.name);
|
105
|
+
if(!taxon) {
|
106
|
+
continue;
|
107
|
+
}
|
108
|
+
taxon.addPhoto(new InatPhoto(
|
109
|
+
csvPhoto.id,
|
110
|
+
csvPhoto.ext,
|
111
|
+
csvPhoto.licenseCode,
|
112
|
+
csvPhoto.attrName
|
113
|
+
) );
|
114
|
+
}
|
115
|
+
}
|
116
|
+
}
|
117
|
+
|
84
118
|
getFamilies() {
|
85
119
|
return this.#families;
|
86
120
|
}
|
@@ -175,9 +209,9 @@ class Taxa {
|
|
175
209
|
const color = this.#flower_colors[colorName];
|
176
210
|
if (!color) {
|
177
211
|
throw new Error(
|
178
|
-
|
212
|
+
"flower color \"" +
|
179
213
|
colorName +
|
180
|
-
|
214
|
+
"\" not found for " +
|
181
215
|
name
|
182
216
|
);
|
183
217
|
}
|