@ca-plant-list/ca-plant-list 0.4.21 → 0.4.23

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 (47) hide show
  1. package/data/exceptions.json +22 -1
  2. package/data/synonyms.csv +2 -0
  3. package/data/taxa.csv +1754 -1753
  4. package/lib/basepagerenderer.js +10 -4
  5. package/lib/ebook/images.js +3 -3
  6. package/lib/ebook/pages/{page_list_families.js → pageListFamilies.js} +1 -1
  7. package/lib/ebook/pages/{page_list_flowers.js → pageListFlowers.js} +2 -2
  8. package/lib/ebook/pages/page_list_species.js +1 -1
  9. package/lib/ebook/pages/taxonpage.js +1 -1
  10. package/lib/ebook/pages/tocpage.js +2 -2
  11. package/lib/ebook/plantbook.js +3 -3
  12. package/lib/errorlog.js +1 -1
  13. package/lib/externalsites.js +113 -35
  14. package/lib/files.js +3 -5
  15. package/lib/flowercolor.js +2 -2
  16. package/lib/genera.js +4 -4
  17. package/lib/html.js +7 -8
  18. package/lib/htmltaxon.js +122 -33
  19. package/lib/index.d.ts +72 -27
  20. package/lib/index.js +3 -3
  21. package/lib/pagerenderer.js +6 -6
  22. package/lib/taxonomy/families.js +104 -0
  23. package/lib/{taxa.js → taxonomy/taxa.js} +18 -18
  24. package/lib/{taxon.js → taxonomy/taxon.js} +41 -111
  25. package/lib/taxonomy/taxonomy.js +17 -0
  26. package/lib/tools/calflora.js +2 -2
  27. package/lib/tools/calscape.js +3 -3
  28. package/lib/tools/cch2.js +128 -10
  29. package/lib/tools/fna.js +163 -0
  30. package/lib/tools/inat.js +3 -3
  31. package/lib/tools/jepsoneflora.js +21 -2
  32. package/lib/tools/rpi.js +5 -5
  33. package/lib/tools/supplementaltext.js +1 -1
  34. package/lib/tools/taxacsv.js +23 -4
  35. package/lib/types.js +10 -0
  36. package/lib/utils/inat-tools.js +2 -2
  37. package/lib/web/pageFamily.js +146 -0
  38. package/lib/web/pagetaxon.js +21 -63
  39. package/package.json +2 -1
  40. package/scripts/build-ebook.js +4 -4
  41. package/scripts/build-site.js +3 -3
  42. package/scripts/cpl-photos.js +1 -1
  43. package/scripts/cpl-tools.js +18 -2
  44. package/scripts/inatobsphotos.js +2 -2
  45. package/scripts/inattaxonphotos.js +2 -2
  46. package/lib/families.js +0 -243
  47. package/lib/jepson.js +0 -17
@@ -2,12 +2,13 @@ import { Config } from "./config.js";
2
2
  import { Files } from "./files.js";
3
3
  import { Jekyll } from "./jekyll.js";
4
4
  import { GlossaryPages } from "./web/glossarypages.js";
5
+ import { PageFamilyList } from "./web/pageFamily.js";
5
6
 
6
7
  class BasePageRenderer {
7
8
  /**
8
9
  * @param {string} outputDir
9
- * @param {import("./taxa.js").Taxa} taxa
10
- * @param {import("./htmltaxon.js").TaxaColDef[]} [familyCols]
10
+ * @param {import("./types.js").Taxa} taxa
11
+ * @param {import("./types.js").TaxaColDef[]} [familyCols]
11
12
  */
12
13
  static renderBasePages(outputDir, taxa, familyCols) {
13
14
  const siteGenerator = new Jekyll(outputDir);
@@ -21,7 +22,12 @@ class BasePageRenderer {
21
22
  // Copy illustrations.
22
23
  siteGenerator.copyIllustrations(taxa.getFlowerColors());
23
24
 
24
- taxa.getFamilies().renderPages(outputDir, familyCols);
25
+ const fl = new PageFamilyList(
26
+ outputDir,
27
+ taxa.getFamilies().getFamilies(),
28
+ );
29
+ fl.render(familyCols);
30
+ fl.renderPages(outputDir, familyCols);
25
31
 
26
32
  new GlossaryPages(siteGenerator).renderPages();
27
33
 
@@ -30,7 +36,7 @@ class BasePageRenderer {
30
36
 
31
37
  /**
32
38
  * @param {string} outputDir
33
- * @param {import("./taxa.js").Taxa} taxa
39
+ * @param {import("./types.js").Taxa} taxa
34
40
  */
35
41
  static renderTools(outputDir, taxa) {
36
42
  const names = [];
@@ -14,7 +14,7 @@ class Images {
14
14
  /**
15
15
  * @param {import("../sitegenerator.js").SiteGenerator} siteGenerator
16
16
  * @param {string} contentDir
17
- * @param {import("../taxa.js").Taxa} taxa
17
+ * @param {import("../types.js").Taxa} taxa
18
18
  */
19
19
  constructor(siteGenerator, contentDir, taxa) {
20
20
  this.#siteGenerator = siteGenerator;
@@ -23,7 +23,7 @@ class Images {
23
23
  }
24
24
 
25
25
  /**
26
- * @param {import("../taxon.js").Taxon[]} taxa
26
+ * @param {import("../taxonomy/taxon.js").Taxon[]} taxa
27
27
  */
28
28
  async createImages(taxa) {
29
29
  const meter = new ProgressMeter("processing photos", taxa.length);
@@ -118,7 +118,7 @@ class Images {
118
118
  }
119
119
 
120
120
  /**
121
- * @param {import("../taxon.js").Taxon} taxon
121
+ * @param {import("../taxonomy/taxon.js").Taxon} taxon
122
122
  * @returns {import("../photo.js").Photo[]}
123
123
  */
124
124
  static getTaxonPhotos(taxon) {
@@ -6,7 +6,7 @@ class PageListFamilies extends EBookPage {
6
6
 
7
7
  /**
8
8
  * @param {string} outputDir
9
- * @param {import("../../families.js").Families} families
9
+ * @param {import("../../types.js").Families} families
10
10
  */
11
11
  constructor(outputDir, families) {
12
12
  super(outputDir + "/list_families.html", "All Families");
@@ -8,7 +8,7 @@ const FN_FLOWER_TIME_INDEX = "fm.html";
8
8
  class PageListFlowers {
9
9
  /**
10
10
  * @param {string} contentDir
11
- * @param {import("../../taxa.js").Taxa} taxa
11
+ * @param {import("../../types.js").Taxa} taxa
12
12
  */
13
13
  static createPages(contentDir, taxa) {
14
14
  new PageListFlowerTimeIndex(contentDir).create();
@@ -83,7 +83,7 @@ class PageListFlowerTime extends EBookPage {
83
83
 
84
84
  /**
85
85
  * @param {string} outputDir
86
- * @param {import("../../taxa.js").Taxa} taxa
86
+ * @param {import("../../types.js").Taxa} taxa
87
87
  * @param {number} month
88
88
  */
89
89
  constructor(outputDir, taxa, month) {
@@ -8,7 +8,7 @@ class PageListSpecies extends EBookPage {
8
8
  /**
9
9
  *
10
10
  * @param {string} outputDir
11
- * @param {import("../../taxon.js").Taxon[]} taxa
11
+ * @param {import("../../taxonomy/taxon.js").Taxon[]} taxa
12
12
  * @param {string} filename
13
13
  * @param {string} title
14
14
  */
@@ -13,7 +13,7 @@ class TaxonPage extends EBookPage {
13
13
 
14
14
  /**
15
15
  * @param {string} outputDir
16
- * @param {import("../../taxon.js").Taxon} taxon
16
+ * @param {import("../../taxonomy/taxon.js").Taxon} taxon
17
17
  * @param {Images} images
18
18
  */
19
19
  constructor(outputDir, taxon, images) {
@@ -1,13 +1,13 @@
1
1
  import { EBookPage } from "../ebookpage.js";
2
2
  import { XHTML } from "../xhtml.js";
3
- import { PageListFlowers } from "./page_list_flowers.js";
3
+ import { PageListFlowers } from "./pageListFlowers.js";
4
4
 
5
5
  class TOCPage extends EBookPage {
6
6
  #taxa;
7
7
 
8
8
  /**
9
9
  * @param {string} outputDir
10
- * @param {import("../../taxa.js").Taxa} taxa
10
+ * @param {import("../../taxonomy/taxa.js").Taxa} taxa
11
11
  */
12
12
  constructor(outputDir, taxa) {
13
13
  super(outputDir + "/toc.xhtml", "Table of Contents");
@@ -3,9 +3,9 @@ import { EBook } from "./ebook.js";
3
3
  import { EBookSiteGenerator } from "./ebooksitegenerator.js";
4
4
  import { GlossaryPages } from "./glossarypages.js";
5
5
  import { Images } from "./images.js";
6
- import { PageListFamilies } from "./pages/page_list_families.js";
6
+ import { PageListFamilies } from "./pages/pageListFamilies.js";
7
7
  import { PageListFlowerColor } from "./pages/page_list_flower_color.js";
8
- import { PageListFlowers } from "./pages/page_list_flowers.js";
8
+ import { PageListFlowers } from "./pages/pageListFlowers.js";
9
9
  import { PageListSpecies } from "./pages/page_list_species.js";
10
10
  import { TaxonPage } from "./pages/taxonpage.js";
11
11
  import { TOCPage } from "./pages/tocpage.js";
@@ -18,7 +18,7 @@ class PlantBook extends EBook {
18
18
  /**
19
19
  * @param {string} outputDir
20
20
  * @param {import("../config.js").Config} config
21
- * @param {import("../taxa.js").Taxa} taxa
21
+ * @param {import("../types.js").Taxa} taxa
22
22
  */
23
23
  constructor(outputDir, config, taxa) {
24
24
  super(
package/lib/errorlog.js CHANGED
@@ -17,7 +17,7 @@ class ErrorLog {
17
17
  }
18
18
 
19
19
  /**
20
- * @param {...string} args
20
+ * @param {...any} args
21
21
  */
22
22
  log(...args) {
23
23
  if (this.#echo) {
@@ -1,13 +1,51 @@
1
- /** @typedef {{
2
- coords?: [number, number];
3
- project_id?: string;
4
- subview?: "grid" | "list" | "map";
5
- taxon_id?: string;
6
- }} InatObsOptions */
7
-
8
1
  export class ExternalSites {
9
2
  /**
10
- * @param {import("./taxon.js").Taxon} taxon
3
+ * @param {import("./types.js").Taxon} taxon
4
+ * @param {import("./types.js").Config} config
5
+ * @returns {URL|undefined}
6
+ */
7
+ static getCalfloraObsLink(taxon, config) {
8
+ const name = taxon.getCalfloraName();
9
+ if (!name) {
10
+ return;
11
+ }
12
+ const url = new URL(
13
+ "https://www.calflora.org/entry/observ.html?track=m#srch=t&grezc=5&cols=b&lpcli=t&cc=" +
14
+ config.getCountyCodes().join("!") +
15
+ "&incobs=f&taxon=" +
16
+ name,
17
+ );
18
+ return url;
19
+ }
20
+
21
+ /**
22
+ * @param {import("./types.js").Taxon} taxon
23
+ * @returns {URL|undefined}
24
+ */
25
+ static getCalfloraRefLink(taxon) {
26
+ const calfloraID = taxon.getCalfloraID();
27
+ if (!calfloraID) {
28
+ return;
29
+ }
30
+ return new URL("https://www.calflora.org/app/taxon?crn=" + calfloraID);
31
+ }
32
+
33
+ /**
34
+ * @param {import("./types.js").Taxon} taxon
35
+ * @returns {URL|undefined}
36
+ */
37
+ static getCalscapeLink(taxon) {
38
+ const calscapeCN = taxon.getCalscapeCommonName();
39
+ if (!calscapeCN) {
40
+ return;
41
+ }
42
+ return new URL(
43
+ `https://www.calscape.org/${taxon.getCalscapeName().replaceAll(" ", "-")}-()`,
44
+ );
45
+ }
46
+
47
+ /**
48
+ * @param {import("./types.js").Taxon} taxon
11
49
  * @param {import("./config.js").Config} config
12
50
  * @returns {URL|undefined}
13
51
  */
@@ -21,7 +59,7 @@ export class ExternalSites {
21
59
  }
22
60
 
23
61
  /**
24
- * @param {import("./taxon.js").Taxon} taxon
62
+ * @param {import("./types.js").Taxon} taxon
25
63
  * @returns {URL|undefined}
26
64
  */
27
65
  static getCCH2RefLink(taxon) {
@@ -35,40 +73,80 @@ export class ExternalSites {
35
73
  }
36
74
 
37
75
  /**
38
- * @param {InatObsOptions} options
76
+ * @param {import("./types.js").Taxon} taxon
77
+ * @returns {URL|undefined}
39
78
  */
40
- static getInatObsLink(options) {
79
+ static getFNARefLink(taxon) {
80
+ const name = taxon.getFNAName();
81
+ if (!name) {
82
+ return;
83
+ }
41
84
  const url = new URL(
42
- "https://www.inaturalist.org/observations?subview=map",
85
+ "http://floranorthamerica.org/" + name.replaceAll(" ", "_"),
43
86
  );
87
+ return url;
88
+ }
44
89
 
45
- if (options.coords) {
46
- const delta = 0.1;
47
- const params = url.searchParams;
48
- const lat = options.coords[1];
49
- const lng = options.coords[0];
50
- params.set("nelat", (lat + delta).toString());
51
- params.set("swlat", (lat - delta).toString());
52
- params.set("nelng", (lng + delta).toString());
53
- params.set("swlng", (lng - delta).toString());
90
+ /**
91
+ * @param {import("./types.js").Taxon} taxon
92
+ * @param {import("./config.js").Config} config
93
+ * @returns {URL|undefined}
94
+ */
95
+ static getInatObsLink(taxon, config) {
96
+ const iNatID = taxon.getINatID();
97
+ if (!iNatID) {
98
+ return;
54
99
  }
55
100
 
56
- for (const [k, v] of Object.entries(options)) {
57
- switch (k) {
58
- case "created_d1":
59
- case "list_id":
60
- case "place_id":
61
- case "project_id":
62
- case "subview":
63
- case "taxon_id":
64
- case "taxon_name":
65
- if (typeof v === "string") {
66
- url.searchParams.set(k, v);
67
- }
68
- break;
101
+ const url = new URL(
102
+ "https://www.inaturalist.org/observations?subview=map",
103
+ );
104
+ url.searchParams.set("taxon_id", iNatID);
105
+ for (const p of ["place_id", "project_id"]) {
106
+ const v = config.getConfigValue("inat", p);
107
+ if (v) {
108
+ url.searchParams.set(p, v);
69
109
  }
70
110
  }
71
111
 
72
- return url.toString();
112
+ return url;
113
+ }
114
+
115
+ /**
116
+ * @param {import("./types.js").Taxon} taxon
117
+ * @returns {URL|undefined}
118
+ */
119
+ static getINatRefLink(taxon) {
120
+ const iNatID = taxon.getINatID();
121
+ if (!iNatID) {
122
+ return;
123
+ }
124
+ return new URL("https://www.inaturalist.org/taxa/" + iNatID);
125
+ }
126
+
127
+ /**
128
+ * @param {import("./types.js").Taxonomy} taxon
129
+ * @returns {URL|undefined}
130
+ */
131
+ static getJepsonRefLink(taxon) {
132
+ const id = taxon.getJepsonID();
133
+ if (!id) {
134
+ return;
135
+ }
136
+ return new URL(
137
+ "https://ucjeps.berkeley.edu/eflora/eflora_display.php?tid=" + id,
138
+ );
139
+ }
140
+
141
+ /**
142
+ * @param {import("./types.js").Taxon} taxon
143
+ * @returns {URL|undefined}
144
+ */
145
+ static getRPIRefLink(taxon) {
146
+ const rpiID = taxon.getRPIID();
147
+ if (!rpiID) {
148
+ return;
149
+ }
150
+ return new URL("https://rareplants.cnps.org/Plants/Details/" + rpiID);
73
151
  }
74
152
  }
package/lib/files.js CHANGED
@@ -13,15 +13,13 @@ class Files {
13
13
 
14
14
  /**
15
15
  * @param {string} fileName
16
- * @param {*} inStream
17
- * @access private
16
+ * @param {import("node:stream").Stream} inStream
18
17
  */
19
18
  static #createFileFromStream(fileName, inStream) {
20
19
  /**
21
- *
22
20
  * @param {string} fileName
23
- * @param {*} inStream
24
- * @param {*} resolve
21
+ * @param {import("node:stream").Stream} inStream
22
+ * @param {function(boolean):void} resolve
25
23
  */
26
24
  function implementation(fileName, inStream, resolve) {
27
25
  const outStream = fs.createWriteStream(fileName);
@@ -3,7 +3,7 @@ import { TextUtils } from "./textutils.js";
3
3
  class FlowerColor {
4
4
  #colorName;
5
5
  #colorCode;
6
- /** @type {import("./taxon.js").Taxon[]} */
6
+ /** @type {import("./types.js").Taxon[]} */
7
7
  #taxa = [];
8
8
 
9
9
  /**
@@ -16,7 +16,7 @@ class FlowerColor {
16
16
  }
17
17
 
18
18
  /**
19
- * @param {import("./taxon.js").Taxon} taxon
19
+ * @param {import("./types.js").Taxon} taxon
20
20
  */
21
21
  addTaxon(taxon) {
22
22
  this.#taxa.push(taxon);
package/lib/genera.js CHANGED
@@ -6,7 +6,7 @@ class Genera {
6
6
  #genera;
7
7
 
8
8
  /**
9
- * @param {import("./families.js").Families} families
9
+ * @param {import("./types.js").Families} families
10
10
  */
11
11
  constructor(families) {
12
12
  const dataDir = Config.getPackageDir() + "/data";
@@ -15,7 +15,7 @@ class Genera {
15
15
  }
16
16
 
17
17
  /**
18
- * @param {import("./taxon.js").Taxon} taxon
18
+ * @param {import("./types.js").Taxon} taxon
19
19
  */
20
20
  addTaxon(taxon) {
21
21
  const genusName = taxon.getGenusName();
@@ -46,7 +46,7 @@ class Genus {
46
46
  #data;
47
47
 
48
48
  /**
49
- * @param {{family:string,familyObj:import("./families.js").Family,taxa:import("./taxon.js").Taxon[]}} data
49
+ * @param {{family:string,familyObj:import("./types.js").Family,taxa:import("./types.js").Taxon[]}} data
50
50
  */
51
51
  constructor(data) {
52
52
  this.#data = data;
@@ -57,7 +57,7 @@ class Genus {
57
57
  }
58
58
 
59
59
  /**
60
- * @returns {import("./taxon.js").Taxon[]}
60
+ * @returns {import("./types.js").Taxon[]}
61
61
  */
62
62
  getTaxa() {
63
63
  return this.#data.taxa.sort((a, b) =>
package/lib/html.js CHANGED
@@ -48,7 +48,7 @@ export class HTML {
48
48
 
49
49
  /**
50
50
  * Generate HTML for an <a> element.
51
- * @param {string|undefined} href
51
+ * @param {URL|string|undefined} href
52
52
  * @param {string} linkText
53
53
  * @param {string|Object<string,string>} [attributes]
54
54
  * @param {boolean} [openInNewWindow] true if the link should open in a new window.
@@ -57,7 +57,7 @@ export class HTML {
57
57
  static getLink(href, linkText, attributes = {}, openInNewWindow) {
58
58
  let html = "<a";
59
59
  if (href !== undefined) {
60
- html += this.renderAttribute("href", href);
60
+ html += this.renderAttribute("href", href.toString());
61
61
  }
62
62
  html += this.renderAttributes(attributes);
63
63
  if (openInNewWindow) {
@@ -70,8 +70,7 @@ export class HTML {
70
70
  * Get a Bootstrap formatted tooltip element.
71
71
  * @param {string} text - The text or HTML that should trigger the tooltip on hover.
72
72
  * @param {string} tooltip - The tooltip text or HTML.
73
- * @param {Object} options
74
- * @param {boolean} [options.icon] [true] display an icon after the text
73
+ * @param {{icon?:boolean}} options
75
74
  * @returns {string} A &lt;span> element to be used as a Bootstrap tooltip.
76
75
  */
77
76
  static getToolTip(text, tooltip, options = {}) {
@@ -106,19 +105,19 @@ export class HTML {
106
105
 
107
106
  /**
108
107
  * @param {string} elName
109
- * @param {string} text
108
+ * @param {string|number} text
110
109
  * @param {Object<string,string>} [attributes]
111
110
  */
112
111
  static textElement(elName, text, attributes = {}) {
113
- return HTML.#getElement(elName, text, attributes, true);
112
+ return HTML.#getElement(elName, text.toString(), attributes, true);
114
113
  }
115
114
 
116
115
  /**
117
116
  * @param {string} elName
118
- * @param {string} text
117
+ * @param {string|number} text
119
118
  * @param {string|Object<string,string>|undefined} [attributes]
120
119
  */
121
120
  static wrap(elName, text, attributes) {
122
- return HTML.#getElement(elName, text, attributes, false);
121
+ return HTML.#getElement(elName, text.toString(), attributes, false);
123
122
  }
124
123
  }