@ca-plant-list/ca-plant-list 0.3.6 → 0.4.0

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 (94) hide show
  1. package/.vscode/settings.json +7 -1
  2. package/data/synonyms.csv +109 -3
  3. package/data/taxa.csv +65 -29
  4. package/data/text/Antennaria-media.md +1 -0
  5. package/data/text/Antennaria-rosea-subsp-rosea.md +1 -0
  6. package/data/text/Antirrhinum-thompsonii.md +1 -0
  7. package/data/text/Calyptridium-monospermum.md +1 -0
  8. package/data/text/Calyptridium-umbellatum.md +1 -0
  9. package/data/text/Camassia-leichtlinii-subsp-suksdorfii.md +1 -0
  10. package/data/text/Camassia-quamash-subsp-breviflora.md +1 -0
  11. package/data/text/Clarkia-affinis.md +1 -0
  12. package/data/text/Clarkia-breweri.md +1 -0
  13. package/data/text/Clarkia-concinna-subsp-automixa.md +1 -0
  14. package/data/text/Clarkia-modesta.md +1 -0
  15. package/data/text/Clarkia-purpurea-subsp-quadrivulnera.md +1 -0
  16. package/data/text/Clarkia-rubicunda.md +1 -0
  17. package/data/text/Delphinium-californicum-subsp-californicum.md +1 -1
  18. package/data/text/Delphinium-californicum-subsp-interius.md +1 -0
  19. package/data/text/Delphinium-glaucum.md +1 -0
  20. package/data/text/Delphinium-hesperium-subsp-hesperium.md +1 -1
  21. package/data/text/Delphinium-hesperium-subsp-pallescens.md +1 -0
  22. package/data/text/Delphinium-nuttallianum.md +1 -0
  23. package/data/text/Delphinium-parryi-subsp-parryi.md +1 -0
  24. package/data/text/Drymocallis-glandulosa-var-glandulosa.md +1 -0
  25. package/data/text/Drymocallis-lactea-var-austiniae.md +1 -0
  26. package/data/text/Erigeron-compositus.md +1 -0
  27. package/data/text/Erigeron-glacialis-var-glacialis.md +1 -0
  28. package/data/text/Erythranthe-breweri.md +1 -0
  29. package/data/text/Erythranthe-erubescens.md +1 -0
  30. package/data/text/Erythranthe-moschata.md +1 -0
  31. package/data/text/Erythranthe-primuloides.md +1 -0
  32. package/data/text/Erythranthe-tilingii.md +1 -0
  33. package/data/text/Lilium-pardalinum-subsp-shastense.md +1 -0
  34. package/data/text/Logfia-filaginoides.md +1 -0
  35. package/data/text/Logfia-gallica.md +1 -0
  36. package/data/text/Malacothamnus-arcuatus-var-elmeri.md +1 -0
  37. package/data/text/Malacothamnus-fremontii-var-fremontii.md +1 -0
  38. package/data/text/Navarretia-leptalea-subsp-bicolor.md +1 -0
  39. package/data/text/Navarretia-leptalea-subsp-leptalea.md +1 -0
  40. package/data/text/Polemonium-californicum.md +1 -0
  41. package/data/text/Polemonium-pulcherrimum-var-pulcherrimum.md +1 -0
  42. package/data/text/Primula-jeffreyi.md +1 -0
  43. package/data/text/Primula-tetrandra.md +1 -0
  44. package/data/text/Trifolium-obtusiflorum.md +1 -0
  45. package/data/text/Trifolium-willdenovii.md +1 -0
  46. package/lib/basepagerenderer.js +3 -4
  47. package/lib/config.js +42 -19
  48. package/lib/csv.js +54 -36
  49. package/lib/ebook/ebook.js +84 -57
  50. package/lib/ebook/ebookpage.js +22 -11
  51. package/lib/ebook/ebooksitegenerator.js +36 -14
  52. package/lib/ebook/glossarypages.js +20 -17
  53. package/lib/ebook/images.js +59 -42
  54. package/lib/ebook/pages/page_list_families.js +0 -2
  55. package/lib/ebook/pages/page_list_flower_color.js +14 -9
  56. package/lib/ebook/pages/page_list_flowers.js +59 -41
  57. package/lib/ebook/pages/page_list_species.js +15 -9
  58. package/lib/ebook/pages/taxonpage.js +3 -6
  59. package/lib/ebook/pages/tocpage.js +26 -20
  60. package/lib/ebook/plantbook.js +6 -13
  61. package/lib/ebook/{image.js → taxonimage.js} +2 -2
  62. package/lib/ebook/xhtml.js +3 -5
  63. package/lib/exceptions.js +42 -26
  64. package/lib/externalsites.js +11 -4
  65. package/lib/families.js +10 -10
  66. package/lib/flowercolor.js +42 -0
  67. package/lib/genera.js +13 -23
  68. package/lib/genericpage.js +38 -18
  69. package/lib/html.js +11 -23
  70. package/lib/htmltaxon.js +114 -14
  71. package/lib/index.d.ts +54 -0
  72. package/lib/index.js +2 -30
  73. package/lib/jekyll.js +49 -21
  74. package/lib/jepson.js +7 -8
  75. package/lib/markdown.js +13 -9
  76. package/lib/pagerenderer.js +162 -82
  77. package/lib/plants/glossary.js +14 -14
  78. package/lib/program.js +47 -0
  79. package/lib/rareplants.js +44 -30
  80. package/lib/sitegenerator.js +41 -24
  81. package/lib/taxa.js +25 -142
  82. package/lib/taxon.js +3 -5
  83. package/lib/web/glossarypages.js +37 -18
  84. package/lib/web/pagetaxon.js +1 -5
  85. package/package.json +5 -3
  86. package/schemas/exceptions.schema.json +57 -0
  87. package/scripts/build-ebook.js +39 -48
  88. package/scripts/build-site.js +49 -28
  89. package/types/classes.d.ts +154 -0
  90. package/lib/commandandtaxaprocessor.js +0 -25
  91. package/lib/commandprocessor.js +0 -108
  92. package/lib/generictaxaloader.js +0 -48
  93. package/lib/taxaloader.js +0 -48
  94. package/lib/taxaprocessor.js +0 -34
package/lib/exceptions.js CHANGED
@@ -2,55 +2,71 @@ import { Config } from "./config.js";
2
2
  import { Files } from "./files.js";
3
3
 
4
4
  class Exceptions {
5
-
5
+ /** @type {Object<string,Object<string,Object<string,{}>>>} */
6
6
  #exceptions = {};
7
7
 
8
- constructor( dir ) {
9
-
10
- function readConfig( fileName ) {
11
- return JSON.parse( Files.read( fileName ) );
8
+ /**
9
+ * @param {string} dir
10
+ */
11
+ constructor(dir) {
12
+ /**
13
+ * @param {string} fileName
14
+ */
15
+ function readConfig(fileName) {
16
+ return JSON.parse(Files.read(fileName));
12
17
  }
13
18
 
14
19
  // Read default configuration.
15
- this.#exceptions = readConfig( Config.getPackageDir() + "/data/exceptions.json" );
20
+ this.#exceptions = readConfig(
21
+ Config.getPackageDir() + "/data/exceptions.json"
22
+ );
16
23
 
17
24
  // Add/overwrite with local configuration.
18
- const localExceptions = readConfig( dir + "/exceptions.json" );
19
- for ( const [ k, v ] of Object.entries( localExceptions ) ) {
20
- this.#exceptions[ k ] = v;
25
+ const localExceptions = readConfig(dir + "/exceptions.json");
26
+ for (const [k, v] of Object.entries(localExceptions)) {
27
+ this.#exceptions[k] = v;
21
28
  // Tag as a local exception so we can distinguish between global and local.
22
29
  v.local = true;
23
30
  }
24
-
25
31
  }
26
32
 
27
33
  getExceptions() {
28
- return Object.entries( this.#exceptions );
34
+ return Object.entries(this.#exceptions);
29
35
  }
30
36
 
31
- getValue( name, cat, subcat, defaultValue ) {
32
- const taxonData = this.#exceptions[ name ];
33
- if ( taxonData ) {
34
- const catData = taxonData[ cat ];
35
- if ( catData ) {
36
- const val = catData[ subcat ];
37
- return ( val === undefined ) ? defaultValue : val;
37
+ /**
38
+ * @param {string} name
39
+ * @param {string} cat
40
+ * @param {string} subcat
41
+ * @param {string} defaultValue
42
+ */
43
+ getValue(name, cat, subcat, defaultValue) {
44
+ const taxonData = this.#exceptions[name];
45
+ if (taxonData) {
46
+ const catData = taxonData[cat];
47
+ if (catData) {
48
+ const val = catData[subcat];
49
+ return val === undefined ? defaultValue : val;
38
50
  }
39
51
  }
40
52
  return defaultValue;
41
53
  }
42
54
 
43
- hasException( name, cat, subcat ) {
44
- const taxonData = this.#exceptions[ name ];
45
- if ( taxonData ) {
46
- const catData = taxonData[ cat ];
47
- if ( catData ) {
48
- return catData[ subcat ] !== undefined;
55
+ /**
56
+ * @param {string} name
57
+ * @param {string} cat
58
+ * @param {string} subcat
59
+ */
60
+ hasException(name, cat, subcat) {
61
+ const taxonData = this.#exceptions[name];
62
+ if (taxonData) {
63
+ const catData = taxonData[cat];
64
+ if (catData) {
65
+ return catData[subcat] !== undefined;
49
66
  }
50
67
  }
51
68
  return false;
52
69
  }
53
-
54
70
  }
55
71
 
56
- export { Exceptions };
72
+ export { Exceptions };
@@ -1,4 +1,7 @@
1
1
  class ExternalSites {
2
+ /**
3
+ * @param {InatObsOptions} options
4
+ */
2
5
  static getInatObsLink(options) {
3
6
  const url = new URL(
4
7
  "https://www.inaturalist.org/observations?subview=map"
@@ -9,10 +12,14 @@ class ExternalSites {
9
12
  case "coords": {
10
13
  const delta = 0.1;
11
14
  const params = url.searchParams;
12
- params.set("nelat", v[1] + delta);
13
- params.set("swlat", v[1] - delta);
14
- params.set("nelng", v[0] + delta);
15
- params.set("swlng", v[0] - delta);
15
+ /** @type {number} */
16
+ const lat = v[1];
17
+ /** @type {number} */
18
+ const lng = v[0];
19
+ params.set("nelat", (lat + delta).toString());
20
+ params.set("swlat", (lat - delta).toString());
21
+ params.set("nelng", (lng + delta).toString());
22
+ params.set("swlng", (lng - delta).toString());
16
23
  break;
17
24
  }
18
25
  case "created_d1":
package/lib/families.js CHANGED
@@ -1,11 +1,9 @@
1
1
  import { GenericPage } from "./genericpage.js";
2
2
  import { HTML } from "./html.js";
3
3
  import { Jepson } from "./jepson.js";
4
- import { Taxa } from "./taxa.js";
5
4
  import { Files } from "./files.js";
6
5
  import { Config } from "./config.js";
7
- // eslint-disable-next-line no-unused-vars
8
- import { Taxon } from "./index.js";
6
+ import { HTMLTaxon } from "./htmltaxon.js";
9
7
 
10
8
  class Family {
11
9
  #name;
@@ -83,7 +81,7 @@ class Families {
83
81
 
84
82
  /**
85
83
  * @param {string} outputDir
86
- * @param {import("./index.js").TaxaCol[]} taxaColumns
84
+ * @param {TaxaCol[]} taxaColumns
87
85
  */
88
86
  renderPages(outputDir, taxaColumns) {
89
87
  new PageFamilyList(outputDir, this.#families).render(taxaColumns);
@@ -111,7 +109,7 @@ class PageFamilyList extends GenericPage {
111
109
  }
112
110
 
113
111
  /**
114
- * @param {import("./index.js").TaxaCol[]} taxaColumns
112
+ * @param {TaxaCol[]} taxaColumns
115
113
  */
116
114
  render(taxaColumns) {
117
115
  let html = this.getDefaultIntro();
@@ -178,8 +176,7 @@ class PageFamily extends GenericPage {
178
176
  }
179
177
 
180
178
  /**
181
- *
182
- * @param {import("./index.js").TaxaCol[]} columns
179
+ * @param {TaxaCol[]} columns
183
180
  */
184
181
  render(columns) {
185
182
  let html = this.getDefaultIntro();
@@ -190,7 +187,7 @@ class PageFamily extends GenericPage {
190
187
  { class: "section" }
191
188
  );
192
189
 
193
- html += Taxa.getHTMLTable(this.#family.getTaxa(), columns);
190
+ html += HTMLTaxon.getTaxaTable(this.#family.getTaxa(), columns);
194
191
 
195
192
  this.writeFile(html);
196
193
  }
@@ -209,17 +206,20 @@ class PageSection extends GenericPage {
209
206
  this.#taxa = taxa;
210
207
  }
211
208
 
209
+ /**
210
+ * @param {TaxaCol[]} [columns]
211
+ */
212
212
  render(columns) {
213
213
  let html = this.getDefaultIntro();
214
214
 
215
- html += Taxa.getHTMLTable(this.#taxa, columns);
215
+ html += HTMLTaxon.getTaxaTable(this.#taxa, columns);
216
216
 
217
217
  this.writeFile(html);
218
218
  }
219
219
  }
220
220
 
221
221
  class Sections {
222
- /** @type {Object<string,Taxon[]} */
222
+ /** @type {Object<string,Taxon[]>} */
223
223
  static #sections = {};
224
224
 
225
225
  /**
@@ -0,0 +1,42 @@
1
+ import { TextUtils } from "./textutils.js";
2
+
3
+ class FlowerColor {
4
+ #colorName;
5
+ #colorCode;
6
+ /** @type {Taxon[]} */
7
+ #taxa = [];
8
+
9
+ /**
10
+ * @param {string} colorName
11
+ * @param {string} [colorCode]
12
+ */
13
+ constructor(colorName, colorCode) {
14
+ this.#colorName = colorName;
15
+ this.#colorCode = colorCode ? colorCode : colorName;
16
+ }
17
+
18
+ /**
19
+ * @param {Taxon} taxon
20
+ */
21
+ addTaxon(taxon) {
22
+ this.#taxa.push(taxon);
23
+ }
24
+
25
+ getColorCode() {
26
+ return this.#colorCode;
27
+ }
28
+
29
+ getColorName(uc = false) {
30
+ return uc ? TextUtils.ucFirst(this.#colorName) : this.#colorName;
31
+ }
32
+
33
+ getFileName() {
34
+ return "list_fc_" + this.#colorName + ".html";
35
+ }
36
+
37
+ getTaxa() {
38
+ return this.#taxa;
39
+ }
40
+ }
41
+
42
+ export { FlowerColor };
package/lib/genera.js CHANGED
@@ -1,8 +1,5 @@
1
1
  import { Config } from "./config.js";
2
- import { Families } from "./families.js";
3
2
  import { Files } from "./files.js";
4
- // eslint-disable-next-line no-unused-vars
5
- import { Taxon } from "./taxon.js";
6
3
 
7
4
  class Genera {
8
5
  #families;
@@ -24,21 +21,17 @@ class Genera {
24
21
  const genusName = taxon.getGenusName();
25
22
  const genusData = this.#genera[genusName];
26
23
  if (!genusData) {
27
- console.log(taxon.getName() + " genus not found");
28
- return;
24
+ throw new Error(taxon.getName() + " genus not found");
29
25
  }
30
26
 
31
- if (genusData.taxa === undefined) {
27
+ if (genusData.familyObj === undefined) {
28
+ // Initialize genus data.
29
+ genusData.familyObj = this.#families.getFamily(genusData.family);
32
30
  genusData.taxa = [];
33
31
  }
34
- genusData.taxa.push(taxon);
32
+ genusData.familyObj.addTaxon(taxon);
35
33
 
36
- const family = this.getFamily(genusName);
37
- if (!family) {
38
- console.log(taxon.getName() + " family not found");
39
- return;
40
- }
41
- family.addTaxon(taxon);
34
+ genusData.taxa.push(taxon);
42
35
  }
43
36
 
44
37
  /**
@@ -47,25 +40,22 @@ class Genera {
47
40
  getGenus(genusName) {
48
41
  return new Genus(this.#genera[genusName]);
49
42
  }
50
-
51
- /**
52
- * @param {string} genusName
53
- */
54
- getFamily(genusName) {
55
- const genus = this.#genera[genusName];
56
- if (genus) {
57
- return this.#families.getFamily(genus.family);
58
- }
59
- }
60
43
  }
61
44
 
62
45
  class Genus {
63
46
  #data;
64
47
 
48
+ /**
49
+ * @param {{family:string,familyObj:Family,taxa:Taxon[]}} data
50
+ */
65
51
  constructor(data) {
66
52
  this.#data = data;
67
53
  }
68
54
 
55
+ getFamily() {
56
+ return this.#data.familyObj;
57
+ }
58
+
69
59
  getTaxa() {
70
60
  return this.#data.taxa.sort((a, b) =>
71
61
  a.getName().localeCompare(b.getName())
@@ -1,14 +1,22 @@
1
- import { Config, Files, HTML, Jekyll } from "@ca-plant-list/ca-plant-list";
1
+ import { Config } from "./config.js";
2
+ import { Files } from "./files.js";
3
+ import { HTML } from "./html.js";
4
+ import { Jekyll } from "./jekyll.js";
2
5
  import { Markdown } from "./markdown.js";
3
6
 
4
7
  class GenericPage {
5
-
6
8
  #outputDir;
7
9
  #title;
8
10
  #baseFileName;
9
11
  #js;
10
12
 
11
- constructor( outputDir, title, baseFileName, js ) {
13
+ /**
14
+ * @param {string} outputDir
15
+ * @param {string} title
16
+ * @param {string} baseFileName
17
+ * @param {string} [js]
18
+ */
19
+ constructor(outputDir, title, baseFileName, js) {
12
20
  this.#outputDir = outputDir;
13
21
  this.#title = title;
14
22
  this.#baseFileName = baseFileName;
@@ -25,31 +33,41 @@ class GenericPage {
25
33
  }
26
34
 
27
35
  getFrontMatter() {
28
- return "---\n"
29
- + "title: \"" + this.#title + "\"\n"
30
- + ( this.#js ? ( "js: " + this.#js + "\n" ) : "" )
31
- + "---\n";
36
+ return (
37
+ "---\n" +
38
+ 'title: "' +
39
+ this.#title +
40
+ '"\n' +
41
+ (this.#js ? "js: " + this.#js + "\n" : "") +
42
+ "---\n"
43
+ );
32
44
  }
33
45
 
34
46
  getMarkdown() {
35
47
  // Include site-specific markdown.
36
- let html = this.#getMarkdown( "intros" );
48
+ let html = this.#getMarkdown("intros");
37
49
 
38
50
  // Include package markdown.
39
- const mdPath = Config.getPackageDir() + "/data/text/" + this.#baseFileName + ".md";
40
- if ( Files.exists( mdPath ) ) {
41
- html += HTML.wrap( "div", Markdown.fileToHTML( mdPath ), { class: "section" } );
51
+ const mdPath =
52
+ Config.getPackageDir() + "/data/text/" + this.#baseFileName + ".md";
53
+ if (Files.exists(mdPath)) {
54
+ html += HTML.wrap("div", Markdown.fileToHTML(mdPath), {
55
+ class: "section",
56
+ });
42
57
  }
43
58
 
44
59
  return html;
45
60
  }
46
61
 
47
- #getMarkdown( path ) {
62
+ /**
63
+ * @param {string} path
64
+ */
65
+ #getMarkdown(path) {
48
66
  const textPath = path + "/" + this.#baseFileName + ".md";
49
- if ( !Jekyll.hasInclude( this.#outputDir, textPath ) ) {
67
+ if (!Jekyll.hasInclude(this.#outputDir, textPath)) {
50
68
  return "";
51
69
  }
52
- return HTML.wrap( "div", Jekyll.include( textPath ), { class: "section" } );
70
+ return HTML.wrap("div", Jekyll.include(textPath), { class: "section" });
53
71
  }
54
72
 
55
73
  getOutputDir() {
@@ -60,10 +78,12 @@ class GenericPage {
60
78
  return this.#title;
61
79
  }
62
80
 
63
- writeFile( html ) {
64
- Files.write( this.#outputDir + "/" + this.#baseFileName + ".html", html );
81
+ /**
82
+ * @param {string} html
83
+ */
84
+ writeFile(html) {
85
+ Files.write(this.#outputDir + "/" + this.#baseFileName + ".html", html);
65
86
  }
66
-
67
87
  }
68
88
 
69
- export { GenericPage };
89
+ export { GenericPage };
package/lib/html.js CHANGED
@@ -1,11 +1,3 @@
1
- /**
2
- * @deprecated
3
- */
4
- export const HTML_OPTIONS = {
5
- OPEN_NEW: 1,
6
- NO_ESCAPE: 2,
7
- };
8
-
9
1
  /** HTML utility functions. */
10
2
  export class HTML {
11
3
  /**
@@ -35,19 +27,6 @@ export class HTML {
35
27
  .replaceAll(">", "&gt;");
36
28
  }
37
29
 
38
- /**
39
- * @deprecated
40
- */
41
- static getElement(elName, text, attributes = {}, options = 0) {
42
- let html = "<" + elName;
43
- html += this.renderAttributes(attributes);
44
- if (!(options & HTML_OPTIONS.NO_ESCAPE)) {
45
- text = this.escapeText(text);
46
- }
47
- html += ">" + text + "</" + elName + ">";
48
- return html;
49
- }
50
-
51
30
  /**
52
31
  * @param {string} elName
53
32
  * @param {string} text
@@ -71,7 +50,7 @@ export class HTML {
71
50
  * Generate HTML for an &lt;a> element.
72
51
  * @param {string|undefined} href
73
52
  * @param {string} linkText
74
- * @param {Object} [attributes]
53
+ * @param {string|Object<string,string>} [attributes]
75
54
  * @param {boolean} [openInNewWindow] true if the link should open in a new window.
76
55
  * @returns {string} an HTML &lt;a> element.
77
56
  */
@@ -92,7 +71,7 @@ export class HTML {
92
71
  * @param {string} text - The text or HTML that should trigger the tooltip on hover.
93
72
  * @param {string} tooltip - The tooltip text or HTML.
94
73
  * @param {Object} options
95
- * @param {boolean} options.icon [true] display an icon after the text
74
+ * @param {boolean} [options.icon] [true] display an icon after the text
96
75
  * @returns {string} A &lt;span> element to be used as a Bootstrap tooltip.
97
76
  */
98
77
  static getToolTip(text, tooltip, options = {}) {
@@ -103,6 +82,10 @@ export class HTML {
103
82
  return func("span", text, { "data-bs-html": "true", title: tooltip });
104
83
  }
105
84
 
85
+ /**
86
+ * @param {string} n
87
+ * @param {string} v
88
+ */
106
89
  static renderAttribute(n, v) {
107
90
  return " " + n + '="' + this.escapeAttribute(v) + '"';
108
91
  }
@@ -121,6 +104,11 @@ export class HTML {
121
104
  return html;
122
105
  }
123
106
 
107
+ /**
108
+ * @param {string} elName
109
+ * @param {string} text
110
+ * @param {Object<string,string>} attributes
111
+ */
124
112
  static textElement(elName, text, attributes = {}) {
125
113
  return HTML.#getElement(elName, text, attributes, true);
126
114
  }
package/lib/htmltaxon.js CHANGED
@@ -1,15 +1,83 @@
1
1
  import { DateUtils } from "./dateutils.js";
2
2
  import { HTML } from "./html.js";
3
- // eslint-disable-next-line no-unused-vars
4
- import { Taxon } from "./taxon.js";
3
+ import { RarePlants } from "./rareplants.js";
5
4
  import { TextUtils } from "./textutils.js";
6
5
 
6
+ /**
7
+ * @type {Object<string,{title:string,data:function (Taxon):string}>}
8
+ */
9
+ const TAXA_LIST_COLS = {
10
+ CESA: {
11
+ title: "California",
12
+ data: (t) => RarePlants.getCESADescription(t.getCESA()),
13
+ },
14
+ COMMON_NAME: {
15
+ title: "Common Name",
16
+ data: (t) => t.getCommonNames().join(", "),
17
+ },
18
+ CNPS_RANK: {
19
+ title: "CNPS Rank",
20
+ data: (t) =>
21
+ HTML.getToolTip(
22
+ HTML.textElement("span", t.getRPIRankAndThreat()),
23
+ t.getRPIRankAndThreatTooltip()
24
+ ),
25
+ },
26
+ FESA: {
27
+ title: "Federal",
28
+ data: (t) => RarePlants.getFESADescription(t.getFESA()),
29
+ },
30
+ SPECIES: {
31
+ title: "Species",
32
+ data: (t) => t.getHTMLLink(true, true),
33
+ },
34
+ SPECIES_BARE: {
35
+ title: "Species",
36
+ data: (t) => t.getHTMLLink(true, false),
37
+ },
38
+ };
39
+
40
+ const DEFAULT_TAXA_COLUMNS = [
41
+ TAXA_LIST_COLS.SPECIES,
42
+ TAXA_LIST_COLS.COMMON_NAME,
43
+ ];
44
+
7
45
  class HTMLTaxon {
46
+ /**
47
+ * @param {string[]|undefined} colors
48
+ */
49
+ static getFlowerColors(colors, includeColorLink = true) {
50
+ let html = "";
51
+ if (colors) {
52
+ for (const color of colors) {
53
+ const img = HTML.textElement("img", "", {
54
+ src: "./i/f-" + color + ".svg",
55
+ alt: color + " flowers",
56
+ title: color,
57
+ class: "flr-color",
58
+ });
59
+ if (includeColorLink) {
60
+ html += HTML.wrap("a", img, {
61
+ href: "./list_fc_" + color + ".html",
62
+ });
63
+ } else {
64
+ html += img;
65
+ }
66
+ }
67
+ }
68
+ return html;
69
+ }
70
+
8
71
  /**
9
72
  * @param {Taxon} taxon
10
73
  * @param {string} classNames
74
+ * @param {boolean} [includeColorLink=true]
11
75
  */
12
- static getFlowerInfo(taxon, classNames = "section") {
76
+ static getFlowerInfo(
77
+ taxon,
78
+ classNames = "section",
79
+ includeColorLink = true
80
+ ) {
13
81
  const lifeCycle = taxon.getLifeCycle();
14
82
  const colors = taxon.getFlowerColors();
15
83
  const monthStart = taxon.getBloomStart();
@@ -24,16 +92,7 @@ class HTMLTaxon {
24
92
 
25
93
  if (colors || monthStart) {
26
94
  let html = "Flowers: ";
27
- if (colors) {
28
- for (const color of colors) {
29
- html += HTML.textElement("img", "", {
30
- src: "./i/f-" + color + ".svg",
31
- alt: color + " flowers",
32
- title: color,
33
- class: "flr-color",
34
- });
35
- }
36
- }
95
+ html += this.getFlowerColors(colors, includeColorLink);
37
96
  if (monthStart && monthEnd) {
38
97
  html += HTML.wrap(
39
98
  "span",
@@ -47,6 +106,47 @@ class HTMLTaxon {
47
106
  }
48
107
  return HTML.wrap("div", parts.join(""), { class: classNames });
49
108
  }
109
+
110
+ /**
111
+ * @param {Taxon} taxon
112
+ */
113
+ static getLink(taxon) {
114
+ return (
115
+ HTML.getLink(taxon.getFileName(), taxon.getName()) +
116
+ this.getFlowerColors(taxon.getFlowerColors())
117
+ );
118
+ }
119
+
120
+ /**
121
+ * @param {Taxon[]} taxa
122
+ * @param {TaxaCol[]} [columns]
123
+ */
124
+ static getTaxaTable(taxa, columns = DEFAULT_TAXA_COLUMNS) {
125
+ let html = "<table><thead>";
126
+ for (const col of columns) {
127
+ const className = col.class;
128
+ const atts = className !== undefined ? className : {};
129
+ html += HTML.textElement("th", col.title, atts);
130
+ }
131
+ html += "</thead>";
132
+ html += "<tbody>";
133
+
134
+ for (const taxon of taxa) {
135
+ html += "<tr>";
136
+ for (const col of columns) {
137
+ const data = col.data(taxon);
138
+ const className = col.class;
139
+ const atts = className !== undefined ? className : {};
140
+ html += HTML.wrap("td", data, atts);
141
+ }
142
+ html += "</tr>";
143
+ }
144
+
145
+ html += "</tbody>";
146
+ html += "</table>";
147
+
148
+ return html;
149
+ }
50
150
  }
51
151
 
52
- export { HTMLTaxon };
152
+ export { HTMLTaxon, TAXA_LIST_COLS };
package/lib/index.d.ts ADDED
@@ -0,0 +1,54 @@
1
+ import { Command } from "commander";
2
+
3
+ export class Config {
4
+ constructor(dataDir: string);
5
+ getConfigValue(
6
+ prefix: string,
7
+ name: string,
8
+ subcategory?: string,
9
+ defaultValue?: string
10
+ ): string;
11
+ getCountyCodes(): string[];
12
+ getLabel(name: string, dflt: string): string;
13
+ }
14
+
15
+ export class CSV {
16
+ static parseFile(dir: string, fileName: string);
17
+ }
18
+
19
+ export class ErrorLog {
20
+ constructor(fileName: string, echo?: boolean);
21
+ log(...msg: string[]);
22
+ write(): void;
23
+ }
24
+
25
+ export class Exceptions {
26
+ constructor(dataDir: string);
27
+ hasException(name: string, cat: string, subcat: string);
28
+ }
29
+
30
+ export class Files {
31
+ static exists(fileName: string): boolean;
32
+ static async fetch(url: string | URL, targetFileName: string | undefined);
33
+ static mkdir(dir: string);
34
+ static rmDir(dir: string);
35
+ static write(fileName: string, data: string, overwrite: boolean);
36
+ }
37
+
38
+ export class Program {
39
+ static getIncludeList(dataDir: string): string[];
40
+ static getProgram(): Command;
41
+ }
42
+
43
+ export class Taxa {
44
+ constructor(
45
+ inclusionList: Object<string, TaxonData> | true,
46
+ errorLog: ErrorLog,
47
+ showFlowerErrors: boolean,
48
+ taxonFactory?: (td: TaxonData, g: Genera) => Taxon,
49
+ extraTaxa?: TaxonData[],
50
+ extraSynonyms?: SynonymData[]
51
+ );
52
+ getTaxon(string): Taxon;
53
+ getTaxonList(): Taxon[];
54
+ }