@ca-plant-list/ca-plant-list 0.3.2 → 0.3.3

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 (54) hide show
  1. package/.vscode/settings.json +4 -2
  2. package/data/exceptions.json +0 -3
  3. package/data/glossary/ovary.md +3 -0
  4. package/data/glossary/pistil.md +3 -0
  5. package/data/glossary/stigma.md +3 -0
  6. package/data/glossary/style.md +3 -0
  7. package/data/illustrations/inkscape/pistil.svg +156 -0
  8. package/data/synonyms.csv +8 -2
  9. package/data/taxa.csv +54 -52
  10. package/data/text/Ceanothus-cuneatus-var-cuneatus.md +1 -0
  11. package/data/text/Ceanothus-leucodermis.md +1 -0
  12. package/data/text/Delphinium-californicum-subsp-californicum.md +1 -0
  13. package/data/text/Delphinium-decorum-subsp-decorum.md +1 -0
  14. package/data/text/Delphinium-hesperium-subsp-hesperium.md +1 -0
  15. package/data/text/Delphinium-patens-subsp-patens.md +1 -0
  16. package/data/text/Galium-andrewsii-subsp-gatense.md +1 -0
  17. package/data/text/Helianthella-californica-var-californica.md +1 -0
  18. package/data/text/Helianthella-castanea.md +1 -0
  19. package/data/text/Iris-macrosiphon.md +1 -0
  20. package/data/text/Lasthenia-californica-subsp-californica.md +1 -0
  21. package/data/text/Lasthenia-gracilis.md +1 -0
  22. package/data/text/Lithophragma-affine.md +1 -1
  23. package/data/text/Lithophragma-parviflorum-var-parviflorum.md +1 -1
  24. package/data/text/Lomatium-californicum.md +0 -0
  25. package/data/text/Lomatium-dasycarpum-subsp-dasycarpum.md +1 -0
  26. package/data/text/Lomatium-utriculatum.md +1 -0
  27. package/data/text/Nemophila-heterophylla.md +1 -0
  28. package/data/text/Nemophila-parviflora-var-parviflora.md +1 -0
  29. package/data/text/Plectritis-ciliosa.md +1 -0
  30. package/data/text/Plectritis-macrocera.md +1 -0
  31. package/data/text/Primula-clevelandii-var-patula.md +1 -0
  32. package/data/text/Primula-hendersonii.md +1 -0
  33. package/data/text/Sidalcea-diploscypha.md +1 -0
  34. package/data/text/Thysanocarpus-curvipes.md +1 -0
  35. package/data/text/Thysanocarpus-laciniatus.md +1 -0
  36. package/data/text/Viola-douglasii.md +1 -0
  37. package/data/text/Viola-pedunculata.md +1 -0
  38. package/data/text/Viola-purpurea-subsp-quercetorum.md +1 -0
  39. package/ebook/css/main.css +5 -0
  40. package/lib/basepagerenderer.js +30 -28
  41. package/lib/dateutils.js +36 -16
  42. package/lib/ebook/pages/taxonpage.js +63 -36
  43. package/lib/errorlog.js +16 -11
  44. package/lib/families.js +109 -71
  45. package/lib/files.js +103 -45
  46. package/lib/generictaxaloader.js +15 -7
  47. package/lib/index.js +38 -3
  48. package/lib/taxa.js +164 -87
  49. package/lib/taxaloader.js +28 -15
  50. package/lib/taxaprocessor.js +6 -8
  51. package/lib/taxon.js +109 -56
  52. package/package.json +4 -6
  53. package/scripts/build-ebook.js +30 -25
  54. package/lib/index.d.ts +0 -345
package/lib/taxa.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { Config } from "./config.js";
2
- import { Taxon } from "./taxon.js";
3
2
  import { HTML } from "./html.js";
4
3
  import { CSV } from "./csv.js";
5
4
  import { RarePlants } from "./rareplants.js";
5
+ import { ErrorLog, Taxon } from "./index.js";
6
6
 
7
7
  const FLOWER_COLORS = [
8
8
  { name: "white", color: "white" },
@@ -14,50 +14,65 @@ const FLOWER_COLORS = [
14
14
  { name: "purple", color: "purple" },
15
15
  ];
16
16
 
17
+ /**
18
+ * @type {Object.<string,import("./index.js").TaxaCol>}
19
+ */
17
20
  const TAXA_LIST_COLS = {
18
21
  CESA: {
19
22
  title: "California",
20
- data: ( t ) => RarePlants.getCESADescription( t.getCESA() )
23
+ data: (t) => RarePlants.getCESADescription(t.getCESA()),
21
24
  },
22
25
  COMMON_NAME: {
23
26
  title: "Common Name",
24
- data: ( t ) => t.getCommonNames().join( ", " )
27
+ data: (t) => t.getCommonNames().join(", "),
25
28
  },
26
29
  CNPS_RANK: {
27
30
  title: "CNPS Rank",
28
- data: ( t ) => HTML.getToolTip( HTML.textElement( "span", t.getRPIRankAndThreat() ), t.getRPIRankAndThreatTooltip() )
31
+ data: (t) =>
32
+ HTML.getToolTip(
33
+ HTML.textElement("span", t.getRPIRankAndThreat()),
34
+ t.getRPIRankAndThreatTooltip()
35
+ ),
29
36
  },
30
37
  FESA: {
31
38
  title: "Federal",
32
- data: ( t ) => RarePlants.getFESADescription( t.getFESA() )
39
+ data: (t) => RarePlants.getFESADescription(t.getFESA()),
33
40
  },
34
41
  SPECIES: {
35
42
  title: "Species",
36
- data: ( t ) => t.getHTMLLink( true, true )
43
+ data: (t) => t.getHTMLLink(true, true),
37
44
  },
38
45
  SPECIES_BARE: {
39
46
  title: "Species",
40
- data: ( t ) => t.getHTMLLink( true, false )
47
+ data: (t) => t.getHTMLLink(true, false),
41
48
  },
42
49
  };
43
50
 
44
- const DEFAULT_COLUMNS = [ TAXA_LIST_COLS.SPECIES, TAXA_LIST_COLS.COMMON_NAME ];
51
+ const DEFAULT_COLUMNS = [TAXA_LIST_COLS.SPECIES, TAXA_LIST_COLS.COMMON_NAME];
45
52
 
46
53
  class FlowerColor {
47
-
48
54
  #color;
55
+ /** @type {Taxon[]} */
49
56
  #taxa = [];
50
57
 
51
- constructor( color ) {
58
+ /**
59
+ * @param {string} color
60
+ */
61
+ constructor(color) {
52
62
  this.#color = color;
53
63
  }
54
64
 
55
- addTaxon( taxon ) {
56
- this.#taxa.push( taxon );
65
+ /**
66
+ * @param {Taxon} taxon
67
+ */
68
+ addTaxon(taxon) {
69
+ this.#taxa.push(taxon);
57
70
  }
58
71
 
59
- getColorName( uc = false ) {
60
- return uc ? ( this.#color[ 0 ].toUpperCase() + this.#color.substring( 1 ) ) : this.#color;
72
+ getColorName(uc = false) {
73
+ return uc
74
+ ? this.#color[0].toUpperCase() + this.#color.substring(1)
75
+ : this.#color;
61
76
  }
62
77
 
63
78
  getFileName() {
@@ -67,67 +82,100 @@ class FlowerColor {
67
82
  getTaxa() {
68
83
  return this.#taxa;
69
84
  }
70
-
71
85
  }
72
86
 
73
87
  class Taxa {
74
-
75
88
  #errorLog;
89
+ /** @type {Object<string,Taxon>} */
76
90
  #taxa = {};
91
+ /** @type {Object<string,FlowerColor>} */
77
92
  #flower_colors = {};
78
93
  #sortedTaxa;
79
94
  #synonyms = new Set();
80
95
  #isSubset;
81
96
 
82
- constructor( inclusionList, errorLog, showFlowerErrors, taxaMeta = {}, taxonClass = Taxon, extraTaxa = [], extraSynonyms = [] ) {
83
-
84
- this.#isSubset = ( inclusionList !== true );
97
+ /**
98
+ *
99
+ * @param {*} inclusionList
100
+ * @param {ErrorLog} errorLog
101
+ * @param {*} showFlowerErrors
102
+ * @param {*} taxaMeta
103
+ * @param {*} taxonClass
104
+ * @param {*} extraTaxa
105
+ * @param {*} extraSynonyms
106
+ */
107
+ constructor(
108
+ inclusionList,
109
+ errorLog,
110
+ showFlowerErrors,
111
+ taxaMeta = {},
112
+ taxonClass = Taxon,
113
+ extraTaxa = [],
114
+ extraSynonyms = []
115
+ ) {
116
+ this.#isSubset = inclusionList !== true;
85
117
 
86
118
  this.#errorLog = errorLog;
87
119
 
88
- for ( const color of FLOWER_COLORS ) {
89
- this.#flower_colors[ color.name ] = new FlowerColor( color.name );
120
+ for (const color of FLOWER_COLORS) {
121
+ this.#flower_colors[color.name] = new FlowerColor(color.name);
90
122
  }
91
123
 
92
124
  const dataDir = Config.getPackageDir() + "/data";
93
125
 
94
- const taxaCSV = CSV.parseFile( dataDir, "taxa.csv" );
95
- this.#loadTaxa( taxaCSV, inclusionList, taxaMeta, taxonClass, showFlowerErrors );
96
- this.#loadTaxa( extraTaxa, inclusionList, taxaMeta, taxonClass, showFlowerErrors );
126
+ const taxaCSV = CSV.parseFile(dataDir, "taxa.csv");
127
+ this.#loadTaxa(
128
+ taxaCSV,
129
+ inclusionList,
130
+ taxaMeta,
131
+ taxonClass,
132
+ showFlowerErrors
133
+ );
134
+ this.#loadTaxa(
135
+ extraTaxa,
136
+ inclusionList,
137
+ taxaMeta,
138
+ taxonClass,
139
+ showFlowerErrors
140
+ );
97
141
 
98
142
  // Make sure everything in the inclusionList has been loaded.
99
- for ( const name of Object.keys( inclusionList ) ) {
100
- if ( !this.getTaxon( name ) ) {
101
- this.#errorLog.log( name, "not found in taxon list" );
143
+ for (const name of Object.keys(inclusionList)) {
144
+ if (!this.getTaxon(name)) {
145
+ this.#errorLog.log(name, "not found in taxon list");
102
146
  }
103
147
  }
104
148
 
105
- this.#sortedTaxa = Object.values( this.#taxa ).sort( ( a, b ) => a.getName().localeCompare( b.getName() ) );
106
-
107
- const synCSV = CSV.parseFile( dataDir, "synonyms.csv" );
108
- this.#loadSyns( synCSV, inclusionList );
109
- this.#loadSyns( extraSynonyms, inclusionList );
149
+ this.#sortedTaxa = Object.values(this.#taxa).sort((a, b) =>
150
+ a.getName().localeCompare(b.getName())
151
+ );
110
152
 
153
+ const synCSV = CSV.parseFile(dataDir, "synonyms.csv");
154
+ this.#loadSyns(synCSV, inclusionList);
155
+ this.#loadSyns(extraSynonyms, inclusionList);
111
156
  }
112
157
 
113
- static getHTMLTable( taxa, columns = DEFAULT_COLUMNS ) {
114
-
158
+ /**
159
+ * @param {Taxon[]} taxa
160
+ * @param {import("./index.js").TaxaCol[]} columns
161
+ */
162
+ static getHTMLTable(taxa, columns = DEFAULT_COLUMNS) {
115
163
  let html = "<table><thead>";
116
- for ( const col of columns ) {
164
+ for (const col of columns) {
117
165
  const className = col.class;
118
166
  const atts = className ? { class: className } : {};
119
- html += HTML.textElement( "th", col.title, atts );
167
+ html += HTML.textElement("th", col.title, atts);
120
168
  }
121
169
  html += "</thead>";
122
170
  html += "<tbody>";
123
171
 
124
- for ( const taxon of taxa ) {
172
+ for (const taxon of taxa) {
125
173
  html += "<tr>";
126
- for ( const col of columns ) {
127
- const data = col.data( taxon );
174
+ for (const col of columns) {
175
+ const data = col.data(taxon);
128
176
  const className = col.class;
129
177
  const atts = className ? { class: className } : {};
130
- html += HTML.wrap( "td", data, atts );
178
+ html += HTML.wrap("td", data, atts);
131
179
  }
132
180
  html += "</tr>";
133
181
  }
@@ -138,28 +186,37 @@ class Taxa {
138
186
  return html;
139
187
  }
140
188
 
141
- getFlowerColor( name ) {
142
- return this.#flower_colors[ name ];
189
+ /**
190
+ * @param {string} name
191
+ */
192
+ getFlowerColor(name) {
193
+ return this.#flower_colors[name];
143
194
  }
144
195
 
145
196
  static getFlowerColorNames() {
146
- return FLOWER_COLORS.map( ( o ) => o.name );
197
+ return FLOWER_COLORS.map((o) => o.name);
147
198
  }
148
199
 
149
200
  static getFlowerColors() {
150
201
  return FLOWER_COLORS;
151
202
  }
152
203
 
153
- getTaxon( name ) {
154
- return this.#taxa[ name ];
204
+ /**
205
+ * @param {string} name
206
+ */
207
+ getTaxon(name) {
208
+ return this.#taxa[name];
155
209
  }
156
210
 
157
211
  getTaxonList() {
158
212
  return this.#sortedTaxa;
159
213
  }
160
214
 
161
- hasSynonym( formerName ) {
162
- return this.#synonyms.has( formerName );
215
+ /**
216
+ * @param {string} formerName
217
+ */
218
+ hasSynonym(formerName) {
219
+ return this.#synonyms.has(formerName);
163
220
  }
164
221
 
165
222
  /**
@@ -170,75 +227,95 @@ class Taxa {
170
227
  return this.#isSubset;
171
228
  }
172
229
 
173
- #loadSyns( synCSV, inclusionList ) {
174
- for ( const syn of synCSV ) {
175
- const currName = syn[ "Current" ];
176
- const taxon = this.getTaxon( currName );
177
- if ( !taxon ) {
178
- if ( inclusionList === true && !syn.Type ) {
230
+ /**
231
+ * @param {*} synCSV
232
+ * @param {*} inclusionList
233
+ */
234
+ #loadSyns(synCSV, inclusionList) {
235
+ for (const syn of synCSV) {
236
+ const currName = syn["Current"];
237
+ const taxon = this.getTaxon(currName);
238
+ if (!taxon) {
239
+ if (inclusionList === true && !syn.Type) {
179
240
  // If including all taxa, note the error - the target is not defined, and this is not
180
241
  // a synonym for a non-Jepson system.
181
- console.log( "synonym target not found: " + currName );
242
+ console.log("synonym target not found: " + currName);
182
243
  }
183
244
  continue;
184
245
  }
185
- const formerName = syn[ "Former" ];
186
- this.#synonyms.add( formerName );
187
- taxon.addSynonym( formerName, syn[ "Type" ] );
246
+ const formerName = syn["Former"];
247
+ this.#synonyms.add(formerName);
248
+ taxon.addSynonym(formerName, syn["Type"]);
188
249
  }
189
250
  }
190
251
 
191
- #loadTaxa( taxaCSV, inclusionList, taxaMeta, taxonClass, showFlowerErrors ) {
192
- for ( const row of taxaCSV ) {
193
-
194
- const name = row[ "taxon_name" ];
252
+ /**
253
+ * @param {*} taxaCSV
254
+ * @param {*} inclusionList
255
+ * @param {*} taxaMeta
256
+ * @param {Taxon} taxonClass
257
+ * @param {boolean} showFlowerErrors
258
+ */
259
+ #loadTaxa(taxaCSV, inclusionList, taxaMeta, taxonClass, showFlowerErrors) {
260
+ for (const row of taxaCSV) {
261
+ const name = row["taxon_name"];
195
262
 
196
263
  let taxon_overrides = {};
197
- if ( inclusionList !== true ) {
198
- taxon_overrides = inclusionList[ name ];
199
- if ( !taxon_overrides ) {
264
+ if (inclusionList !== true) {
265
+ taxon_overrides = inclusionList[name];
266
+ if (!taxon_overrides) {
200
267
  continue;
201
268
  }
202
269
  }
203
270
 
204
- if ( this.#taxa[ name ] ) {
205
- this.#errorLog.log( name, "has multiple entries" );
271
+ if (this.#taxa[name]) {
272
+ this.#errorLog.log(name, "has multiple entries");
206
273
  }
207
274
 
208
- const status = taxon_overrides[ "status" ];
209
- if ( status !== undefined ) {
210
- row[ "status" ] = status;
275
+ const status = taxon_overrides["status"];
276
+ if (status !== undefined) {
277
+ row["status"] = status;
211
278
  }
212
- const taxon = new taxonClass( row, taxaMeta[ name ] );
213
- this.#taxa[ name ] = taxon;
279
+ const taxon = new taxonClass(row, taxaMeta[name]);
280
+ this.#taxa[name] = taxon;
214
281
  const colors = taxon.getFlowerColors();
215
- if ( colors ) {
216
- for ( const colorName of colors ) {
217
- const color = this.#flower_colors[ colorName ];
218
- if ( !color ) {
219
- throw new Error( "flower color \"" + colorName + "\" not found" );
282
+ if (colors) {
283
+ for (const colorName of colors) {
284
+ const color = this.#flower_colors[colorName];
285
+ if (!color) {
286
+ throw new Error(
287
+ 'flower color "' + colorName + '" not found'
288
+ );
220
289
  }
221
- color.addTaxon( taxon );
290
+ color.addTaxon(taxon);
222
291
  }
223
292
  }
224
293
 
225
- if ( showFlowerErrors ) {
294
+ if (showFlowerErrors) {
226
295
  // Make sure flower colors/bloom times are present or not depending on taxon.
227
- if ( taxon.shouldHaveFlowers() ) {
228
- if ( !colors || !taxon.getBloomStart() || !taxon.getBloomEnd() ) {
229
- this.#errorLog.log( name, "does not have all flower info" );
296
+ if (taxon.shouldHaveFlowers()) {
297
+ if (
298
+ !colors ||
299
+ !taxon.getBloomStart() ||
300
+ !taxon.getBloomEnd()
301
+ ) {
302
+ this.#errorLog.log(
303
+ name,
304
+ "does not have all flower info"
305
+ );
230
306
  }
231
307
  } else {
232
- if ( colors || taxon.getBloomStart() || taxon.getBloomEnd() ) {
233
- this.#errorLog.log( name, "should not have flower info" );
308
+ if (
309
+ colors ||
310
+ taxon.getBloomStart() ||
311
+ taxon.getBloomEnd()
312
+ ) {
313
+ this.#errorLog.log(name, "should not have flower info");
234
314
  }
235
315
  }
236
316
  }
237
317
  }
238
-
239
318
  }
240
-
241
-
242
319
  }
243
320
 
244
- export { Taxa, TAXA_LIST_COLS };
321
+ export { Taxa, TAXA_LIST_COLS };
package/lib/taxaloader.js CHANGED
@@ -1,35 +1,48 @@
1
- import { CSV } from "./csv.js";
2
- import { Files } from "./files.js";
3
1
  import { GenericTaxaLoader } from "./generictaxaloader.js";
4
- import { Taxa } from "./taxa.js";
2
+ import { CSV, Files, Taxa } from "./index.js";
5
3
 
6
4
  class TaxaLoader extends GenericTaxaLoader {
7
-
8
- constructor( options ) {
9
- super( options );
5
+ /**
6
+ * @param {*} options
7
+ */
8
+ constructor(options) {
9
+ super(options);
10
10
  }
11
11
 
12
+ /**
13
+ * @return {Promise<Taxa>}
14
+ */
12
15
  async loadTaxa() {
13
- function getIncludeList( dataDir ) {
16
+ /**
17
+ *
18
+ * @param {string} dataDir
19
+ * @returns
20
+ */
21
+ function getIncludeList(dataDir) {
14
22
  // Read inclusion list.
15
23
  const includeFileName = "taxa_include.csv";
16
24
  const includeFilePath = dataDir + "/" + includeFileName;
17
- if ( !Files.exists( includeFilePath ) ) {
18
- console.log( includeFilePath + " not found; loading all taxa" );
25
+ if (!Files.exists(includeFilePath)) {
26
+ console.log(includeFilePath + " not found; loading all taxa");
19
27
  return true;
20
28
  }
21
- const includeCSV = CSV.parseFile( dataDir, includeFileName );
29
+ /**@type { import("./index.js").TaxonData[]} */
30
+ const includeCSV = CSV.parseFile(dataDir, includeFileName);
31
+ /** @type {Object<string,import("./index.js").TaxonData>} */
22
32
  const include = {};
23
- for ( const row of includeCSV ) {
24
- include[ row[ "taxon_name" ] ] = row;
33
+ for (const row of includeCSV) {
34
+ include[row["taxon_name"]] = row;
25
35
  }
26
36
  return include;
27
37
  }
28
38
 
29
39
  const options = this.getOptions();
30
- return new Taxa( getIncludeList( options.datadir ), this.getErrorLog(), options[ "show-flower-errors" ] );
40
+ return new Taxa(
41
+ getIncludeList(options.datadir),
42
+ this.getErrorLog(),
43
+ options["show-flower-errors"]
44
+ );
31
45
  }
32
-
33
46
  }
34
47
 
35
- export { TaxaLoader };
48
+ export { TaxaLoader };
@@ -1,12 +1,11 @@
1
1
  import { TaxaLoader } from "./taxaloader.js";
2
2
 
3
3
  class TaxaProcessor {
4
-
5
4
  #options;
6
5
  #taxaLoaderClass;
7
6
  #taxaLoader;
8
7
 
9
- constructor( options, taxaLoaderClass = TaxaLoader ) {
8
+ constructor(options, taxaLoaderClass = TaxaLoader) {
10
9
  this.#options = options;
11
10
  this.#taxaLoaderClass = taxaLoaderClass;
12
11
  }
@@ -23,14 +22,13 @@ class TaxaProcessor {
23
22
  return this.#taxaLoader.getTaxa();
24
23
  }
25
24
 
26
- async process( commandRunner ) {
27
- console.log( "loading data" );
28
- this.#taxaLoader = new this.#taxaLoaderClass( this.#options );
25
+ async process(commandRunner) {
26
+ console.log("loading data");
27
+ this.#taxaLoader = new this.#taxaLoaderClass(this.#options);
29
28
  await this.#taxaLoader.load();
29
+ await commandRunner(this);
30
30
  this.#taxaLoader.writeErrorLog();
31
- await commandRunner( this );
32
31
  }
33
-
34
32
  }
35
33
 
36
- export { TaxaProcessor };
34
+ export { TaxaProcessor };