@ca-plant-list/ca-plant-list 0.3.7 → 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 (69) hide show
  1. package/.vscode/settings.json +7 -1
  2. package/data/synonyms.csv +85 -2
  3. package/data/taxa.csv +38 -16
  4. package/data/text/Antennaria-media.md +1 -0
  5. package/data/text/Antennaria-rosea-subsp-rosea.md +1 -0
  6. package/data/text/Camassia-leichtlinii-subsp-suksdorfii.md +1 -0
  7. package/data/text/Camassia-quamash-subsp-breviflora.md +1 -0
  8. package/data/text/Delphinium-glaucum.md +1 -0
  9. package/data/text/Delphinium-nuttallianum.md +1 -0
  10. package/data/text/Drymocallis-glandulosa-var-glandulosa.md +1 -0
  11. package/data/text/Drymocallis-lactea-var-austiniae.md +1 -0
  12. package/data/text/Erigeron-compositus.md +1 -0
  13. package/data/text/Erigeron-glacialis-var-glacialis.md +1 -0
  14. package/data/text/Erythranthe-breweri.md +1 -0
  15. package/data/text/Erythranthe-erubescens.md +1 -0
  16. package/data/text/Navarretia-leptalea-subsp-bicolor.md +1 -0
  17. package/data/text/Navarretia-leptalea-subsp-leptalea.md +1 -0
  18. package/data/text/Polemonium-californicum.md +1 -0
  19. package/data/text/Polemonium-pulcherrimum-var-pulcherrimum.md +1 -0
  20. package/data/text/Primula-jeffreyi.md +1 -0
  21. package/data/text/Primula-tetrandra.md +1 -0
  22. package/lib/basepagerenderer.js +3 -4
  23. package/lib/config.js +42 -19
  24. package/lib/csv.js +54 -36
  25. package/lib/ebook/ebook.js +84 -57
  26. package/lib/ebook/ebookpage.js +22 -11
  27. package/lib/ebook/ebooksitegenerator.js +36 -14
  28. package/lib/ebook/glossarypages.js +20 -17
  29. package/lib/ebook/images.js +13 -5
  30. package/lib/ebook/pages/page_list_families.js +0 -2
  31. package/lib/ebook/pages/page_list_flower_color.js +14 -9
  32. package/lib/ebook/pages/page_list_flowers.js +59 -41
  33. package/lib/ebook/pages/taxonpage.js +1 -1
  34. package/lib/ebook/pages/tocpage.js +26 -20
  35. package/lib/ebook/plantbook.js +6 -13
  36. package/lib/ebook/{image.js → taxonimage.js} +2 -2
  37. package/lib/exceptions.js +42 -26
  38. package/lib/externalsites.js +11 -4
  39. package/lib/families.js +10 -8
  40. package/lib/flowercolor.js +42 -0
  41. package/lib/genera.js +13 -21
  42. package/lib/genericpage.js +12 -0
  43. package/lib/html.js +11 -23
  44. package/lib/htmltaxon.js +89 -6
  45. package/lib/index.d.ts +54 -0
  46. package/lib/index.js +2 -30
  47. package/lib/jekyll.js +49 -21
  48. package/lib/jepson.js +7 -8
  49. package/lib/markdown.js +6 -0
  50. package/lib/pagerenderer.js +43 -8
  51. package/lib/plants/glossary.js +5 -0
  52. package/lib/program.js +47 -0
  53. package/lib/rareplants.js +44 -30
  54. package/lib/sitegenerator.js +41 -24
  55. package/lib/taxa.js +20 -134
  56. package/lib/taxon.js +1 -1
  57. package/lib/web/glossarypages.js +6 -0
  58. package/lib/web/pagetaxon.js +1 -5
  59. package/package.json +6 -3
  60. package/schemas/exceptions.schema.json +57 -0
  61. package/scripts/build-ebook.js +38 -47
  62. package/scripts/build-site.js +25 -14
  63. package/types/classes.d.ts +136 -8
  64. package/lib/commandandtaxaprocessor.js +0 -25
  65. package/lib/commandprocessor.js +0 -108
  66. package/lib/generictaxaloader.js +0 -48
  67. package/lib/taxaloader.js +0 -50
  68. package/lib/taxaprocessor.js +0 -34
  69. /package/data/text/{Calyptridium-ubellatum.md → Calyptridium-umbellatum.md} +0 -0
package/lib/genera.js CHANGED
@@ -6,7 +6,6 @@ class Genera {
6
6
  #genera;
7
7
 
8
8
  /**
9
- *
10
9
  * @param {Families} families
11
10
  */
12
11
  constructor(families) {
@@ -22,21 +21,17 @@ class Genera {
22
21
  const genusName = taxon.getGenusName();
23
22
  const genusData = this.#genera[genusName];
24
23
  if (!genusData) {
25
- console.log(taxon.getName() + " genus not found");
26
- return;
24
+ throw new Error(taxon.getName() + " genus not found");
27
25
  }
28
26
 
29
- if (genusData.taxa === undefined) {
27
+ if (genusData.familyObj === undefined) {
28
+ // Initialize genus data.
29
+ genusData.familyObj = this.#families.getFamily(genusData.family);
30
30
  genusData.taxa = [];
31
31
  }
32
- genusData.taxa.push(taxon);
32
+ genusData.familyObj.addTaxon(taxon);
33
33
 
34
- const family = this.getFamily(genusName);
35
- if (!family) {
36
- console.log(taxon.getName() + " family not found");
37
- return;
38
- }
39
- family.addTaxon(taxon);
34
+ genusData.taxa.push(taxon);
40
35
  }
41
36
 
42
37
  /**
@@ -45,25 +40,22 @@ class Genera {
45
40
  getGenus(genusName) {
46
41
  return new Genus(this.#genera[genusName]);
47
42
  }
48
-
49
- /**
50
- * @param {string} genusName
51
- */
52
- getFamily(genusName) {
53
- const genus = this.#genera[genusName];
54
- if (genus) {
55
- return this.#families.getFamily(genus.family);
56
- }
57
- }
58
43
  }
59
44
 
60
45
  class Genus {
61
46
  #data;
62
47
 
48
+ /**
49
+ * @param {{family:string,familyObj:Family,taxa:Taxon[]}} data
50
+ */
63
51
  constructor(data) {
64
52
  this.#data = data;
65
53
  }
66
54
 
55
+ getFamily() {
56
+ return this.#data.familyObj;
57
+ }
58
+
67
59
  getTaxa() {
68
60
  return this.#data.taxa.sort((a, b) =>
69
61
  a.getName().localeCompare(b.getName())
@@ -10,6 +10,12 @@ class GenericPage {
10
10
  #baseFileName;
11
11
  #js;
12
12
 
13
+ /**
14
+ * @param {string} outputDir
15
+ * @param {string} title
16
+ * @param {string} baseFileName
17
+ * @param {string} [js]
18
+ */
13
19
  constructor(outputDir, title, baseFileName, js) {
14
20
  this.#outputDir = outputDir;
15
21
  this.#title = title;
@@ -53,6 +59,9 @@ class GenericPage {
53
59
  return html;
54
60
  }
55
61
 
62
+ /**
63
+ * @param {string} path
64
+ */
56
65
  #getMarkdown(path) {
57
66
  const textPath = path + "/" + this.#baseFileName + ".md";
58
67
  if (!Jekyll.hasInclude(this.#outputDir, textPath)) {
@@ -69,6 +78,9 @@ class GenericPage {
69
78
  return this.#title;
70
79
  }
71
80
 
81
+ /**
82
+ * @param {string} html
83
+ */
72
84
  writeFile(html) {
73
85
  Files.write(this.#outputDir + "/" + this.#baseFileName + ".html", html);
74
86
  }
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(">", ">");
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,21 +1,68 @@
1
1
  import { DateUtils } from "./dateutils.js";
2
2
  import { HTML } from "./html.js";
3
+ import { RarePlants } from "./rareplants.js";
3
4
  import { TextUtils } from "./textutils.js";
4
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
+
5
45
  class HTMLTaxon {
6
46
  /**
7
- * @param {string[]} colors
47
+ * @param {string[]|undefined} colors
8
48
  */
9
- static getFlowerColors(colors) {
49
+ static getFlowerColors(colors, includeColorLink = true) {
10
50
  let html = "";
11
51
  if (colors) {
12
52
  for (const color of colors) {
13
- html += HTML.textElement("img", "", {
53
+ const img = HTML.textElement("img", "", {
14
54
  src: "./i/f-" + color + ".svg",
15
55
  alt: color + " flowers",
16
56
  title: color,
17
57
  class: "flr-color",
18
58
  });
59
+ if (includeColorLink) {
60
+ html += HTML.wrap("a", img, {
61
+ href: "./list_fc_" + color + ".html",
62
+ });
63
+ } else {
64
+ html += img;
65
+ }
19
66
  }
20
67
  }
21
68
  return html;
@@ -24,8 +71,13 @@ class HTMLTaxon {
24
71
  /**
25
72
  * @param {Taxon} taxon
26
73
  * @param {string} classNames
74
+ * @param {boolean} [includeColorLink=true]
27
75
  */
28
- static getFlowerInfo(taxon, classNames = "section") {
76
+ static getFlowerInfo(
77
+ taxon,
78
+ classNames = "section",
79
+ includeColorLink = true
80
+ ) {
29
81
  const lifeCycle = taxon.getLifeCycle();
30
82
  const colors = taxon.getFlowerColors();
31
83
  const monthStart = taxon.getBloomStart();
@@ -40,7 +92,7 @@ class HTMLTaxon {
40
92
 
41
93
  if (colors || monthStart) {
42
94
  let html = "Flowers: ";
43
- html += this.getFlowerColors(colors);
95
+ html += this.getFlowerColors(colors, includeColorLink);
44
96
  if (monthStart && monthEnd) {
45
97
  html += HTML.wrap(
46
98
  "span",
@@ -64,6 +116,37 @@ class HTMLTaxon {
64
116
  this.getFlowerColors(taxon.getFlowerColors())
65
117
  );
66
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
+ }
67
150
  }
68
151
 
69
- 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
+ }
package/lib/index.js CHANGED
@@ -1,58 +1,30 @@
1
- /**
2
- * @typedef {{
3
- * bloom_end:string;
4
- * bloom_start:string;
5
- * calrecnum:string;
6
- * CESA:string;
7
- * CRPR:string;
8
- * "common name":string;
9
- * FESA:string;
10
- * flower_color:string;
11
- * GRank:string;
12
- * "inat id":string;
13
- * "jepson id":string;
14
- * life_cycle:"annual"|"perennial"|undefined
15
- * SRank:string;
16
- * status:string;
17
- * "RPI ID":string;
18
- * taxon_name:string}} TaxonData
19
- */
20
-
21
1
  import { BasePageRenderer } from "./basepagerenderer.js";
22
- import { CommandProcessor } from "./commandprocessor.js";
23
- import { CommandAndTaxaProcessor } from "./commandandtaxaprocessor.js";
24
2
  import { Config } from "./config.js";
25
3
  import { CSV } from "./csv.js";
26
4
  import { ErrorLog } from "./errorlog.js";
27
5
  import { Exceptions } from "./exceptions.js";
28
6
  import { Families } from "./families.js";
29
7
  import { Files } from "./files.js";
30
- import { GenericTaxaLoader } from "./generictaxaloader.js";
31
8
  import { HTML } from "./html.js";
32
9
  import { Jekyll } from "./jekyll.js";
33
10
  import { PlantBook } from "./ebook/plantbook.js";
11
+ import { Program } from "./program.js";
34
12
  import { Taxa } from "./taxa.js";
35
- import { TaxaLoader } from "./taxaloader.js";
36
- import { TaxaProcessor } from "./taxaprocessor.js";
37
13
  import { Taxon, TAXA_COLNAMES } from "./taxon.js";
38
14
 
39
15
  export {
40
16
  BasePageRenderer,
41
- CommandProcessor,
42
- CommandAndTaxaProcessor,
43
17
  Config,
44
18
  CSV,
45
19
  ErrorLog,
46
20
  Exceptions,
47
21
  Families,
48
22
  Files,
49
- GenericTaxaLoader,
50
23
  HTML,
51
24
  Jekyll,
52
25
  PlantBook,
26
+ Program,
53
27
  Taxa,
54
- TaxaLoader,
55
- TaxaProcessor,
56
28
  TAXA_COLNAMES,
57
29
  Taxon,
58
30
  };
package/lib/jekyll.js CHANGED
@@ -4,40 +4,68 @@ import { SiteGenerator } from "./sitegenerator.js";
4
4
  const FRONT_DELIM = "---";
5
5
 
6
6
  class Jekyll extends SiteGenerator {
7
-
8
- constructor( baseDir ) {
9
- super( baseDir );
7
+ /**
8
+ * @param {string} baseDir
9
+ */
10
+ constructor(baseDir) {
11
+ super(baseDir);
10
12
  }
11
13
 
12
- static getFrontMatter( atts ) {
13
- const lines = [ FRONT_DELIM ];
14
- for ( const [ k, v ] of Object.entries( atts ) ) {
15
- lines.push( k + ": \"" + v + "\"" );
14
+ /**
15
+ * @param {Object<string,string>} atts
16
+ */
17
+ static getFrontMatter(atts) {
18
+ const lines = [FRONT_DELIM];
19
+ for (const [k, v] of Object.entries(atts)) {
20
+ lines.push(k + ': "' + v + '"');
16
21
  }
17
- if ( !atts.layout ) {
18
- lines.push( "layout: default" );
22
+ if (!atts.layout) {
23
+ lines.push("layout: default");
19
24
  }
20
- lines.push( FRONT_DELIM );
21
- return lines.join( "\n" ) + "\n";
25
+ lines.push(FRONT_DELIM);
26
+ return lines.join("\n") + "\n";
22
27
  }
23
28
 
24
- static hasInclude( baseDir, path ) {
25
- return Files.exists( baseDir + "/_includes/" + path );
29
+ /**
30
+ * @param {string} baseDir
31
+ * @param {string} path
32
+ */
33
+ static hasInclude(baseDir, path) {
34
+ return Files.exists(baseDir + "/_includes/" + path);
26
35
  }
27
36
 
28
- static include( path ) {
37
+ /**
38
+ * @param {string} path
39
+ */
40
+ static include(path) {
29
41
  // This works for .md includes; should have conditional logic to detect other types.
30
- return "{% capture my_include %}{% include " + path + " %}{% endcapture %}{{ my_include | markdownify }}";
42
+ return (
43
+ "{% capture my_include %}{% include " +
44
+ path +
45
+ " %}{% endcapture %}{{ my_include | markdownify }}"
46
+ );
31
47
  }
32
48
 
33
- static writeInclude( baseDir, path, data ) {
34
- Files.write( baseDir + "/_includes/" + path, data );
49
+ /**
50
+ * @param {string} baseDir
51
+ * @param {string} path
52
+ * @param {string} data
53
+ */
54
+ static writeInclude(baseDir, path, data) {
55
+ Files.write(baseDir + "/_includes/" + path, data);
35
56
  }
36
57
 
37
- writeTemplate( content, attributes, filename ) {
38
- Files.write( Files.join( this.getBaseDir(), filename ), Jekyll.getFrontMatter( attributes ) + content );
58
+ /**
59
+ * @param {string} content
60
+ * @param {Object<string,string>} attributes
61
+ * @param {string} filename
62
+ */
63
+ writeTemplate(content, attributes, filename) {
64
+ Files.write(
65
+ Files.join(this.getBaseDir(), filename),
66
+ Jekyll.getFrontMatter(attributes) + content
67
+ );
39
68
  }
40
-
41
69
  }
42
70
 
43
- export { Jekyll };
71
+ export { Jekyll };
package/lib/jepson.js CHANGED
@@ -1,18 +1,17 @@
1
- import { HTML, HTML_OPTIONS } from "./html.js";
1
+ import { HTML } from "./html.js";
2
2
 
3
3
  class Jepson {
4
-
5
- static getEFloraLink( id ) {
6
-
4
+ /**
5
+ * @param {string} id
6
+ */
7
+ static getEFloraLink(id) {
7
8
  return HTML.getLink(
8
9
  "https://ucjeps.berkeley.edu/eflora/eflora_display.php?tid=" + id,
9
10
  "Jepson eFlora",
10
11
  {},
11
- HTML_OPTIONS.OPEN_NEW
12
+ true
12
13
  );
13
-
14
14
  }
15
-
16
15
  }
17
16
 
18
- export { Jepson };
17
+ export { Jepson };
package/lib/markdown.js CHANGED
@@ -4,10 +4,16 @@ import { Files } from "./files.js";
4
4
  class Markdown {
5
5
  static #md = new markdownIt({ xhtmlOut: true });
6
6
 
7
+ /**
8
+ * @param {string} filePath
9
+ */
7
10
  static fileToHTML(filePath) {
8
11
  return this.strToHTML(Files.read(filePath));
9
12
  }
10
13
 
14
+ /**
15
+ * @param {string} str
16
+ */
11
17
  static strToHTML(str) {
12
18
  return this.#md.render(str);
13
19
  }
@@ -1,10 +1,10 @@
1
- import { Taxa, TAXA_LIST_COLS } from "./taxa.js";
2
1
  import { PageTaxon } from "./web/pagetaxon.js";
3
2
  import { RarePlants } from "./rareplants.js";
4
3
  import { BasePageRenderer } from "./basepagerenderer.js";
5
4
  import { GenericPage } from "./genericpage.js";
6
5
  import { Files } from "./files.js";
7
6
  import { HTML } from "./html.js";
7
+ import { HTMLTaxon, TAXA_LIST_COLS } from "./htmltaxon.js";
8
8
 
9
9
  const ENDANGERED_COLS = [
10
10
  TAXA_LIST_COLS.SPECIES,
@@ -19,8 +19,13 @@ const RPI_COLUMNS = [
19
19
  ];
20
20
 
21
21
  class PageRenderer extends BasePageRenderer {
22
+ /**
23
+ * @param {string} outputDir
24
+ * @param {Config} config
25
+ * @param {Taxa} taxa
26
+ */
22
27
  static render(outputDir, config, taxa) {
23
- super.render(outputDir, taxa);
28
+ super.renderBasePages(outputDir, taxa);
24
29
 
25
30
  this.renderLists(outputDir, config, taxa);
26
31
 
@@ -30,7 +35,18 @@ class PageRenderer extends BasePageRenderer {
30
35
  }
31
36
  }
32
37
 
38
+ /**
39
+ * @param {string} outputDir
40
+ * @param {Config} config
41
+ * @param {Taxa} taxa
42
+ */
33
43
  static renderLists(outputDir, config, taxa) {
44
+ /**
45
+ * @param {ListInfo[]} listInfo
46
+ * @param {Object<string,string>} attributes
47
+ * @param {TaxaCol[]} [columns]
48
+ * @returns {string}
49
+ */
34
50
  function getListArray(listInfo, attributes = {}, columns) {
35
51
  const listArray = [];
36
52
  for (const list of listInfo) {
@@ -81,10 +97,18 @@ class PageRenderer extends BasePageRenderer {
81
97
  return renderList(listArray, attributes);
82
98
  }
83
99
 
100
+ /**
101
+ * @param {string[]} listsHTML
102
+ * @param {Object<string,string>} attributes
103
+ */
84
104
  function renderList(listsHTML, attributes = {}) {
85
105
  return HTML.wrap("ul", HTML.arrayToLI(listsHTML), attributes);
86
106
  }
87
107
 
108
+ /**
109
+ * @param {string} title
110
+ * @param {string} listsHTML
111
+ */
88
112
  function renderSection(title, listsHTML) {
89
113
  let html = '<div class="section">';
90
114
  html += HTML.textElement("h2", title);
@@ -93,6 +117,8 @@ class PageRenderer extends BasePageRenderer {
93
117
  return html;
94
118
  }
95
119
 
120
+ /** @typedef {{name:string,filename:string,include:function(Taxon):boolean,columns?:TaxaCol[],listInfo?:ListInfo[]}} ListInfo */
121
+ /** @type {{title:string,listInfo:ListInfo[]}[]} */
96
122
  const sections = [
97
123
  {
98
124
  title: "All Species",
@@ -158,7 +184,9 @@ class PageRenderer extends BasePageRenderer {
158
184
  {
159
185
  name: "Endangered Species",
160
186
  filename: "list_endangered",
161
- include: (t) => t.getCESA() || t.getFESA(),
187
+ include: (t) =>
188
+ t.getCESA() !== undefined ||
189
+ t.getFESA() !== undefined,
162
190
  columns: ENDANGERED_COLS,
163
191
  },
164
192
  ],
@@ -167,10 +195,7 @@ class PageRenderer extends BasePageRenderer {
167
195
 
168
196
  let html = '<div class="wrapper">';
169
197
  for (const section of sections) {
170
- const listHTML = getListArray(
171
- section.listInfo,
172
- section.listInfo.columns
173
- );
198
+ const listHTML = getListArray(section.listInfo);
174
199
 
175
200
  if (listHTML.length > 0) {
176
201
  html += renderSection(section.title, listHTML);
@@ -189,17 +214,27 @@ class PageRenderer extends BasePageRenderer {
189
214
  }
190
215
 
191
216
  class PageTaxonList extends GenericPage {
217
+ /**
218
+ * @param {string} outputDir
219
+ * @param {string} title
220
+ * @param {string} baseName
221
+ */
192
222
  constructor(outputDir, title, baseName) {
193
223
  super(outputDir, title, baseName);
194
224
  }
195
225
 
226
+ /**
227
+ *
228
+ * @param {Taxon[]} taxa
229
+ * @param {TaxaCol[]|undefined} columns
230
+ */
196
231
  render(taxa, columns) {
197
232
  let html = this.getDefaultIntro();
198
233
 
199
234
  html += '<div class="wrapper">';
200
235
 
201
236
  html += '<div class="section">';
202
- html += Taxa.getHTMLTable(taxa, columns);
237
+ html += HTMLTaxon.getTaxaTable(taxa, columns);
203
238
  html += "</div>";
204
239
 
205
240
  html += '<div class="section">';