@ca-plant-list/ca-plant-list 0.4.37 → 0.4.39
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/data/exceptions.json +9 -1
- package/data/inatobsphotos.csv +17 -12
- package/data/inattaxonphotos.csv +73 -54
- package/data/synonyms.csv +4 -0
- package/data/taxa.csv +171 -169
- package/lib/csv.js +5 -0
- package/lib/ebook/ebookpage.js +6 -3
- package/lib/ebook/pages/pageListFamilies.js +2 -4
- package/lib/ebook/pages/pageListFlowers.js +3 -5
- package/lib/ebook/pages/page_list_flower_color.js +2 -4
- package/lib/ebook/pages/page_list_species.js +2 -4
- package/lib/ebook/pages/taxonpage.js +3 -3
- package/lib/ebook/pages/tocpage.js +1 -1
- package/lib/ebook/plantbook.js +3 -2
- package/lib/taxonomy/taxon.js +1 -1
- package/lib/tools/rpi.js +45 -14
- package/package.json +13 -13
package/lib/csv.js
CHANGED
|
@@ -10,6 +10,7 @@ export class CSV {
|
|
|
10
10
|
* @param {string} fileName
|
|
11
11
|
* @param {import("csv-parse").ColumnOption[]|boolean|function (string[]):string[]} columns
|
|
12
12
|
* @param {string|undefined} delimiter
|
|
13
|
+
* @returns {import("csv-parse").Options}
|
|
13
14
|
*/
|
|
14
15
|
static #getOptions(fileName, columns, delimiter) {
|
|
15
16
|
/** @type {import("csv-parse").Options} */
|
|
@@ -104,6 +105,8 @@ export class CSV {
|
|
|
104
105
|
static readFile(fileName, columns = true, delimiter) {
|
|
105
106
|
const content = fs.readFileSync(fileName);
|
|
106
107
|
const options = this.#getOptions(fileName, columns, delimiter);
|
|
108
|
+
/** @type {T[]} */
|
|
109
|
+
// @ts-ignore - need to get options @type to have correct column options
|
|
107
110
|
return parseSync(content, options);
|
|
108
111
|
}
|
|
109
112
|
|
|
@@ -126,6 +129,8 @@ export class CSV {
|
|
|
126
129
|
const content = fs.readFileSync(fileName);
|
|
127
130
|
const options = this.#getOptions(fileName, getHeaders, delimiter);
|
|
128
131
|
|
|
132
|
+
/** @type {T[]} */
|
|
133
|
+
// @ts-ignore - need to get options @type to have correct column options
|
|
129
134
|
const data = parseSync(content, options);
|
|
130
135
|
if (headers === undefined) {
|
|
131
136
|
throw new Error();
|
package/lib/ebook/ebookpage.js
CHANGED
|
@@ -16,9 +16,9 @@ export class EBookPage {
|
|
|
16
16
|
this.#rootPrefix = rootPrefix;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
create() {
|
|
19
|
+
async create() {
|
|
20
20
|
let html = this.#renderPageStart(this.#title);
|
|
21
|
-
html += this.renderPageBody();
|
|
21
|
+
html += await this.renderPageBody();
|
|
22
22
|
html += this.#renderPageEnd();
|
|
23
23
|
fs.writeFileSync(this.#fileName, html);
|
|
24
24
|
}
|
|
@@ -31,7 +31,10 @@ export class EBookPage {
|
|
|
31
31
|
return "<body>";
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
/**
|
|
35
|
+
* @returns {Promise<string>}
|
|
36
|
+
*/
|
|
37
|
+
async renderPageBody() {
|
|
35
38
|
throw new Error("must be implemented by subclass");
|
|
36
39
|
}
|
|
37
40
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EBookPage } from "../ebookpage.js";
|
|
2
2
|
import { XHTML } from "../xhtml.js";
|
|
3
3
|
|
|
4
|
-
class PageListFamilies extends EBookPage {
|
|
4
|
+
export class PageListFamilies extends EBookPage {
|
|
5
5
|
#families;
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -13,7 +13,7 @@ class PageListFamilies extends EBookPage {
|
|
|
13
13
|
this.#families = families;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
renderPageBody() {
|
|
16
|
+
async renderPageBody() {
|
|
17
17
|
const html = XHTML.textElement("h1", this.getTitle());
|
|
18
18
|
|
|
19
19
|
const links = [];
|
|
@@ -27,5 +27,3 @@ class PageListFamilies extends EBookPage {
|
|
|
27
27
|
return html + XHTML.wrap("ol", XHTML.arrayToLI(links));
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
|
|
31
|
-
export { PageListFamilies };
|
|
@@ -5,7 +5,7 @@ import { EBook } from "../ebook.js";
|
|
|
5
5
|
|
|
6
6
|
const FN_FLOWER_TIME_INDEX = "fm.html";
|
|
7
7
|
|
|
8
|
-
class PageListFlowers {
|
|
8
|
+
export class PageListFlowers {
|
|
9
9
|
/**
|
|
10
10
|
* @param {string} contentDir
|
|
11
11
|
* @param {import("../../types.js").Taxa} taxa
|
|
@@ -70,7 +70,7 @@ class PageListFlowerTimeIndex extends EBookPage {
|
|
|
70
70
|
super(outputDir + "/" + FN_FLOWER_TIME_INDEX, "Flowering Times");
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
renderPageBody() {
|
|
73
|
+
async renderPageBody() {
|
|
74
74
|
const html = XHTML.textElement("h1", this.getTitle());
|
|
75
75
|
return html + PageListFlowers.renderMonthLinks();
|
|
76
76
|
}
|
|
@@ -106,7 +106,7 @@ class PageListFlowerTime extends EBookPage {
|
|
|
106
106
|
return "list_fm_" + m1 + ".html";
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
renderPageBody() {
|
|
109
|
+
async renderPageBody() {
|
|
110
110
|
const html = XHTML.textElement("h1", this.getTitle());
|
|
111
111
|
|
|
112
112
|
/** @type {[number,number]} */
|
|
@@ -123,5 +123,3 @@ class PageListFlowerTime extends EBookPage {
|
|
|
123
123
|
return html + XHTML.wrap("ol", XHTML.arrayToLI(links));
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
|
-
|
|
127
|
-
export { PageListFlowers, PageListFlowerTime };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EBookPage } from "../ebookpage.js";
|
|
2
2
|
import { XHTML } from "../xhtml.js";
|
|
3
3
|
|
|
4
|
-
class PageListFlowerColor extends EBookPage {
|
|
4
|
+
export class PageListFlowerColor extends EBookPage {
|
|
5
5
|
#color;
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -16,7 +16,7 @@ class PageListFlowerColor extends EBookPage {
|
|
|
16
16
|
this.#color = color;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
renderPageBody() {
|
|
19
|
+
async renderPageBody() {
|
|
20
20
|
const html = XHTML.textElement("h1", this.getTitle());
|
|
21
21
|
|
|
22
22
|
const links = [];
|
|
@@ -27,5 +27,3 @@ class PageListFlowerColor extends EBookPage {
|
|
|
27
27
|
return html + XHTML.wrap("ol", XHTML.arrayToLI(links));
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
|
|
31
|
-
export { PageListFlowerColor };
|
|
@@ -2,7 +2,7 @@ import { HTMLTaxon } from "../../htmltaxon.js";
|
|
|
2
2
|
import { EBookPage } from "../ebookpage.js";
|
|
3
3
|
import { XHTML } from "../xhtml.js";
|
|
4
4
|
|
|
5
|
-
class PageListSpecies extends EBookPage {
|
|
5
|
+
export class PageListSpecies extends EBookPage {
|
|
6
6
|
#taxa;
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -17,7 +17,7 @@ class PageListSpecies extends EBookPage {
|
|
|
17
17
|
this.#taxa = taxa;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
renderPageBody() {
|
|
20
|
+
async renderPageBody() {
|
|
21
21
|
const html = XHTML.textElement("h1", this.getTitle());
|
|
22
22
|
|
|
23
23
|
const links = [];
|
|
@@ -28,5 +28,3 @@ class PageListSpecies extends EBookPage {
|
|
|
28
28
|
return html + XHTML.wrap("ol", XHTML.arrayToLI(links));
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
|
|
32
|
-
export { PageListSpecies };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { imageSizeFromFile } from "image-size/fromFile";
|
|
1
2
|
import { EBookPage } from "../ebookpage.js";
|
|
2
3
|
import { XHTML } from "../xhtml.js";
|
|
3
4
|
import { Markdown } from "../../markdown.js";
|
|
@@ -5,7 +6,6 @@ import { HTMLTaxon } from "../../htmltaxon.js";
|
|
|
5
6
|
import { Config } from "../../config.js";
|
|
6
7
|
import { Files } from "../../files.js";
|
|
7
8
|
import { Images } from "../images.js";
|
|
8
|
-
import imageSize from "image-size";
|
|
9
9
|
|
|
10
10
|
class TaxonPage extends EBookPage {
|
|
11
11
|
#config;
|
|
@@ -25,7 +25,7 @@ class TaxonPage extends EBookPage {
|
|
|
25
25
|
this.#images = images;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
renderPageBody() {
|
|
28
|
+
async renderPageBody() {
|
|
29
29
|
/**
|
|
30
30
|
* @param {string} name
|
|
31
31
|
*/
|
|
@@ -72,7 +72,7 @@ class TaxonPage extends EBookPage {
|
|
|
72
72
|
|
|
73
73
|
let photoHTML = "";
|
|
74
74
|
for (const photo of photos) {
|
|
75
|
-
const dimensions =
|
|
75
|
+
const dimensions = await imageSizeFromFile(
|
|
76
76
|
this.#images.getCompressedFilePath(photo),
|
|
77
77
|
);
|
|
78
78
|
let img = XHTML.textElement("img", "", {
|
package/lib/ebook/plantbook.js
CHANGED
|
@@ -56,12 +56,13 @@ class PlantBook extends EBook {
|
|
|
56
56
|
|
|
57
57
|
for (let index = 0; index < taxonList.length; index++) {
|
|
58
58
|
const taxon = taxonList[index];
|
|
59
|
-
new TaxonPage(
|
|
59
|
+
const page = new TaxonPage(
|
|
60
60
|
contentDir,
|
|
61
61
|
this.#config,
|
|
62
62
|
taxon,
|
|
63
63
|
this.#images,
|
|
64
|
-
)
|
|
64
|
+
);
|
|
65
|
+
await page.create();
|
|
65
66
|
meter.update(index + 1);
|
|
66
67
|
}
|
|
67
68
|
meter.stop();
|
package/lib/taxonomy/taxon.js
CHANGED
|
@@ -226,7 +226,7 @@ class Taxon extends Taxonomy {
|
|
|
226
226
|
|
|
227
227
|
getINatName() {
|
|
228
228
|
const name = this.#iNatSyn ? this.#iNatSyn : this.getName();
|
|
229
|
-
return name.replace(/ (subsp|var)\./, "").replace("×", "× ");
|
|
229
|
+
return name.replace(/ (cf|subsp|var)\./, "").replace("×", "× ");
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
/**
|
package/lib/tools/rpi.js
CHANGED
|
@@ -4,7 +4,7 @@ import { Files } from "../files.js";
|
|
|
4
4
|
import { TaxaCSV } from "./taxacsv.js";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* @typedef {"CESA"|"CNDDB"|"FESA"|"Global"} Rank
|
|
7
|
+
* @typedef {"CRPR"|"CESA"|"CNDDB"|"FESA"|"Global"} Rank
|
|
8
8
|
* @typedef {Map<string,Map<Rank,string|undefined>>} RanksToUpdate
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -166,17 +166,13 @@ export class RPI {
|
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
rank,
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
169
|
+
checkStatusMatch(
|
|
170
|
+
name,
|
|
171
|
+
"CRPR",
|
|
172
|
+
rank,
|
|
173
|
+
taxon.getRPIRankAndThreat(),
|
|
174
|
+
ranksToUpdate,
|
|
175
|
+
);
|
|
180
176
|
checkStatusMatch(
|
|
181
177
|
name,
|
|
182
178
|
"CESA",
|
|
@@ -249,7 +245,7 @@ export class RPI {
|
|
|
249
245
|
|
|
250
246
|
this.#checkExceptions(taxa, config, exceptions, errorLog);
|
|
251
247
|
|
|
252
|
-
this.#scrape(toolsDataDir, taxa, exceptions, errorLog);
|
|
248
|
+
this.#scrape(toolsDataDir, dataDir, taxa, exceptions, errorLog, update);
|
|
253
249
|
|
|
254
250
|
if (update) {
|
|
255
251
|
this.#updateRanks(dataDir, ranksToUpdate);
|
|
@@ -421,11 +417,20 @@ export class RPI {
|
|
|
421
417
|
|
|
422
418
|
/**
|
|
423
419
|
* @param {string} toolsDataDir
|
|
420
|
+
* @param {string} dataDir
|
|
424
421
|
* @param {import("../types.js").Taxa} taxa
|
|
425
422
|
* @param {import("../exceptions.js").Exceptions} exceptions
|
|
426
423
|
* @param {import("../errorlog.js").ErrorLog} errorLog
|
|
424
|
+
* @param {boolean} update
|
|
427
425
|
*/
|
|
428
|
-
static async #scrape(
|
|
426
|
+
static async #scrape(
|
|
427
|
+
toolsDataDir,
|
|
428
|
+
dataDir,
|
|
429
|
+
taxa,
|
|
430
|
+
exceptions,
|
|
431
|
+
errorLog,
|
|
432
|
+
update,
|
|
433
|
+
) {
|
|
429
434
|
const toolsDataPath = toolsDataDir + "/rpi";
|
|
430
435
|
const fileName = HTML_FILE_NAME;
|
|
431
436
|
const filePath = toolsDataPath + "/" + fileName;
|
|
@@ -444,6 +449,9 @@ export class RPI {
|
|
|
444
449
|
rpiIDs[name] = id;
|
|
445
450
|
}
|
|
446
451
|
|
|
452
|
+
/** @type {Map<string,string>} */
|
|
453
|
+
const idsToUpdate = new Map();
|
|
454
|
+
|
|
447
455
|
for (const taxon of taxa.getTaxonList()) {
|
|
448
456
|
if (!taxon.getRPIRankAndThreat()) {
|
|
449
457
|
continue;
|
|
@@ -463,8 +471,13 @@ export class RPI {
|
|
|
463
471
|
id,
|
|
464
472
|
taxon.getRPIID(),
|
|
465
473
|
);
|
|
474
|
+
idsToUpdate.set(name, id);
|
|
466
475
|
}
|
|
467
476
|
}
|
|
477
|
+
|
|
478
|
+
if (update) {
|
|
479
|
+
this.#updateIDs(dataDir, idsToUpdate);
|
|
480
|
+
}
|
|
468
481
|
}
|
|
469
482
|
|
|
470
483
|
/**
|
|
@@ -485,6 +498,24 @@ export class RPI {
|
|
|
485
498
|
return false;
|
|
486
499
|
}
|
|
487
500
|
|
|
501
|
+
/**
|
|
502
|
+
* @param {string} dataDir
|
|
503
|
+
* @param {Map<string,string>} idsToUpdate
|
|
504
|
+
*/
|
|
505
|
+
static #updateIDs(dataDir, idsToUpdate) {
|
|
506
|
+
const taxa = new TaxaCSV(dataDir);
|
|
507
|
+
|
|
508
|
+
for (const taxonData of taxa.getTaxa()) {
|
|
509
|
+
const id = idsToUpdate.get(taxonData.taxon_name);
|
|
510
|
+
if (!id) {
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
taxonData["RPI ID"] = id;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
taxa.write();
|
|
517
|
+
}
|
|
518
|
+
|
|
488
519
|
/**
|
|
489
520
|
* @param {string} dataDir
|
|
490
521
|
* @param {RanksToUpdate} ranksToUpdate
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ca-plant-list/ca-plant-list",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.39",
|
|
4
4
|
"description": "Tools to create files for a website listing plants in an area of California.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -36,18 +36,18 @@
|
|
|
36
36
|
"inatobsphotos": "scripts/inatobsphotos.js"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@11ty/eleventy": "^3.
|
|
39
|
+
"@11ty/eleventy": "^3.1.2",
|
|
40
40
|
"@htmltools/scrape": "^0.1.1",
|
|
41
|
-
"archiver": "^
|
|
41
|
+
"archiver": "^7.0.1",
|
|
42
42
|
"cli-progress": "^3.12.0",
|
|
43
|
-
"commander": "^14.0.
|
|
44
|
-
"csv-parse": "^
|
|
45
|
-
"csv-stringify": "^6.
|
|
43
|
+
"commander": "^14.0.2",
|
|
44
|
+
"csv-parse": "^6.1.0",
|
|
45
|
+
"csv-stringify": "^6.6.0",
|
|
46
46
|
"exceljs": "^4.4.0",
|
|
47
|
-
"image-size": "^
|
|
47
|
+
"image-size": "^2.0.2",
|
|
48
48
|
"markdown-it": "^14.1.0",
|
|
49
|
-
"sharp": "^0.
|
|
50
|
-
"svgo-ll": "^6.0
|
|
49
|
+
"sharp": "^0.34.4",
|
|
50
|
+
"svgo-ll": "^6.2.0",
|
|
51
51
|
"unzipper": "^0.12.3"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
@@ -57,10 +57,10 @@
|
|
|
57
57
|
"@types/markdown-it": "^14.1.2",
|
|
58
58
|
"@types/node": "^22.10.7",
|
|
59
59
|
"@types/unzipper": "^0.10.9",
|
|
60
|
-
"eslint": "^9.
|
|
61
|
-
"jest": "^
|
|
60
|
+
"eslint": "^9.39.0",
|
|
61
|
+
"jest": "^30.2.0",
|
|
62
62
|
"prettier": "^3.6.2",
|
|
63
|
-
"puppeteer": "^24.
|
|
64
|
-
"typescript": "^5.9.
|
|
63
|
+
"puppeteer": "^24.27.0",
|
|
64
|
+
"typescript": "^5.9.3"
|
|
65
65
|
}
|
|
66
66
|
}
|