@ca-plant-list/ca-plant-list 0.4.27 → 0.4.29

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.
Files changed (36) hide show
  1. package/data/exceptions.json +0 -31
  2. package/data/genera.json +52 -28
  3. package/data/glossary/anther.md +3 -0
  4. package/data/glossary/filament.md +3 -0
  5. package/data/glossary/stamen.md +3 -0
  6. package/data/illustrations/inkscape/stamen.svg +132 -0
  7. package/data/inatobsphotos.csv +0 -5
  8. package/data/inattaxonphotos.csv +80 -64
  9. package/data/synonyms.csv +157 -168
  10. package/data/taxa.csv +55 -56
  11. package/data/text/Bowlesia-incana.md +1 -0
  12. package/data/text/Castilleja-attenuata.md +1 -0
  13. package/data/text/Castilleja-densiflora-subsp-densiflora.md +1 -0
  14. package/data/text/Castilleja-exserta-subsp-exserta.md +1 -0
  15. package/data/text/Castilleja-exserta-subsp-latifolia.md +1 -0
  16. package/data/text/Dichelostemma-congestum.md +1 -0
  17. package/data/text/Dipterostemon-capitatus-subsp-capitatus.md +1 -0
  18. package/data/text/Lathyrus-vestitus-var-vestitus.md +1 -1
  19. package/data/text/Psilocarphus-brevissimus-var-brevissimus.md +1 -0
  20. package/data/text/Psilocarphus-chilensis.md +1 -0
  21. package/data/text/Psilocarphus-oregonus.md +1 -0
  22. package/data/text/Psilocarphus-tenellus.md +1 -0
  23. package/data/text/Ribes-californicum-var-californicum.md +1 -1
  24. package/data/text/Ribes-menziesii-var-menziesii.md +1 -1
  25. package/data/text/Vicia-americana-subsp-americana.md +1 -1
  26. package/data/text/Vicia-benghalensis.md +1 -0
  27. package/data/text/Vicia-disperma.md +1 -0
  28. package/data/text/Vicia-gigantea.md +1 -0
  29. package/data/text/Vicia-sativa-subsp-nigra.md +1 -0
  30. package/lib/flowercolor.js +1 -3
  31. package/lib/taxonomy/taxon.js +5 -1
  32. package/lib/tools/cch2.js +37 -18
  33. package/lib/tools/jepsonfamilies.js +1 -1
  34. package/package.json +1 -1
  35. package/scripts/cpl-photos.js +61 -24
  36. package/scripts/cpl-tools.js +4 -1
@@ -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
- const headers = ["name", "id", "ext", "licenseCode", "attrName"];
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
- const photosFileName = `./data/${PHOTO_FILE_NAME}`;
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(photosFileName);
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();
@@ -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(