@ca-plant-list/ca-plant-list 0.3.1 → 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 (59) hide show
  1. package/.vscode/settings.json +5 -0
  2. package/data/exceptions.json +88 -83
  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 +56 -54
  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/Trillium-chloropetalum.md +1 -1
  37. package/data/text/Viola-douglasii.md +1 -0
  38. package/data/text/Viola-pedunculata.md +1 -0
  39. package/data/text/Viola-purpurea-subsp-quercetorum.md +1 -0
  40. package/ebook/css/main.css +5 -0
  41. package/lib/basepagerenderer.js +30 -28
  42. package/lib/csv.js +13 -0
  43. package/lib/dateutils.js +36 -16
  44. package/lib/ebook/pages/taxonpage.js +63 -36
  45. package/lib/errorlog.js +16 -11
  46. package/lib/exceptions.js +2 -0
  47. package/lib/families.js +109 -71
  48. package/lib/files.js +103 -45
  49. package/lib/generictaxaloader.js +15 -7
  50. package/lib/html.js +2 -2
  51. package/lib/index.js +38 -3
  52. package/lib/taxa.js +175 -86
  53. package/lib/taxaloader.js +28 -15
  54. package/lib/taxaprocessor.js +6 -8
  55. package/lib/taxon.js +109 -56
  56. package/lib/web/pagetaxon.js +1 -1
  57. package/package.json +6 -8
  58. package/scripts/build-ebook.js +30 -25
  59. package/lib/index.d.ts +0 -327
package/lib/taxon.js CHANGED
@@ -1,5 +1,5 @@
1
+ import { HTML } from "./index.js";
1
2
  import { Genera } from "./genera.js";
2
- import { HTML } from "./html.js";
3
3
  import { RarePlants } from "./rareplants.js";
4
4
 
5
5
  const TAXA_COLNAMES = {
@@ -10,15 +10,16 @@ const TAXA_COLNAMES = {
10
10
  };
11
11
 
12
12
  class Taxon {
13
-
14
13
  #name;
15
14
  #genus;
16
15
  #commonNames;
17
16
  #status;
18
17
  #jepsonID;
19
18
  #calRecNum;
19
+ /**@type {string|undefined} */
20
20
  #cfSyn;
21
21
  #iNatID;
22
+ /**@type {string|undefined} */
22
23
  #iNatSyn;
23
24
  #flowerColors;
24
25
  #bloomStart;
@@ -29,38 +30,52 @@ class Taxon {
29
30
  #fesa;
30
31
  #rankCNDDB;
31
32
  #rankGlobal;
33
+ /** @type {string[]} */
32
34
  #synonyms = [];
33
35
 
34
- constructor( data ) {
35
- const name = data[ "taxon_name" ];
36
- const commonNames = data[ TAXA_COLNAMES.COMMON_NAME ];
37
- const cesa = data[ "CESA" ];
38
- const fesa = data[ "FESA" ];
39
- const rankGlobal = data[ "GRank" ];
40
- const rankCNDDB = data[ "SRank" ];
36
+ /**
37
+ * @param {import("./index.js").TaxonData} data
38
+ */
39
+ constructor(data) {
40
+ const name = data["taxon_name"];
41
+ const commonNames = data["common name"];
42
+ const cesa = data["CESA"];
43
+ const fesa = data["FESA"];
44
+ const rankGlobal = data["GRank"];
45
+ const rankCNDDB = data["SRank"];
41
46
  this.#name = name;
42
- this.#genus = name.split( " " )[ 0 ];
43
- this.#commonNames = commonNames ? commonNames.split( "," ).map( t => t.trim() ) : [];
44
- this.#status = data[ "status" ];
45
- this.#jepsonID = data[ "jepson id" ];
46
- this.#calRecNum = data[ "calrecnum" ];
47
- this.#iNatID = data[ "inat id" ];
48
- const colors = data[ TAXA_COLNAMES.FLOWER_COLOR ];
49
- this.#flowerColors = colors ? colors.split( "," ) : undefined;
50
- this.#bloomStart = data[ TAXA_COLNAMES.BLOOM_START ];
51
- this.#bloomEnd = data[ TAXA_COLNAMES.BLOOM_END ];
52
- this.#rpiID = data[ "RPI ID" ];
53
- this.#rankRPI = data[ "CRPR" ];
47
+ this.#genus = name.split(" ")[0];
48
+ this.#commonNames = commonNames
49
+ ? commonNames.split(",").map((t) => t.trim())
50
+ : [];
51
+ this.#status = data["status"];
52
+ this.#jepsonID = data["jepson id"];
53
+ this.#calRecNum = data["calrecnum"];
54
+ this.#iNatID = data["inat id"];
55
+ const colors = data["flower_color"];
56
+ this.#flowerColors = colors ? colors.split(",") : undefined;
57
+ if (data["bloom_start"]) {
58
+ this.#bloomStart = parseInt(data["bloom_start"]);
59
+ }
60
+ if (data["bloom_end"]) {
61
+ this.#bloomEnd = parseInt(data["bloom_end"]);
62
+ }
63
+ this.#rpiID = data["RPI ID"];
64
+ this.#rankRPI = data["CRPR"];
54
65
  this.#cesa = cesa ? cesa : undefined;
55
66
  this.#fesa = fesa ? fesa : undefined;
56
67
  this.#rankCNDDB = rankCNDDB ? rankCNDDB : undefined;
57
68
  this.#rankGlobal = rankGlobal ? rankGlobal : undefined;
58
- Genera.addTaxon( this );
69
+ Genera.addTaxon(this);
59
70
  }
60
71
 
61
- addSynonym( syn, type ) {
62
- this.#synonyms.push( syn );
63
- switch ( type ) {
72
+ /**
73
+ * @param {string} syn
74
+ * @param {string} type
75
+ */
76
+ addSynonym(syn, type) {
77
+ this.#synonyms.push(syn);
78
+ switch (type) {
64
79
  case "CF":
65
80
  // Synonym is in Calflora format.
66
81
  this.#cfSyn = syn;
@@ -74,22 +89,28 @@ class Taxon {
74
89
 
75
90
  getBaseFileName() {
76
91
  // Convert spaces to "-" and remove ".".
77
- return this.#name.replaceAll( " ", "-" ).replaceAll( ".", "" );
92
+ return this.#name.replaceAll(" ", "-").replaceAll(".", "");
78
93
  }
79
94
 
95
+ /**
96
+ * @returns {number|undefined}
97
+ */
80
98
  getBloomEnd() {
81
99
  return this.#bloomEnd;
82
100
  }
83
101
 
102
+ /**
103
+ * @returns {number|undefined}
104
+ */
84
105
  getBloomStart() {
85
106
  return this.#bloomStart;
86
107
  }
87
108
 
88
109
  getCalfloraName() {
89
- if ( this.#cfSyn ) {
110
+ if (this.#cfSyn) {
90
111
  return this.#cfSyn;
91
112
  }
92
- return this.getName().replace( " subsp.", " ssp." ).replace( "×", "X" );
113
+ return this.getName().replace(" subsp.", " ssp.").replace("×", "X");
93
114
  }
94
115
 
95
116
  getCalfloraID() {
@@ -98,11 +119,16 @@ class Taxon {
98
119
 
99
120
  getCalfloraTaxonLink() {
100
121
  const calfloraID = this.getCalfloraID();
101
- if ( !calfloraID ) {
122
+ if (!calfloraID) {
102
123
  return;
103
124
  }
104
- const link = HTML.getLink( "https://www.calflora.org/app/taxon?crn=" + calfloraID, "Calflora", {}, true );
105
- return this.#cfSyn ? ( link + " (" + this.#cfSyn + ")" ) : link;
125
+ const link = HTML.getLink(
126
+ "https://www.calflora.org/app/taxon?crn=" + calfloraID,
127
+ "Calflora",
128
+ {},
129
+ true
130
+ );
131
+ return this.#cfSyn ? link + " (" + this.#cfSyn + ")" : link;
106
132
  }
107
133
 
108
134
  getCESA() {
@@ -118,14 +144,14 @@ class Taxon {
118
144
  }
119
145
 
120
146
  getFamily() {
121
- return Genera.getFamily( this.#genus );
147
+ return Genera.getFamily(this.#genus);
122
148
  }
123
149
 
124
150
  getFESA() {
125
151
  return this.#fesa;
126
152
  }
127
153
 
128
- getFileName( ext = "html" ) {
154
+ getFileName(ext = "html") {
129
155
  return this.getBaseFileName() + "." + ext;
130
156
  }
131
157
 
@@ -134,7 +160,7 @@ class Taxon {
134
160
  }
135
161
 
136
162
  getGenus() {
137
- return Genera.getGenus( this.#genus );
163
+ return Genera.getGenus(this.#genus);
138
164
  }
139
165
 
140
166
  getGenusName() {
@@ -145,18 +171,29 @@ class Taxon {
145
171
  return this.#rankGlobal;
146
172
  }
147
173
 
148
- getHTMLLink( href = true, includeRPI = true ) {
149
- href = href ? ( "./" + this.getFileName() ) : undefined;
174
+ /**
175
+ *
176
+ * @param {boolean|string|undefined} href
177
+ * @param {boolean} includeRPI
178
+ */
179
+ getHTMLLink(href = true, includeRPI = true) {
180
+ href = href ? "./" + this.getFileName() : undefined;
150
181
  let className = this.isNative() ? "native" : "non-native";
151
182
  let isRare = false;
152
- if ( includeRPI && this.isRare() ) {
183
+ if (includeRPI && this.isRare()) {
153
184
  isRare = true;
154
185
  className += " rare";
155
186
  }
156
187
  const attributes = { class: className };
157
- const link = HTML.wrap( "span", HTML.getLink( href, this.getName() ), attributes );
158
- if ( isRare ) {
159
- return HTML.getToolTip( link, this.getRPIRankAndThreatTooltip(), { icon: false } );
188
+ const link = HTML.wrap(
189
+ "span",
190
+ HTML.getLink(href, this.getName()),
191
+ attributes
192
+ );
193
+ if (isRare) {
194
+ return HTML.getToolTip(link, this.getRPIRankAndThreatTooltip(), {
195
+ icon: false,
196
+ });
160
197
  }
161
198
  return link;
162
199
  }
@@ -167,7 +204,7 @@ class Taxon {
167
204
 
168
205
  getINatName() {
169
206
  const name = this.#iNatSyn ? this.#iNatSyn : this.getName();
170
- return name.replace( / (subsp|var)\./, "" ).replace( "×", "× " );
207
+ return name.replace(/ (subsp|var)\./, "").replace("×", "× ");
171
208
  }
172
209
 
173
210
  getINatSyn() {
@@ -176,11 +213,16 @@ class Taxon {
176
213
 
177
214
  getINatTaxonLink() {
178
215
  const iNatID = this.getINatID();
179
- if ( !iNatID ) {
216
+ if (!iNatID) {
180
217
  return "";
181
218
  }
182
- const link = HTML.getLink( "https://www.inaturalist.org/taxa/" + iNatID, "iNaturalist", {}, true );
183
- return this.#iNatSyn ? ( link + " (" + this.#iNatSyn + ")" ) : link;
219
+ const link = HTML.getLink(
220
+ "https://www.inaturalist.org/taxa/" + iNatID,
221
+ "iNaturalist",
222
+ {},
223
+ true
224
+ );
225
+ return this.#iNatSyn ? link + " (" + this.#iNatSyn + ")" : link;
184
226
  }
185
227
 
186
228
  getJepsonID() {
@@ -196,10 +238,10 @@ class Taxon {
196
238
  }
197
239
 
198
240
  getRPIRank() {
199
- if ( !this.#rankRPI ) {
241
+ if (!this.#rankRPI) {
200
242
  return this.#rankRPI;
201
243
  }
202
- return this.#rankRPI.split( "." )[ 0 ];
244
+ return this.#rankRPI.split(".")[0];
203
245
  }
204
246
 
205
247
  getRPIRankAndThreat() {
@@ -207,15 +249,22 @@ class Taxon {
207
249
  }
208
250
 
209
251
  getRPIRankAndThreatTooltip() {
210
- return RarePlants.getRPIRankAndThreatDescriptions( this.getRPIRankAndThreat() ).join( "<br>" );
252
+ return RarePlants.getRPIRankAndThreatDescriptions(
253
+ this.getRPIRankAndThreat()
254
+ ).join("<br>");
211
255
  }
212
256
 
213
257
  getRPITaxonLink() {
214
258
  const rpiID = this.getRPIID();
215
- if ( !rpiID ) {
259
+ if (!rpiID) {
216
260
  return "";
217
261
  }
218
- const link = HTML.getLink( "https://rareplants.cnps.org/Plants/Details/" + rpiID, "CNPS Rare Plant Inventory", {}, true );
262
+ const link = HTML.getLink(
263
+ "https://rareplants.cnps.org/Plants/Details/" + rpiID,
264
+ "CNPS Rare Plant Inventory",
265
+ {},
266
+ true
267
+ );
219
268
  return link;
220
269
  }
221
270
 
@@ -223,16 +272,20 @@ class Taxon {
223
272
  return this.#status;
224
273
  }
225
274
 
226
- getStatusDescription( config ) {
227
- switch ( this.#status ) {
275
+ /**
276
+ * @param {*} config
277
+ * @returns
278
+ */
279
+ getStatusDescription(config) {
280
+ switch (this.#status) {
228
281
  case "N":
229
282
  return "Native";
230
283
  case "NC":
231
- return config.getLabel( "status-NC", "Introduced" );
284
+ return config.getLabel("status-NC", "Introduced");
232
285
  case "X":
233
286
  return "Introduced";
234
287
  }
235
- throw new Error( this.#status );
288
+ throw new Error(this.#status);
236
289
  }
237
290
 
238
291
  getSynonyms() {
@@ -257,7 +310,7 @@ class Taxon {
257
310
 
258
311
  shouldHaveFlowers() {
259
312
  const sectionName = this.getFamily().getSectionName();
260
- switch ( sectionName ) {
313
+ switch (sectionName) {
261
314
  case "Ceratophyllales":
262
315
  case "Eudicots":
263
316
  case "Magnoliids":
@@ -269,9 +322,9 @@ class Taxon {
269
322
  case "Lycophytes":
270
323
  return false;
271
324
  default:
272
- throw new Error( sectionName );
325
+ throw new Error(sectionName);
273
326
  }
274
327
  }
275
328
  }
276
329
 
277
- export { TAXA_COLNAMES, Taxon };
330
+ export { TAXA_COLNAMES, Taxon };
@@ -1,9 +1,9 @@
1
- import { HTML } from "@ca-plant-list/ca-plant-list";
2
1
  import { Jepson } from "../jepson.js";
3
2
  import { RarePlants } from "../rareplants.js";
4
3
  import { GenericPage } from "../genericpage.js";
5
4
  import { ExternalSites } from "../externalsites.js";
6
5
  import { DateUtils } from "../dateutils.js";
6
+ import { HTML } from "../html.js";
7
7
 
8
8
  class PageTaxon extends GenericPage {
9
9
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ca-plant-list/ca-plant-list",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Tools to create Jekyll files for a website listing plants in an area of California.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -10,11 +10,7 @@
10
10
  "homepage": "https://github.com/ca-plants/ca-plant-list",
11
11
  "type": "module",
12
12
  "exports": {
13
- ".": "./lib/index.js",
14
- "./Families": "./lib/families.js",
15
- "./Files": "./lib/files.js",
16
- "./HTML": "./lib/html.js",
17
- "./Jekyll": "./lib/jekyll.js"
13
+ ".": "./lib/index.js"
18
14
  },
19
15
  "types": "./lib/index.d.ts",
20
16
  "bin": {
@@ -35,7 +31,9 @@
35
31
  },
36
32
  "devDependencies": {
37
33
  "@types/node": "^18.11.9",
34
+ "@types/unzipper": "^0.10.9",
35
+ "dts-bundle-generator": "^9.3.1",
38
36
  "eslint": "^8.26.0",
39
- "typescript": "^4.9.3"
37
+ "typescript": "^5.3.3"
40
38
  }
41
- }
39
+ }
@@ -6,64 +6,69 @@ import { Files } from "../lib/files.js";
6
6
  import { TaxaProcessor } from "../lib/taxaprocessor.js";
7
7
  import { CommandProcessor } from "../lib/commandprocessor.js";
8
8
 
9
- const OPTION_DEFS = [
10
- { name: "locationsdir", type: String },
11
- ];
9
+ const OPTION_DEFS = [{ name: "locationsdir", type: String }];
12
10
 
13
11
  const OPTION_HELP = [
14
12
  {
15
13
  name: "locationsdir",
16
14
  type: String,
17
15
  typeLabel: "{underline path}",
18
- description: "If this option is specified, multiple ebooks will be generated. {bold locationsdir} must be a subdirectory"
19
- + " of the current directory, and each subdirectory of {bold locationsdir} is processed in turn to generate an ebook."
20
- + " Each ebook is placed in a subdirectory of {bold outputdir}."
16
+ description:
17
+ "If this option is specified, multiple ebooks will be generated. {bold locationsdir} must be a subdirectory" +
18
+ " of the current directory, and each subdirectory of {bold locationsdir} is processed in turn to generate an ebook." +
19
+ " Each ebook is placed in a subdirectory of {bold outputdir}.",
21
20
  },
22
21
  ];
23
22
 
24
23
  class BookCommand extends CommandProcessor {
25
-
26
24
  constructor() {
27
- super( "ca-plant-book", "A tool to generate an ebook with local plant data.", OPTION_DEFS, OPTION_HELP );
25
+ super(
26
+ "ca-plant-book",
27
+ "A tool to generate an ebook with local plant data.",
28
+ OPTION_DEFS,
29
+ OPTION_HELP
30
+ );
28
31
  }
29
-
30
32
  }
31
33
 
32
- async function commandRunner( tp ) {
34
+ async function commandRunner(tp) {
33
35
  const options = tp.getOptions();
34
- const ebook = new PlantBook( options.outputdir, new Config( options.datadir ), tp.getTaxa() );
36
+ const ebook = new PlantBook(
37
+ options.outputdir,
38
+ new Config(options.datadir),
39
+ tp.getTaxa()
40
+ );
35
41
  await ebook.create();
36
42
  }
37
43
 
38
- async function generateEBooks( options ) {
44
+ async function generateEBooks(options) {
39
45
  const locationsDir = options.locationsdir;
40
46
 
41
47
  // If there is a "locations" directory, generate a book for all subdirectories.
42
- if ( locationsDir ) {
48
+ if (locationsDir) {
43
49
  // Generate ebook for each location.
44
50
  const outputBase = options.outputdir;
45
- const subdirs = Files.getDirEntries( locationsDir );
46
- for ( const subdir of subdirs ) {
47
- console.log( "Generating " + subdir );
51
+ const subdirs = Files.getDirEntries(locationsDir);
52
+ for (const subdir of subdirs) {
53
+ console.log("Generating " + subdir);
48
54
  const suffix = "/" + subdir;
49
55
  const path = locationsDir + suffix;
50
- if ( Files.isDir( path ) ) {
56
+ if (Files.isDir(path)) {
51
57
  options.datadir = path;
52
58
  options.outputdir = outputBase + suffix;
53
- const gen = new TaxaProcessor( options );
54
- await gen.process( commandRunner );
59
+ const gen = new TaxaProcessor(options);
60
+ await gen.process(commandRunner);
55
61
  }
56
62
  }
57
63
  } else {
58
64
  // Otherwise use the default directory.
59
- const gen = new TaxaProcessor( options );
60
- await gen.process( commandRunner );
65
+ const gen = new TaxaProcessor(options);
66
+ await gen.process(commandRunner);
61
67
  }
62
-
63
68
  }
64
69
 
65
70
  const cmd = new BookCommand();
66
71
  const options = cmd.getOptions();
67
- if ( !options.help ) {
68
- generateEBooks( options );
69
- }
72
+ if (!options.help) {
73
+ await generateEBooks(options);
74
+ }