@ca-plant-list/ca-plant-list 0.3.6 → 0.4.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/.vscode/settings.json +7 -1
- package/data/synonyms.csv +109 -3
- package/data/taxa.csv +65 -29
- package/data/text/Antennaria-media.md +1 -0
- package/data/text/Antennaria-rosea-subsp-rosea.md +1 -0
- package/data/text/Antirrhinum-thompsonii.md +1 -0
- package/data/text/Calyptridium-monospermum.md +1 -0
- package/data/text/Calyptridium-umbellatum.md +1 -0
- package/data/text/Camassia-leichtlinii-subsp-suksdorfii.md +1 -0
- package/data/text/Camassia-quamash-subsp-breviflora.md +1 -0
- package/data/text/Clarkia-affinis.md +1 -0
- package/data/text/Clarkia-breweri.md +1 -0
- package/data/text/Clarkia-concinna-subsp-automixa.md +1 -0
- package/data/text/Clarkia-modesta.md +1 -0
- package/data/text/Clarkia-purpurea-subsp-quadrivulnera.md +1 -0
- package/data/text/Clarkia-rubicunda.md +1 -0
- package/data/text/Delphinium-californicum-subsp-californicum.md +1 -1
- package/data/text/Delphinium-californicum-subsp-interius.md +1 -0
- package/data/text/Delphinium-glaucum.md +1 -0
- package/data/text/Delphinium-hesperium-subsp-hesperium.md +1 -1
- package/data/text/Delphinium-hesperium-subsp-pallescens.md +1 -0
- package/data/text/Delphinium-nuttallianum.md +1 -0
- package/data/text/Delphinium-parryi-subsp-parryi.md +1 -0
- package/data/text/Drymocallis-glandulosa-var-glandulosa.md +1 -0
- package/data/text/Drymocallis-lactea-var-austiniae.md +1 -0
- package/data/text/Erigeron-compositus.md +1 -0
- package/data/text/Erigeron-glacialis-var-glacialis.md +1 -0
- package/data/text/Erythranthe-breweri.md +1 -0
- package/data/text/Erythranthe-erubescens.md +1 -0
- package/data/text/Erythranthe-moschata.md +1 -0
- package/data/text/Erythranthe-primuloides.md +1 -0
- package/data/text/Erythranthe-tilingii.md +1 -0
- package/data/text/Lilium-pardalinum-subsp-shastense.md +1 -0
- package/data/text/Logfia-filaginoides.md +1 -0
- package/data/text/Logfia-gallica.md +1 -0
- package/data/text/Malacothamnus-arcuatus-var-elmeri.md +1 -0
- package/data/text/Malacothamnus-fremontii-var-fremontii.md +1 -0
- package/data/text/Navarretia-leptalea-subsp-bicolor.md +1 -0
- package/data/text/Navarretia-leptalea-subsp-leptalea.md +1 -0
- package/data/text/Polemonium-californicum.md +1 -0
- package/data/text/Polemonium-pulcherrimum-var-pulcherrimum.md +1 -0
- package/data/text/Primula-jeffreyi.md +1 -0
- package/data/text/Primula-tetrandra.md +1 -0
- package/data/text/Trifolium-obtusiflorum.md +1 -0
- package/data/text/Trifolium-willdenovii.md +1 -0
- package/lib/basepagerenderer.js +3 -4
- package/lib/config.js +42 -19
- package/lib/csv.js +54 -36
- package/lib/ebook/ebook.js +84 -57
- package/lib/ebook/ebookpage.js +22 -11
- package/lib/ebook/ebooksitegenerator.js +36 -14
- package/lib/ebook/glossarypages.js +20 -17
- package/lib/ebook/images.js +59 -42
- package/lib/ebook/pages/page_list_families.js +0 -2
- package/lib/ebook/pages/page_list_flower_color.js +14 -9
- package/lib/ebook/pages/page_list_flowers.js +59 -41
- package/lib/ebook/pages/page_list_species.js +15 -9
- package/lib/ebook/pages/taxonpage.js +3 -6
- package/lib/ebook/pages/tocpage.js +26 -20
- package/lib/ebook/plantbook.js +6 -13
- package/lib/ebook/{image.js → taxonimage.js} +2 -2
- package/lib/ebook/xhtml.js +3 -5
- package/lib/exceptions.js +42 -26
- package/lib/externalsites.js +11 -4
- package/lib/families.js +10 -10
- package/lib/flowercolor.js +42 -0
- package/lib/genera.js +13 -23
- package/lib/genericpage.js +38 -18
- package/lib/html.js +11 -23
- package/lib/htmltaxon.js +114 -14
- package/lib/index.d.ts +54 -0
- package/lib/index.js +2 -30
- package/lib/jekyll.js +49 -21
- package/lib/jepson.js +7 -8
- package/lib/markdown.js +13 -9
- package/lib/pagerenderer.js +162 -82
- package/lib/plants/glossary.js +14 -14
- package/lib/program.js +47 -0
- package/lib/rareplants.js +44 -30
- package/lib/sitegenerator.js +41 -24
- package/lib/taxa.js +25 -142
- package/lib/taxon.js +3 -5
- package/lib/web/glossarypages.js +37 -18
- package/lib/web/pagetaxon.js +1 -5
- package/package.json +5 -3
- package/schemas/exceptions.schema.json +57 -0
- package/scripts/build-ebook.js +39 -48
- package/scripts/build-site.js +49 -28
- package/types/classes.d.ts +154 -0
- package/lib/commandandtaxaprocessor.js +0 -25
- package/lib/commandprocessor.js +0 -108
- package/lib/generictaxaloader.js +0 -48
- package/lib/taxaloader.js +0 -48
- package/lib/taxaprocessor.js +0 -34
package/lib/index.js
CHANGED
@@ -1,58 +1,30 @@
|
|
1
|
-
/**
|
2
|
-
* @typedef {{
|
3
|
-
* bloom_end:string;
|
4
|
-
* bloom_start:string;
|
5
|
-
* calrecnum:string;
|
6
|
-
* CESA:string;
|
7
|
-
* CRPR:string;
|
8
|
-
* "common name":string;
|
9
|
-
* FESA:string;
|
10
|
-
* flower_color:string;
|
11
|
-
* GRank:string;
|
12
|
-
* "inat id":string;
|
13
|
-
* "jepson id":string;
|
14
|
-
* life_cycle:"annual"|"perennial"|undefined
|
15
|
-
* SRank:string;
|
16
|
-
* status:string;
|
17
|
-
* "RPI ID":string;
|
18
|
-
* taxon_name:string}} TaxonData
|
19
|
-
*/
|
20
|
-
|
21
1
|
import { BasePageRenderer } from "./basepagerenderer.js";
|
22
|
-
import { CommandProcessor } from "./commandprocessor.js";
|
23
|
-
import { CommandAndTaxaProcessor } from "./commandandtaxaprocessor.js";
|
24
2
|
import { Config } from "./config.js";
|
25
3
|
import { CSV } from "./csv.js";
|
26
4
|
import { ErrorLog } from "./errorlog.js";
|
27
5
|
import { Exceptions } from "./exceptions.js";
|
28
6
|
import { Families } from "./families.js";
|
29
7
|
import { Files } from "./files.js";
|
30
|
-
import { GenericTaxaLoader } from "./generictaxaloader.js";
|
31
8
|
import { HTML } from "./html.js";
|
32
9
|
import { Jekyll } from "./jekyll.js";
|
33
10
|
import { PlantBook } from "./ebook/plantbook.js";
|
11
|
+
import { Program } from "./program.js";
|
34
12
|
import { Taxa } from "./taxa.js";
|
35
|
-
import { TaxaLoader } from "./taxaloader.js";
|
36
|
-
import { TaxaProcessor } from "./taxaprocessor.js";
|
37
13
|
import { Taxon, TAXA_COLNAMES } from "./taxon.js";
|
38
14
|
|
39
15
|
export {
|
40
16
|
BasePageRenderer,
|
41
|
-
CommandProcessor,
|
42
|
-
CommandAndTaxaProcessor,
|
43
17
|
Config,
|
44
18
|
CSV,
|
45
19
|
ErrorLog,
|
46
20
|
Exceptions,
|
47
21
|
Families,
|
48
22
|
Files,
|
49
|
-
GenericTaxaLoader,
|
50
23
|
HTML,
|
51
24
|
Jekyll,
|
52
25
|
PlantBook,
|
26
|
+
Program,
|
53
27
|
Taxa,
|
54
|
-
TaxaLoader,
|
55
|
-
TaxaProcessor,
|
56
28
|
TAXA_COLNAMES,
|
57
29
|
Taxon,
|
58
30
|
};
|
package/lib/jekyll.js
CHANGED
@@ -4,40 +4,68 @@ import { SiteGenerator } from "./sitegenerator.js";
|
|
4
4
|
const FRONT_DELIM = "---";
|
5
5
|
|
6
6
|
class Jekyll extends SiteGenerator {
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
/**
|
8
|
+
* @param {string} baseDir
|
9
|
+
*/
|
10
|
+
constructor(baseDir) {
|
11
|
+
super(baseDir);
|
10
12
|
}
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
/**
|
15
|
+
* @param {Object<string,string>} atts
|
16
|
+
*/
|
17
|
+
static getFrontMatter(atts) {
|
18
|
+
const lines = [FRONT_DELIM];
|
19
|
+
for (const [k, v] of Object.entries(atts)) {
|
20
|
+
lines.push(k + ': "' + v + '"');
|
16
21
|
}
|
17
|
-
if (
|
18
|
-
lines.push(
|
22
|
+
if (!atts.layout) {
|
23
|
+
lines.push("layout: default");
|
19
24
|
}
|
20
|
-
lines.push(
|
21
|
-
return lines.join(
|
25
|
+
lines.push(FRONT_DELIM);
|
26
|
+
return lines.join("\n") + "\n";
|
22
27
|
}
|
23
28
|
|
24
|
-
|
25
|
-
|
29
|
+
/**
|
30
|
+
* @param {string} baseDir
|
31
|
+
* @param {string} path
|
32
|
+
*/
|
33
|
+
static hasInclude(baseDir, path) {
|
34
|
+
return Files.exists(baseDir + "/_includes/" + path);
|
26
35
|
}
|
27
36
|
|
28
|
-
|
37
|
+
/**
|
38
|
+
* @param {string} path
|
39
|
+
*/
|
40
|
+
static include(path) {
|
29
41
|
// This works for .md includes; should have conditional logic to detect other types.
|
30
|
-
return
|
42
|
+
return (
|
43
|
+
"{% capture my_include %}{% include " +
|
44
|
+
path +
|
45
|
+
" %}{% endcapture %}{{ my_include | markdownify }}"
|
46
|
+
);
|
31
47
|
}
|
32
48
|
|
33
|
-
|
34
|
-
|
49
|
+
/**
|
50
|
+
* @param {string} baseDir
|
51
|
+
* @param {string} path
|
52
|
+
* @param {string} data
|
53
|
+
*/
|
54
|
+
static writeInclude(baseDir, path, data) {
|
55
|
+
Files.write(baseDir + "/_includes/" + path, data);
|
35
56
|
}
|
36
57
|
|
37
|
-
|
38
|
-
|
58
|
+
/**
|
59
|
+
* @param {string} content
|
60
|
+
* @param {Object<string,string>} attributes
|
61
|
+
* @param {string} filename
|
62
|
+
*/
|
63
|
+
writeTemplate(content, attributes, filename) {
|
64
|
+
Files.write(
|
65
|
+
Files.join(this.getBaseDir(), filename),
|
66
|
+
Jekyll.getFrontMatter(attributes) + content
|
67
|
+
);
|
39
68
|
}
|
40
|
-
|
41
69
|
}
|
42
70
|
|
43
|
-
export { Jekyll };
|
71
|
+
export { Jekyll };
|
package/lib/jepson.js
CHANGED
@@ -1,18 +1,17 @@
|
|
1
|
-
import { HTML
|
1
|
+
import { HTML } from "./html.js";
|
2
2
|
|
3
3
|
class Jepson {
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
/**
|
5
|
+
* @param {string} id
|
6
|
+
*/
|
7
|
+
static getEFloraLink(id) {
|
7
8
|
return HTML.getLink(
|
8
9
|
"https://ucjeps.berkeley.edu/eflora/eflora_display.php?tid=" + id,
|
9
10
|
"Jepson eFlora",
|
10
11
|
{},
|
11
|
-
|
12
|
+
true
|
12
13
|
);
|
13
|
-
|
14
14
|
}
|
15
|
-
|
16
15
|
}
|
17
16
|
|
18
|
-
export { Jepson };
|
17
|
+
export { Jepson };
|
package/lib/markdown.js
CHANGED
@@ -1,18 +1,22 @@
|
|
1
1
|
import markdownIt from "markdown-it";
|
2
|
-
import { Files } from "
|
2
|
+
import { Files } from "./files.js";
|
3
3
|
|
4
4
|
class Markdown {
|
5
|
+
static #md = new markdownIt({ xhtmlOut: true });
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
/**
|
8
|
+
* @param {string} filePath
|
9
|
+
*/
|
10
|
+
static fileToHTML(filePath) {
|
11
|
+
return this.strToHTML(Files.read(filePath));
|
10
12
|
}
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
+
/**
|
15
|
+
* @param {string} str
|
16
|
+
*/
|
17
|
+
static strToHTML(str) {
|
18
|
+
return this.#md.render(str);
|
14
19
|
}
|
15
|
-
|
16
20
|
}
|
17
21
|
|
18
|
-
export { Markdown };
|
22
|
+
export { Markdown };
|
package/lib/pagerenderer.js
CHANGED
@@ -1,84 +1,144 @@
|
|
1
|
-
import { Files, Taxa, HTML } from "@ca-plant-list/ca-plant-list";
|
2
|
-
import { TAXA_LIST_COLS } from "./taxa.js";
|
3
1
|
import { PageTaxon } from "./web/pagetaxon.js";
|
4
2
|
import { RarePlants } from "./rareplants.js";
|
5
3
|
import { BasePageRenderer } from "./basepagerenderer.js";
|
6
4
|
import { GenericPage } from "./genericpage.js";
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
import { Files } from "./files.js";
|
6
|
+
import { HTML } from "./html.js";
|
7
|
+
import { HTMLTaxon, TAXA_LIST_COLS } from "./htmltaxon.js";
|
8
|
+
|
9
|
+
const ENDANGERED_COLS = [
|
10
|
+
TAXA_LIST_COLS.SPECIES,
|
11
|
+
TAXA_LIST_COLS.COMMON_NAME,
|
12
|
+
TAXA_LIST_COLS.CESA,
|
13
|
+
TAXA_LIST_COLS.FESA,
|
14
|
+
];
|
15
|
+
const RPI_COLUMNS = [
|
16
|
+
TAXA_LIST_COLS.SPECIES_BARE,
|
17
|
+
TAXA_LIST_COLS.COMMON_NAME,
|
18
|
+
TAXA_LIST_COLS.CNPS_RANK,
|
19
|
+
];
|
10
20
|
|
11
21
|
class PageRenderer extends BasePageRenderer {
|
22
|
+
/**
|
23
|
+
* @param {string} outputDir
|
24
|
+
* @param {Config} config
|
25
|
+
* @param {Taxa} taxa
|
26
|
+
*/
|
27
|
+
static render(outputDir, config, taxa) {
|
28
|
+
super.renderBasePages(outputDir, taxa);
|
12
29
|
|
13
|
-
|
14
|
-
|
15
|
-
super.render( outputDir, taxa );
|
16
|
-
|
17
|
-
this.renderLists( outputDir, config, taxa );
|
30
|
+
this.renderLists(outputDir, config, taxa);
|
18
31
|
|
19
32
|
const taxonList = taxa.getTaxonList();
|
20
|
-
for (
|
21
|
-
new PageTaxon(
|
33
|
+
for (const taxon of taxonList) {
|
34
|
+
new PageTaxon(outputDir, config, taxon).render();
|
22
35
|
}
|
23
|
-
|
24
36
|
}
|
25
37
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
38
|
+
/**
|
39
|
+
* @param {string} outputDir
|
40
|
+
* @param {Config} config
|
41
|
+
* @param {Taxa} taxa
|
42
|
+
*/
|
43
|
+
static renderLists(outputDir, config, taxa) {
|
44
|
+
/**
|
45
|
+
* @param {ListInfo[]} listInfo
|
46
|
+
* @param {Object<string,string>} attributes
|
47
|
+
* @param {TaxaCol[]} [columns]
|
48
|
+
* @returns {string}
|
49
|
+
*/
|
50
|
+
function getListArray(listInfo, attributes = {}, columns) {
|
30
51
|
const listArray = [];
|
31
|
-
for (
|
52
|
+
for (const list of listInfo) {
|
32
53
|
const listTaxa = [];
|
33
54
|
const calfloraTaxa = [];
|
34
55
|
const iNatTaxa = [];
|
35
|
-
for (
|
36
|
-
if (
|
37
|
-
listTaxa.push(
|
38
|
-
calfloraTaxa.push(
|
39
|
-
iNatTaxa.push(
|
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());
|
40
61
|
}
|
41
62
|
}
|
42
63
|
|
43
|
-
if (
|
64
|
+
if (listTaxa.length === 0) {
|
44
65
|
continue;
|
45
66
|
}
|
46
67
|
|
47
|
-
Files.write(
|
48
|
-
|
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
|
+
);
|
49
76
|
|
50
77
|
const cols = columns ? columns : list.columns;
|
51
|
-
new PageTaxonList(
|
78
|
+
new PageTaxonList(outputDir, list.name, list.filename).render(
|
79
|
+
listTaxa,
|
80
|
+
cols
|
81
|
+
);
|
52
82
|
|
53
83
|
// Check for sublists.
|
54
|
-
const subListHTML = list.listInfo
|
55
|
-
|
56
|
-
|
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
|
+
);
|
57
95
|
}
|
58
96
|
|
59
|
-
return renderList(
|
97
|
+
return renderList(listArray, attributes);
|
60
98
|
}
|
61
99
|
|
62
|
-
|
63
|
-
|
100
|
+
/**
|
101
|
+
* @param {string[]} listsHTML
|
102
|
+
* @param {Object<string,string>} attributes
|
103
|
+
*/
|
104
|
+
function renderList(listsHTML, attributes = {}) {
|
105
|
+
return HTML.wrap("ul", HTML.arrayToLI(listsHTML), attributes);
|
64
106
|
}
|
65
107
|
|
66
|
-
|
67
|
-
|
68
|
-
|
108
|
+
/**
|
109
|
+
* @param {string} title
|
110
|
+
* @param {string} listsHTML
|
111
|
+
*/
|
112
|
+
function renderSection(title, listsHTML) {
|
113
|
+
let html = '<div class="section">';
|
114
|
+
html += HTML.textElement("h2", title);
|
69
115
|
html += listsHTML;
|
70
116
|
html += "</div>";
|
71
117
|
return html;
|
72
118
|
}
|
73
119
|
|
120
|
+
/** @typedef {{name:string,filename:string,include:function(Taxon):boolean,columns?:TaxaCol[],listInfo?:ListInfo[]}} ListInfo */
|
121
|
+
/** @type {{title:string,listInfo:ListInfo[]}[]} */
|
74
122
|
const sections = [
|
75
123
|
{
|
76
124
|
title: "All Species",
|
77
125
|
listInfo: [
|
78
|
-
{
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|
+
],
|
82
142
|
},
|
83
143
|
{
|
84
144
|
title: "Rare Plants",
|
@@ -86,101 +146,121 @@ class PageRenderer extends BasePageRenderer {
|
|
86
146
|
{
|
87
147
|
name: "CNPS Ranked Plants",
|
88
148
|
filename: "list_rpi",
|
89
|
-
include: (
|
149
|
+
include: (t) => t.getRPIRank() !== undefined,
|
90
150
|
columns: RPI_COLUMNS,
|
91
151
|
listInfo: [
|
92
152
|
{
|
93
|
-
name: RarePlants.getRPIRankDescription(
|
153
|
+
name: RarePlants.getRPIRankDescription("1A"),
|
94
154
|
filename: "list_rpi_1a",
|
95
|
-
include: (
|
155
|
+
include: (t) => t.getRPIRank() === "1A",
|
96
156
|
},
|
97
157
|
{
|
98
|
-
name: RarePlants.getRPIRankDescription(
|
158
|
+
name: RarePlants.getRPIRankDescription("1B"),
|
99
159
|
filename: "list_rpi_1b",
|
100
|
-
include: (
|
160
|
+
include: (t) => t.getRPIRank() === "1B",
|
101
161
|
},
|
102
162
|
{
|
103
|
-
name: RarePlants.getRPIRankDescription(
|
163
|
+
name: RarePlants.getRPIRankDescription("2A"),
|
104
164
|
filename: "list_rpi_2a",
|
105
|
-
include: (
|
165
|
+
include: (t) => t.getRPIRank() === "2A",
|
106
166
|
},
|
107
167
|
{
|
108
|
-
name: RarePlants.getRPIRankDescription(
|
168
|
+
name: RarePlants.getRPIRankDescription("2B"),
|
109
169
|
filename: "list_rpi_2b",
|
110
|
-
include: (
|
170
|
+
include: (t) => t.getRPIRank() === "2B",
|
111
171
|
},
|
112
172
|
{
|
113
|
-
name: RarePlants.getRPIRankDescription(
|
173
|
+
name: RarePlants.getRPIRankDescription("3"),
|
114
174
|
filename: "list_rpi_3",
|
115
|
-
include: (
|
175
|
+
include: (t) => t.getRPIRank() === "3",
|
116
176
|
},
|
117
177
|
{
|
118
|
-
name: RarePlants.getRPIRankDescription(
|
178
|
+
name: RarePlants.getRPIRankDescription("4"),
|
119
179
|
filename: "list_rpi_4",
|
120
|
-
include: (
|
180
|
+
include: (t) => t.getRPIRank() === "4",
|
121
181
|
},
|
122
|
-
]
|
182
|
+
],
|
123
183
|
},
|
124
184
|
{
|
125
185
|
name: "Endangered Species",
|
126
186
|
filename: "list_endangered",
|
127
|
-
include: (
|
187
|
+
include: (t) =>
|
188
|
+
t.getCESA() !== undefined ||
|
189
|
+
t.getFESA() !== undefined,
|
128
190
|
columns: ENDANGERED_COLS,
|
129
191
|
},
|
130
|
-
]
|
192
|
+
],
|
131
193
|
},
|
132
194
|
];
|
133
195
|
|
134
|
-
let html =
|
135
|
-
for (
|
196
|
+
let html = '<div class="wrapper">';
|
197
|
+
for (const section of sections) {
|
198
|
+
const listHTML = getListArray(section.listInfo);
|
136
199
|
|
137
|
-
|
138
|
-
|
139
|
-
if ( listHTML.length > 0 ) {
|
140
|
-
html += renderSection( section.title, listHTML );
|
200
|
+
if (listHTML.length > 0) {
|
201
|
+
html += renderSection(section.title, listHTML);
|
141
202
|
}
|
142
|
-
|
143
203
|
}
|
144
|
-
html += renderSection(
|
204
|
+
html += renderSection(
|
205
|
+
"Taxonomy",
|
206
|
+
renderList([HTML.getLink("./list_families.html", "Plant Families")])
|
207
|
+
);
|
145
208
|
|
146
209
|
html += "</div>";
|
147
210
|
|
148
211
|
// Write lists to includes directory so it can be inserted into pages.
|
149
|
-
Files.write(
|
150
|
-
|
212
|
+
Files.write(outputDir + "/_includes/plantlists.html", html);
|
151
213
|
}
|
152
|
-
|
153
214
|
}
|
154
215
|
|
155
216
|
class PageTaxonList extends GenericPage {
|
156
|
-
|
157
|
-
|
158
|
-
|
217
|
+
/**
|
218
|
+
* @param {string} outputDir
|
219
|
+
* @param {string} title
|
220
|
+
* @param {string} baseName
|
221
|
+
*/
|
222
|
+
constructor(outputDir, title, baseName) {
|
223
|
+
super(outputDir, title, baseName);
|
159
224
|
}
|
160
225
|
|
161
|
-
|
162
|
-
|
226
|
+
/**
|
227
|
+
*
|
228
|
+
* @param {Taxon[]} taxa
|
229
|
+
* @param {TaxaCol[]|undefined} columns
|
230
|
+
*/
|
231
|
+
render(taxa, columns) {
|
163
232
|
let html = this.getDefaultIntro();
|
164
233
|
|
165
|
-
html +=
|
234
|
+
html += '<div class="wrapper">';
|
166
235
|
|
167
|
-
html +=
|
168
|
-
html +=
|
236
|
+
html += '<div class="section">';
|
237
|
+
html += HTMLTaxon.getTaxaTable(taxa, columns);
|
169
238
|
html += "</div>";
|
170
239
|
|
171
|
-
html +=
|
172
|
-
html += HTML.textElement(
|
240
|
+
html += '<div class="section">';
|
241
|
+
html += HTML.textElement("h2", "Download");
|
173
242
|
html += "<ul>";
|
174
|
-
html +=
|
175
|
-
|
243
|
+
html +=
|
244
|
+
"<li>" +
|
245
|
+
HTML.getLink(
|
246
|
+
"./calflora_" + this.getBaseFileName() + ".txt",
|
247
|
+
"Calflora List"
|
248
|
+
) +
|
249
|
+
"</li>";
|
250
|
+
html +=
|
251
|
+
"<li>" +
|
252
|
+
HTML.getLink(
|
253
|
+
"./inat_" + this.getBaseFileName() + ".txt",
|
254
|
+
"iNaturalist List"
|
255
|
+
) +
|
256
|
+
"</li>";
|
176
257
|
html += "</ul>";
|
177
258
|
html += "</div>";
|
178
259
|
|
179
260
|
html += "</div>";
|
180
261
|
|
181
|
-
this.writeFile(
|
182
|
-
|
262
|
+
this.writeFile(html);
|
183
263
|
}
|
184
264
|
}
|
185
265
|
|
186
|
-
export { PageRenderer };
|
266
|
+
export { PageRenderer };
|
package/lib/plants/glossary.js
CHANGED
@@ -1,38 +1,39 @@
|
|
1
|
-
import { Config
|
1
|
+
import { Config } from "../config.js";
|
2
|
+
import { Files } from "../files.js";
|
2
3
|
|
3
4
|
class Glossary {
|
4
|
-
|
5
5
|
#srcPath;
|
6
|
+
/** @type {GlossaryEntry[]} */
|
6
7
|
#srcEntries = [];
|
7
8
|
|
8
9
|
constructor() {
|
9
|
-
|
10
10
|
this.#srcPath = Config.getPackageDir() + "/data/glossary";
|
11
11
|
|
12
12
|
// Find all entries in the glossary directory.
|
13
|
-
const entries = Files.getDirEntries(
|
14
|
-
for (
|
15
|
-
this.#srcEntries.push(
|
13
|
+
const entries = Files.getDirEntries(this.#srcPath).sort();
|
14
|
+
for (const entry of entries) {
|
15
|
+
this.#srcEntries.push(new GlossaryEntry(this.#srcPath, entry));
|
16
16
|
}
|
17
|
-
|
18
17
|
}
|
19
18
|
|
20
19
|
getEntries() {
|
21
20
|
return this.#srcEntries;
|
22
21
|
}
|
23
|
-
|
24
22
|
}
|
25
23
|
|
26
24
|
class GlossaryEntry {
|
27
|
-
|
28
25
|
#srcPath;
|
29
26
|
#fileName;
|
30
27
|
#term;
|
31
28
|
|
32
|
-
|
29
|
+
/**
|
30
|
+
* @param {string} srcPath
|
31
|
+
* @param {string} fileName
|
32
|
+
*/
|
33
|
+
constructor(srcPath, fileName) {
|
33
34
|
this.#srcPath = srcPath;
|
34
35
|
this.#fileName = fileName;
|
35
|
-
this.#term = fileName.split(
|
36
|
+
this.#term = fileName.split(".")[0];
|
36
37
|
}
|
37
38
|
|
38
39
|
getHTMLFileName() {
|
@@ -40,13 +41,12 @@ class GlossaryEntry {
|
|
40
41
|
}
|
41
42
|
|
42
43
|
getMarkdown() {
|
43
|
-
return Files.read(
|
44
|
+
return Files.read(this.#srcPath + "/" + this.#fileName);
|
44
45
|
}
|
45
46
|
|
46
47
|
getTermName() {
|
47
48
|
return this.#term;
|
48
49
|
}
|
49
|
-
|
50
50
|
}
|
51
51
|
|
52
|
-
export { Glossary };
|
52
|
+
export { Glossary };
|
package/lib/program.js
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
import { Command } from "commander";
|
2
|
+
import { Files } from "./files.js";
|
3
|
+
import { CSV } from "./csv.js";
|
4
|
+
|
5
|
+
class Program {
|
6
|
+
/**
|
7
|
+
* @param {string} dataDir
|
8
|
+
*/
|
9
|
+
static getIncludeList(dataDir) {
|
10
|
+
// Read inclusion list.
|
11
|
+
const includeFileName = "taxa_include.csv";
|
12
|
+
const includeFilePath = dataDir + "/" + includeFileName;
|
13
|
+
if (!Files.exists(includeFilePath)) {
|
14
|
+
console.log(includeFilePath + " not found; loading all taxa");
|
15
|
+
return true;
|
16
|
+
}
|
17
|
+
const includeCSV = CSV.parseFile(dataDir, includeFileName);
|
18
|
+
/** @type {Object<string,TaxonData>} */
|
19
|
+
const include = {};
|
20
|
+
for (const row of includeCSV) {
|
21
|
+
include[row["taxon_name"]] = row;
|
22
|
+
}
|
23
|
+
return include;
|
24
|
+
}
|
25
|
+
|
26
|
+
static getProgram() {
|
27
|
+
const program = new Command();
|
28
|
+
program
|
29
|
+
.option(
|
30
|
+
"-d, --datadir <dir>",
|
31
|
+
"The directory containing plant data.",
|
32
|
+
"./data"
|
33
|
+
)
|
34
|
+
.option(
|
35
|
+
"-f, --show-flower-errors",
|
36
|
+
"Include missing flower color/flowering time in the error log when loading taxa."
|
37
|
+
)
|
38
|
+
.option(
|
39
|
+
"-o, --outputdir <dir>",
|
40
|
+
"The directory to which output should be written.",
|
41
|
+
"./output"
|
42
|
+
);
|
43
|
+
return program;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
export { Program };
|