@ca-plant-list/ca-plant-list 0.4.26 → 0.4.28
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 +0 -27
- package/data/genera.json +52 -28
- package/data/glossary/anther.md +3 -0
- package/data/glossary/filament.md +3 -0
- package/data/glossary/stamen.md +3 -0
- package/data/illustrations/inkscape/stamen.svg +132 -0
- package/data/inatobsphotos.csv +0 -5
- package/data/inattaxonphotos.csv +69 -64
- package/data/synonyms.csv +155 -164
- package/data/taxa.csv +38 -38
- package/data/text/Dichelostemma-congestum.md +1 -0
- package/data/text/Dipterostemon-capitatus-subsp-capitatus.md +1 -0
- package/generators/eleventy/layouts/h1.njk +6 -0
- package/generators/eleventy/layouts/html.njk +55 -0
- package/lib/basepagerenderer.js +35 -15
- package/lib/config.js +5 -3
- package/lib/ebook/ebookpage.js +1 -4
- package/lib/ebook/ebooksitegenerator.js +4 -12
- package/lib/ebook/glossarypages.js +1 -3
- package/lib/ebook/plantbook.js +1 -1
- package/lib/files.js +1 -0
- package/lib/htmltaxon.js +8 -19
- package/lib/index.d.ts +20 -8
- package/lib/index.js +4 -2
- package/lib/jekyll.js +40 -59
- package/lib/markdown.js +3 -5
- package/lib/sitegenerator.js +68 -12
- package/lib/taxonomy/taxon.js +5 -1
- package/lib/tools/cch2.js +37 -18
- package/lib/tools/jepsonfamilies.js +1 -1
- package/lib/types.js +4 -0
- package/lib/utils/eleventyGenerator.js +82 -0
- package/lib/utils/htmlFragments.js +19 -0
- package/lib/web/glossarypages.js +6 -10
- package/lib/web/pageFamily.js +14 -14
- package/lib/web/pageGeneric.js +78 -0
- package/lib/web/{pagetaxon.js → pageTaxon.js} +4 -4
- package/lib/web/pageTaxonList.js +53 -0
- package/lib/{pagerenderer.js → web/renderAllPages.js} +38 -80
- package/package.json +12 -10
- package/scripts/build-site.js +20 -52
- package/scripts/cpl-photos.js +61 -24
- package/scripts/cpl-tools.js +4 -1
- package/static/assets/js/nameSearchData.js +2 -0
- package/{jekyll → static}/assets/js/name_search.js +12 -14
- package/static/name_search.html +15 -0
- package/jekyll/_includes/glossary.html +0 -0
- package/jekyll/name_search.html +0 -17
- package/lib/genericpage.js +0 -88
- /package/{jekyll → generators}/_includes/analytics.html +0 -0
- /package/{jekyll → generators}/_includes/menu_extra.html +0 -0
- /package/{jekyll → generators/jekyll}/_config.yml +0 -0
- /package/{jekyll → generators/jekyll}/_layouts/default.html +0 -0
- /package/{jekyll → generators/jekyll}/_layouts/html.html +0 -0
- /package/{jekyll → static}/assets/css/main.css +0 -0
- /package/{jekyll → static}/assets/js/ui.js +0 -0
- /package/{jekyll → static}/assets/js/utils.js +0 -0
- /package/{jekyll → static}/index.md +0 -0
package/scripts/cpl-photos.js
CHANGED
@@ -9,6 +9,7 @@ import { existsSync } from "fs";
|
|
9
9
|
import { CSV } from "../lib/csv.js";
|
10
10
|
|
11
11
|
const PHOTO_FILE_NAME = "inattaxonphotos.csv";
|
12
|
+
const PHOTO_FILE_PATH = `./data/${PHOTO_FILE_NAME}`;
|
12
13
|
|
13
14
|
const OPT_LOADER = "loader";
|
14
15
|
|
@@ -58,27 +59,7 @@ async function addMissingPhotos(options) {
|
|
58
59
|
errorLog.write();
|
59
60
|
|
60
61
|
// Write updated photo file.
|
61
|
-
|
62
|
-
/** @type {string[][]} */
|
63
|
-
const data = [];
|
64
|
-
for (const taxonName of [...currentTaxaPhotos.keys()].sort()) {
|
65
|
-
// @ts-ignore
|
66
|
-
for (const photo of currentTaxaPhotos.get(taxonName)) {
|
67
|
-
data.push([
|
68
|
-
taxonName,
|
69
|
-
photo.id,
|
70
|
-
photo.ext,
|
71
|
-
photo.licenseCode,
|
72
|
-
photo.attrName ?? "",
|
73
|
-
]);
|
74
|
-
}
|
75
|
-
}
|
76
|
-
|
77
|
-
CSV.writeFileArray(
|
78
|
-
`${options.outputdir}/${PHOTO_FILE_NAME}`,
|
79
|
-
data,
|
80
|
-
headers,
|
81
|
-
);
|
62
|
+
writePhotos(currentTaxaPhotos);
|
82
63
|
}
|
83
64
|
|
84
65
|
/**
|
@@ -128,12 +109,39 @@ async function getTaxa(options) {
|
|
128
109
|
return taxa;
|
129
110
|
}
|
130
111
|
|
112
|
+
/**
|
113
|
+
* @param {{outputdir:string,update:boolean}} options
|
114
|
+
*/
|
115
|
+
async function prune(options) {
|
116
|
+
const taxa = await getTaxa(options);
|
117
|
+
const errorLog = new ErrorLog(options.outputdir + "/log.tsv", true);
|
118
|
+
const currentTaxaPhotos = readPhotos();
|
119
|
+
|
120
|
+
const invalidNames = new Set();
|
121
|
+
|
122
|
+
for (const name of currentTaxaPhotos.keys()) {
|
123
|
+
const taxon = taxa.getTaxon(name);
|
124
|
+
if (!taxon) {
|
125
|
+
errorLog.log(name, `is in ${PHOTO_FILE_NAME} but not in taxa list`);
|
126
|
+
invalidNames.add(name);
|
127
|
+
}
|
128
|
+
}
|
129
|
+
|
130
|
+
if (options.update) {
|
131
|
+
for (const name of invalidNames) {
|
132
|
+
currentTaxaPhotos.delete(name);
|
133
|
+
}
|
134
|
+
writePhotos(currentTaxaPhotos);
|
135
|
+
}
|
136
|
+
|
137
|
+
errorLog.write();
|
138
|
+
}
|
139
|
+
|
131
140
|
/**
|
132
141
|
* @returns {Map<string,import("../lib/utils/inat-tools.js").InatPhotoInfo[]>}
|
133
142
|
*/
|
134
143
|
function readPhotos() {
|
135
|
-
|
136
|
-
if (!existsSync(photosFileName)) {
|
144
|
+
if (!existsSync(PHOTO_FILE_PATH)) {
|
137
145
|
return new Map();
|
138
146
|
}
|
139
147
|
|
@@ -142,7 +150,7 @@ function readPhotos() {
|
|
142
150
|
|
143
151
|
/** @type {import("../lib/utils/inat-tools.js").InatCsvPhoto[]} */
|
144
152
|
// @ts-ignore
|
145
|
-
const csvPhotos = CSV.readFile(
|
153
|
+
const csvPhotos = CSV.readFile(PHOTO_FILE_PATH);
|
146
154
|
for (const csvPhoto of csvPhotos) {
|
147
155
|
const taxonName = csvPhoto.name;
|
148
156
|
let photos = taxonPhotos.get(taxonName);
|
@@ -161,6 +169,30 @@ function readPhotos() {
|
|
161
169
|
return taxonPhotos;
|
162
170
|
}
|
163
171
|
|
172
|
+
/**
|
173
|
+
* @param {Map<string,import("../lib/utils/inat-tools.js").InatPhotoInfo[]>} currentTaxaPhotos
|
174
|
+
*/
|
175
|
+
function writePhotos(currentTaxaPhotos) {
|
176
|
+
// Write updated photo file.
|
177
|
+
const headers = ["name", "id", "ext", "licenseCode", "attrName"];
|
178
|
+
/** @type {string[][]} */
|
179
|
+
const data = [];
|
180
|
+
for (const taxonName of [...currentTaxaPhotos.keys()].sort()) {
|
181
|
+
// @ts-ignore - should always be defined at this point
|
182
|
+
for (const photo of currentTaxaPhotos.get(taxonName)) {
|
183
|
+
data.push([
|
184
|
+
taxonName,
|
185
|
+
photo.id,
|
186
|
+
photo.ext,
|
187
|
+
photo.licenseCode,
|
188
|
+
photo.attrName ?? "",
|
189
|
+
]);
|
190
|
+
}
|
191
|
+
}
|
192
|
+
|
193
|
+
CSV.writeFileArray(PHOTO_FILE_PATH, data, headers);
|
194
|
+
}
|
195
|
+
|
164
196
|
const program = Program.getProgram();
|
165
197
|
program
|
166
198
|
.command("checkmissing")
|
@@ -176,9 +208,14 @@ if (process.env.npm_package_name === "@ca-plant-list/ca-plant-list") {
|
|
176
208
|
.command("addmissing")
|
177
209
|
.description("Add photos to taxa with fewer than the maximum")
|
178
210
|
.action(() => addMissingPhotos(program.opts()));
|
211
|
+
program
|
212
|
+
.command("prune")
|
213
|
+
.description("Remove photos without valid taxon names")
|
214
|
+
.action(() => prune(program.opts()));
|
179
215
|
}
|
180
216
|
program.option(
|
181
217
|
"--loader <path>",
|
182
218
|
"The path (relative to the current directory) of the JavaScript file containing the TaxaLoader class. If not provided, the default TaxaLoader will be used.",
|
183
219
|
);
|
220
|
+
program.option("--update", "Update the file if possible.");
|
184
221
|
await program.parseAsync();
|
package/scripts/cpl-tools.js
CHANGED
@@ -58,10 +58,13 @@ async function build(program, options) {
|
|
58
58
|
|
59
59
|
const exceptions = new Exceptions(options.datadir);
|
60
60
|
const config = new Config(options.datadir);
|
61
|
-
const taxa = await Taxa.loadTaxa(options);
|
62
61
|
|
63
62
|
const errorLog = new ErrorLog(options.outputdir + "/log.tsv", true);
|
64
63
|
for (const tool of tools) {
|
64
|
+
const taxa =
|
65
|
+
tool === TOOLS.JEPSON_FAM
|
66
|
+
? undefined
|
67
|
+
: await Taxa.loadTaxa(options);
|
65
68
|
switch (tool) {
|
66
69
|
case TOOLS.CALFLORA:
|
67
70
|
await Calflora.analyze(
|
@@ -1,8 +1,8 @@
|
|
1
|
+
import { NAMES } from "./nameSearchData.js";
|
1
2
|
import { Utils } from "./utils.js";
|
2
3
|
|
3
4
|
/**
|
4
|
-
* @typedef {
|
5
|
-
* @typedef {{raw:RawSearchData,searchSci:string,searchCommon?:string,synonyms?:string[]}} SearchData
|
5
|
+
* @typedef {{raw:import("../../../lib/types.js").NameSearchData,searchSci:string,searchCommon?:string,synonyms?:string[]}} SearchData
|
6
6
|
*/
|
7
7
|
|
8
8
|
const MIN_LEN = 2;
|
@@ -52,9 +52,9 @@ class Search {
|
|
52
52
|
// Include any matching synonyms.
|
53
53
|
for (const index of syns) {
|
54
54
|
matches.push([
|
55
|
-
taxon.raw
|
56
|
-
taxon.raw
|
57
|
-
taxon.raw
|
55
|
+
taxon.raw.t,
|
56
|
+
taxon.raw.c,
|
57
|
+
taxon.raw.s ? taxon.raw.s[index] : undefined,
|
58
58
|
]);
|
59
59
|
}
|
60
60
|
} else {
|
@@ -62,7 +62,7 @@ class Search {
|
|
62
62
|
const namesMatch =
|
63
63
|
name.includes(value) || (cn && cn.includes(value));
|
64
64
|
if (namesMatch) {
|
65
|
-
matches.push([taxon.raw
|
65
|
+
matches.push([taxon.raw.t, taxon.raw.c]);
|
66
66
|
}
|
67
67
|
}
|
68
68
|
}
|
@@ -146,23 +146,21 @@ class Search {
|
|
146
146
|
/** @type {SearchData[]} */
|
147
147
|
const searchData = [];
|
148
148
|
|
149
|
-
/** @type {
|
150
|
-
// @ts-ignore
|
151
|
-
// eslint-disable-next-line no-undef
|
149
|
+
/** @type {import("../../../lib/types.js").NameSearchData[]} */
|
152
150
|
const names = NAMES;
|
153
151
|
|
154
152
|
for (const taxon of names) {
|
155
153
|
/** @type {SearchData} */
|
156
154
|
const taxonData = {
|
157
155
|
raw: taxon,
|
158
|
-
searchSci: this.#normalizeName(taxon
|
156
|
+
searchSci: this.#normalizeName(taxon.t),
|
159
157
|
};
|
160
|
-
if (taxon
|
161
|
-
taxonData.searchCommon = taxon
|
158
|
+
if (taxon.c) {
|
159
|
+
taxonData.searchCommon = taxon.c.toLowerCase();
|
162
160
|
}
|
163
|
-
if (taxon
|
161
|
+
if (taxon.s) {
|
164
162
|
const syns = [];
|
165
|
-
for (const syn of taxon
|
163
|
+
for (const syn of taxon.s) {
|
166
164
|
syns.push(this.#normalizeName(syn));
|
167
165
|
}
|
168
166
|
taxonData.synonyms = syns;
|
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
title: Name Search
|
3
|
+
js: name_search.js
|
4
|
+
---
|
5
|
+
|
6
|
+
<form id="search_form">
|
7
|
+
<input type="text" id="name" />
|
8
|
+
<label for="name"
|
9
|
+
>Search for scientific name, common name, or synonym.</label
|
10
|
+
>
|
11
|
+
</form>
|
12
|
+
|
13
|
+
<div class="section" id="message"></div>
|
14
|
+
|
15
|
+
<table id="results"></table>
|
File without changes
|
package/jekyll/name_search.html
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
---
|
2
|
-
title: Name Search
|
3
|
-
js: name_search.js
|
4
|
-
---
|
5
|
-
|
6
|
-
<script>
|
7
|
-
const NAMES = {% include names.json %};
|
8
|
-
</script>
|
9
|
-
|
10
|
-
<form id="search_form">
|
11
|
-
<input type="text" id="name">
|
12
|
-
<label for="name">Search for scientific name, common name, or synonym.</label>
|
13
|
-
</form>
|
14
|
-
|
15
|
-
<div class="section" id="message"></div>
|
16
|
-
|
17
|
-
<table id="results"></table>
|
package/lib/genericpage.js
DELETED
@@ -1,88 +0,0 @@
|
|
1
|
-
import { Config } from "./config.js";
|
2
|
-
import { Files } from "./files.js";
|
3
|
-
import { HTML } from "./html.js";
|
4
|
-
import { Jekyll } from "./jekyll.js";
|
5
|
-
import { Markdown } from "./markdown.js";
|
6
|
-
|
7
|
-
class GenericPage {
|
8
|
-
#outputDir;
|
9
|
-
#title;
|
10
|
-
#baseFileName;
|
11
|
-
#js;
|
12
|
-
|
13
|
-
/**
|
14
|
-
* @param {string} outputDir
|
15
|
-
* @param {string} title
|
16
|
-
* @param {string} baseFileName
|
17
|
-
* @param {string} [js]
|
18
|
-
*/
|
19
|
-
constructor(outputDir, title, baseFileName, js) {
|
20
|
-
this.#outputDir = outputDir;
|
21
|
-
this.#title = title;
|
22
|
-
this.#baseFileName = baseFileName;
|
23
|
-
this.#js = js;
|
24
|
-
}
|
25
|
-
|
26
|
-
getBaseFileName() {
|
27
|
-
return this.#baseFileName;
|
28
|
-
}
|
29
|
-
|
30
|
-
getDefaultIntro() {
|
31
|
-
let html = this.getFrontMatter();
|
32
|
-
return html + this.getMarkdown();
|
33
|
-
}
|
34
|
-
|
35
|
-
getFrontMatter() {
|
36
|
-
return (
|
37
|
-
"---\n" +
|
38
|
-
'title: "' +
|
39
|
-
this.#title +
|
40
|
-
'"\n' +
|
41
|
-
(this.#js ? "js: " + this.#js + "\n" : "") +
|
42
|
-
"---\n"
|
43
|
-
);
|
44
|
-
}
|
45
|
-
|
46
|
-
getMarkdown() {
|
47
|
-
// Include site-specific markdown.
|
48
|
-
let html = this.#getMarkdown("intros");
|
49
|
-
|
50
|
-
// Include package markdown.
|
51
|
-
const mdPath =
|
52
|
-
Config.getPackageDir() + "/data/text/" + this.#baseFileName + ".md";
|
53
|
-
const markdownHTML = Markdown.fileToHTML(mdPath);
|
54
|
-
if (markdownHTML) {
|
55
|
-
html += HTML.wrap("div", markdownHTML, { class: "section" });
|
56
|
-
}
|
57
|
-
|
58
|
-
return html;
|
59
|
-
}
|
60
|
-
|
61
|
-
/**
|
62
|
-
* @param {string} path
|
63
|
-
*/
|
64
|
-
#getMarkdown(path) {
|
65
|
-
const textPath = path + "/" + this.#baseFileName + ".md";
|
66
|
-
if (!Jekyll.hasInclude(this.#outputDir, textPath)) {
|
67
|
-
return "";
|
68
|
-
}
|
69
|
-
return HTML.wrap("div", Jekyll.include(textPath), { class: "section" });
|
70
|
-
}
|
71
|
-
|
72
|
-
getOutputDir() {
|
73
|
-
return this.#outputDir;
|
74
|
-
}
|
75
|
-
|
76
|
-
getTitle() {
|
77
|
-
return this.#title;
|
78
|
-
}
|
79
|
-
|
80
|
-
/**
|
81
|
-
* @param {string} html
|
82
|
-
*/
|
83
|
-
writeFile(html) {
|
84
|
-
Files.write(this.#outputDir + "/" + this.#baseFileName + ".html", html);
|
85
|
-
}
|
86
|
-
}
|
87
|
-
|
88
|
-
export { GenericPage };
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|