@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
package/lib/htmltaxon.js CHANGED
@@ -1,20 +1,13 @@
1
1
  import { Config } from "./config.js";
2
2
  import { DateUtils } from "./dateutils.js";
3
+ import { ExternalSites } from "./externalsites.js";
3
4
  import { HTML } from "./html.js";
4
5
  import { Markdown } from "./markdown.js";
5
6
  import { RarePlants } from "./rareplants.js";
6
7
  import { TextUtils } from "./textutils.js";
7
8
 
8
9
  /**
9
- * @typedef {{
10
- class?: string;
11
- data: (taxon: import("./taxon.js").Taxon) => string;
12
- title: string;
13
- }} TaxaColDef
14
- */
15
-
16
- /**
17
- * @type {Record<string,TaxaColDef>}
10
+ * @type {Record<string,import("./types.js").TaxaColDef>}
18
11
  */
19
12
  const TAXA_LIST_COLS = {
20
13
  CESA: {
@@ -30,7 +23,7 @@ const TAXA_LIST_COLS = {
30
23
  data: (t) =>
31
24
  HTML.getToolTip(
32
25
  HTML.textElement("span", t.getRPIRankAndThreat()),
33
- t.getRPIRankAndThreatTooltip(),
26
+ HTMLTaxon.getRPIRankAndThreatTooltip(t),
34
27
  ),
35
28
  },
36
29
  FESA: {
@@ -39,49 +32,105 @@ const TAXA_LIST_COLS = {
39
32
  },
40
33
  SPECIES: {
41
34
  title: "Species",
42
- data: (t) => t.getHTMLLink(true, true),
35
+ data: (t) => HTMLTaxon.getHTMLLink(t, true, true),
43
36
  },
44
37
  SPECIES_BARE: {
45
38
  title: "Species",
46
- data: (t) => t.getHTMLLink(true, false),
39
+ data: (t) => HTMLTaxon.getHTMLLink(t, true, false),
47
40
  },
48
41
  };
49
42
 
50
- /** @type {TaxaColDef[]} */
43
+ /** @type {import("./types.js").TaxaColDef[]} */
51
44
  const DEFAULT_TAXA_COLUMNS = [
52
45
  TAXA_LIST_COLS.SPECIES,
53
46
  TAXA_LIST_COLS.COMMON_NAME,
54
47
  ];
55
48
 
49
+ /** @type {Object<string,{label:string,href:function(import("./types.js").Taxon,import("./types.js").Config):URL|undefined}>} */
50
+ const OBSLINKS = {
51
+ calflora: {
52
+ label: "Calflora",
53
+ href: (taxon, config) =>
54
+ ExternalSites.getCalfloraObsLink(taxon, config),
55
+ },
56
+ cch: {
57
+ label: "CCH2",
58
+ href: (taxon, config) => ExternalSites.getCCH2ObsLink(taxon, config),
59
+ },
60
+ inat: {
61
+ label: "iNaturalist",
62
+ href: (taxon, config) => ExternalSites.getInatObsLink(taxon, config),
63
+ },
64
+ };
65
+
66
+ /** @type {Object<string,{label:string,href:function(import("./types.js").Taxon):URL|undefined}>} */
67
+ const REFLINKS = {
68
+ calflora: {
69
+ label: "Calflora",
70
+ href: (taxon) => ExternalSites.getCalfloraRefLink(taxon),
71
+ },
72
+ calscape: {
73
+ label: "Calscape",
74
+ href: (taxon) => ExternalSites.getCalscapeLink(taxon),
75
+ },
76
+ cch: {
77
+ label: "CCH2",
78
+ href: (taxon) => ExternalSites.getCCH2RefLink(taxon),
79
+ },
80
+ fna: {
81
+ label: "Flora of North America",
82
+ href: (taxon) => ExternalSites.getFNARefLink(taxon),
83
+ },
84
+ inat: {
85
+ label: "iNaturalist",
86
+ href: (taxon) => ExternalSites.getINatRefLink(taxon),
87
+ },
88
+ jepson: {
89
+ label: "Jepson eFlora",
90
+ href: (taxon) => ExternalSites.getJepsonRefLink(taxon),
91
+ },
92
+ rpi: {
93
+ label: "CNPS Rare Plant Inventory",
94
+ href: (taxon) => ExternalSites.getRPIRefLink(taxon),
95
+ },
96
+ };
97
+
56
98
  class HTMLTaxon {
57
99
  /**
58
100
  * @param {string[]} links
59
101
  * @param {URL|string|undefined} href
60
102
  * @param {string} label
103
+ * @param {string} [suffix=""]
61
104
  */
62
- static addLink(links, href, label) {
105
+ static addLink(links, href, label, suffix = "") {
63
106
  if (href === undefined) {
64
107
  return;
65
108
  }
66
109
  const link = HTML.getLink(href.toString(), label, {}, true);
67
- links.push(link);
110
+ links.push(link + suffix);
68
111
  }
69
112
 
70
113
  /**
71
- * @param {import("./taxon.js").Taxon} taxon
72
- * @returns {string|undefined}
114
+ * @param {string[]} links
115
+ * @param {import("./types.js").Taxon} taxon
116
+ * @param {import("./types.js").Config} config
117
+ * @param {import("./index.js").RefSourceCode} sourceCode
118
+ * @param {string} [label]
73
119
  */
74
- static getCalscapeLink(taxon) {
75
- const calscapeCN = taxon.getCalscapeCommonName();
76
- if (!calscapeCN) {
77
- return;
78
- }
79
- return HTML.getLink(
80
- `https://www.calscape.org/${taxon.getCalscapeName().replaceAll(" ", "-")}-()`,
81
- "Calscape",
82
- {},
83
- true,
84
- );
120
+ static addObsLink(links, taxon, config, sourceCode, label) {
121
+ const source = OBSLINKS[sourceCode];
122
+ this.addLink(links, source.href(taxon, config), label ?? source.label);
123
+ }
124
+
125
+ /**
126
+ * @param {string[]} links
127
+ * @param {import("./types.js").Taxon} taxon
128
+ * @param {import("./index.js").RefSourceCode} sourceCode
129
+ * @param {string} [suffix=""]
130
+ */
131
+ static addRefLink(links, taxon, sourceCode, suffix = "") {
132
+ const source = REFLINKS[sourceCode];
133
+ this.addLink(links, source.href(taxon), source.label, suffix);
85
134
  }
86
135
 
87
136
  /**
@@ -110,7 +159,7 @@ class HTMLTaxon {
110
159
  }
111
160
 
112
161
  /**
113
- * @param {import("./taxon.js").Taxon} taxon
162
+ * @param {import("./types.js").Taxon} taxon
114
163
  * @param {string} classNames
115
164
  * @param {boolean} [includeColorLink=true]
116
165
  */
@@ -151,7 +200,7 @@ class HTMLTaxon {
151
200
  }
152
201
 
153
202
  /**
154
- * @param {import("./taxon.js").Taxon} taxon
203
+ * @param {import("./types.js").Taxon} taxon
155
204
  * @returns {string}
156
205
  */
157
206
  static getFooterHTML(taxon) {
@@ -164,7 +213,38 @@ class HTMLTaxon {
164
213
  }
165
214
 
166
215
  /**
167
- * @param {import("./taxon.js").Taxon} taxon
216
+ * @param {import("./types.js").Taxon} taxon
217
+ * @param {boolean|string|undefined} href
218
+ * @param {boolean} includeRPI
219
+ */
220
+ static getHTMLLink(taxon, href = true, includeRPI = true) {
221
+ href = href ? "./" + taxon.getFileName() : undefined;
222
+ let className = taxon.isNative() ? "native" : "non-native";
223
+ let isRare = false;
224
+ if (includeRPI && taxon.isRare()) {
225
+ isRare = true;
226
+ className += " rare";
227
+ }
228
+ const attributes = { class: className };
229
+ const link = HTML.wrap(
230
+ "span",
231
+ HTML.getLink(href, taxon.getName()),
232
+ attributes,
233
+ );
234
+ if (isRare) {
235
+ return HTML.getToolTip(
236
+ link,
237
+ this.getRPIRankAndThreatTooltip(taxon),
238
+ {
239
+ icon: false,
240
+ },
241
+ );
242
+ }
243
+ return link;
244
+ }
245
+
246
+ /**
247
+ * @param {import("./types.js").Taxon} taxon
168
248
  */
169
249
  static getLink(taxon) {
170
250
  return (
@@ -204,8 +284,17 @@ class HTMLTaxon {
204
284
  }
205
285
 
206
286
  /**
207
- * @param {import("./taxon.js").Taxon[]} taxa
208
- * @param {TaxaColDef[]} [columns]
287
+ * @param {import("./types.js").Taxon} taxon
288
+ */
289
+ static getRPIRankAndThreatTooltip(taxon) {
290
+ return RarePlants.getRPIRankAndThreatDescriptions(
291
+ taxon.getRPIRankAndThreat(),
292
+ ).join("<br>");
293
+ }
294
+
295
+ /**
296
+ * @param {import("./types.js").Taxon[]} taxa
297
+ * @param {import("./types.js").TaxaColDef[]} [columns]
209
298
  */
210
299
  static getTaxaTable(taxa, columns = DEFAULT_TAXA_COLUMNS) {
211
300
  let html = "<table><thead>";
package/lib/index.d.ts CHANGED
@@ -4,7 +4,28 @@ import { Command } from "commander";
4
4
 
5
5
  export type NativeStatusCode = "N" | "NC" | "U" | "X";
6
6
 
7
- export type TaxonData = {
7
+ type PhotoRights = "CC0" | "CC BY" | "CC BY-NC" | "C" | null;
8
+
9
+ type RefSourceCode =
10
+ | "calflora"
11
+ | "calscape"
12
+ | "cch"
13
+ | "fna"
14
+ | "inat"
15
+ | "jepson"
16
+ | "rpi";
17
+
18
+ type TaxaColDef<T> = {
19
+ title: string;
20
+ class?: string;
21
+ data: (taxon: T) => string | number;
22
+ };
23
+
24
+ type TaxonomyData = {
25
+ "jepson id": string;
26
+ };
27
+
28
+ export type TaxonData = TaxonomyData & {
8
29
  bloom_end: string;
9
30
  bloom_start: string;
10
31
  calrecnum: string;
@@ -14,10 +35,10 @@ export type TaxonData = {
14
35
  "common name": string;
15
36
  CRPR: string;
16
37
  FESA: string;
38
+ fna: string;
17
39
  flower_color: string;
18
40
  GRank: string;
19
41
  "inat id": string;
20
- "jepson id": string;
21
42
  life_cycle: string;
22
43
  "RPI ID": string;
23
44
  SRank: string;
@@ -27,6 +48,14 @@ export type TaxonData = {
27
48
 
28
49
  // Classes
29
50
 
51
+ export class BasePageRenderer {
52
+ static renderBasePages<T extends Taxon>(
53
+ outputDir: string,
54
+ taxa: Taxa<T>,
55
+ familyCols?: TaxaColDef<T>[],
56
+ ): void;
57
+ }
58
+
30
59
  export class Config {
31
60
  constructor(dataDir: string);
32
61
  getConfigValue(
@@ -40,7 +69,10 @@ export class Config {
40
69
  }
41
70
 
42
71
  export class CSV {
43
- static parseFile(dir: string, fileName: string): Record<string, string>[];
72
+ static readFile(
73
+ fileName: string,
74
+ delimeter?: string,
75
+ ): Record<string, string>[];
44
76
  }
45
77
 
46
78
  export class ErrorLog {
@@ -61,11 +93,6 @@ export class Exceptions {
61
93
  hasException(name: string, cat: string, subcat: string): boolean;
62
94
  }
63
95
 
64
- export class ExternalSites {
65
- static getCCH2ObsLink(taxon: Taxon, config: Config): URL | undefined;
66
- static getCCH2RefLink(taxon: Taxon): URL | undefined;
67
- }
68
-
69
96
  export class Family {
70
97
  getName(): string;
71
98
  }
@@ -78,31 +105,37 @@ export class Files {
78
105
  ): Promise<Headers>;
79
106
  static mkdir(dir: string): void;
80
107
  static rmDir(dir: string): void;
81
- static write(fileName: string, data: string, overwrite: boolean): void;
108
+ static write(fileName: string, data: string, overwrite?: boolean): void;
82
109
  }
83
110
 
84
111
  export class Genera {}
85
112
 
86
- export class Genus {
87
- getTaxa(): Taxon[];
113
+ export class Genus<T extends Taxon> {
114
+ getTaxa(): T[];
88
115
  }
89
116
 
90
117
  export class HTML {
91
118
  static arrayToLI(items: string[]): string;
119
+ static escapeText(text: string): string;
92
120
  static getLink(
93
121
  href: string | undefined,
94
122
  linkText: string,
95
123
  attrs?: Record<string, string> | string,
96
124
  openInNewWindow?: boolean,
97
125
  ): string;
126
+ static getToolTip(
127
+ text: string,
128
+ tooltip: string,
129
+ options?: { icon: boolean },
130
+ ): string;
98
131
  static textElement(
99
132
  elName: string,
100
- text: string,
133
+ text: string | number,
101
134
  attrs?: Record<string, string>,
102
135
  ): string;
103
136
  static wrap(
104
137
  elName: string,
105
- text: string,
138
+ text: string | number,
106
139
  attrs?: string | Record<string, string> | undefined,
107
140
  ): string;
108
141
  }
@@ -113,6 +146,18 @@ export class HTMLTaxon {
113
146
  href: URL | string | undefined,
114
147
  label: string,
115
148
  ): void;
149
+ static addObsLink(
150
+ links: string[],
151
+ taxon: Taxon,
152
+ config: Config,
153
+ sourceCode: RefSourceCode,
154
+ label?: string,
155
+ ): void;
156
+ static addRefLink(
157
+ links: string[],
158
+ taxon: Taxon,
159
+ sourceCode: RefSourceCode,
160
+ ): void;
116
161
  static getFooterHTML(taxon: Taxon): string;
117
162
  static getListSectionHTML(
118
163
  list: string[],
@@ -123,11 +168,10 @@ export class HTMLTaxon {
123
168
  }
124
169
 
125
170
  export class Jekyll {
171
+ static hasInclude(baseDir: string, path: string): boolean;
126
172
  static include(fileName: string): string;
127
173
  }
128
174
 
129
- type PhotoRights = "CC0" | "CC BY" | "CC BY-NC" | "C" | null;
130
-
131
175
  export class Photo {
132
176
  getAttribution(): string;
133
177
  getExt(): string;
@@ -141,38 +185,39 @@ export class Program {
141
185
  static getProgram(): Command;
142
186
  }
143
187
 
144
- export class Taxa {
188
+ export class Taxa<T> {
145
189
  constructor(
146
190
  inclusionList: Record<string, TaxonData> | true,
147
191
  errorLog: ErrorLog,
148
192
  showFlowerErrors: boolean,
149
- taxonFactory?: (td: TaxonData, g: Genera) => Taxon,
193
+ taxonFactory?: (td: TaxonData, g: Genera) => T,
150
194
  extraTaxa?: TaxonData[],
151
195
  extraSynonyms?: Record<string, string>[],
152
196
  );
153
- getTaxon(name: string): Taxon;
154
- getTaxonList(): Taxon[];
197
+ getTaxon(name: string): T;
198
+ getTaxonList(): T[];
155
199
  }
156
200
 
157
201
  export class Taxon {
202
+ constructor(data: TaxonData, genera: Genera);
158
203
  getBaseFileName(): string;
159
204
  getCalfloraID(): string;
160
- getCalfloraTaxonLink(): string;
161
- getCESA(): string | undefined;
162
- getCNDDBRank(): string | undefined;
205
+ getCalfloraName(): string;
206
+ getCESA(): string;
207
+ getCNDDBRank(): string;
163
208
  getCommonNames(): string[];
164
209
  getFamily(): Family;
165
210
  getFileName(): string;
166
- getFESA(): string | undefined;
167
- getGenus(): Genus;
211
+ getFESA(): string;
212
+ getGenus<T extends Taxon>(): Genus<T>;
168
213
  getGenusName(): string;
169
- getGlobalRank(): string | undefined;
214
+ getGlobalRank(): string;
170
215
  getINatID(): string;
171
- getINatTaxonLink(): string;
216
+ getINatName(): string;
172
217
  getJepsonID(): string;
173
218
  getName(): string;
174
219
  getPhotos(): Photo[];
220
+ getRPIRank(): string;
175
221
  getRPIRankAndThreat(): string;
176
- getRPITaxonLink(): string;
177
222
  getSynonyms(): string[];
178
223
  }
package/lib/index.js CHANGED
@@ -4,15 +4,15 @@ import { CSV } from "./csv.js";
4
4
  import { ErrorLog } from "./errorlog.js";
5
5
  import { Exceptions } from "./exceptions.js";
6
6
  import { ExternalSites } from "./externalsites.js";
7
- import { Families } from "./families.js";
7
+ import { Families } from "./taxonomy/families.js";
8
8
  import { Files } from "./files.js";
9
9
  import { HTML } from "./html.js";
10
10
  import { HTMLTaxon } from "./htmltaxon.js";
11
11
  import { Jekyll } from "./jekyll.js";
12
12
  import { PlantBook } from "./ebook/plantbook.js";
13
13
  import { Program } from "./program.js";
14
- import { Taxa } from "./taxa.js";
15
- import { Taxon } from "./taxon.js";
14
+ import { Taxa } from "./taxonomy/taxa.js";
15
+ import { Taxon } from "./taxonomy/taxon.js";
16
16
 
17
17
  export {
18
18
  BasePageRenderer,
@@ -22,7 +22,7 @@ class PageRenderer extends BasePageRenderer {
22
22
  /**
23
23
  * @param {string} outputDir
24
24
  * @param {import('./config.js').Config} config
25
- * @param {import("./taxa.js").Taxa} taxa
25
+ * @param {import("./types.js").Taxa} taxa
26
26
  */
27
27
  static render(outputDir, config, taxa) {
28
28
  super.renderBasePages(outputDir, taxa);
@@ -38,13 +38,13 @@ class PageRenderer extends BasePageRenderer {
38
38
  /**
39
39
  * @param {string} outputDir
40
40
  * @param {import('./config.js').Config} config
41
- * @param {import("./taxa.js").Taxa} taxa
41
+ * @param {import("./types.js").Taxa} taxa
42
42
  */
43
43
  static renderLists(outputDir, config, taxa) {
44
44
  /**
45
45
  * @param {ListInfo[]} listInfo
46
46
  * @param {Object<string,string>} attributes
47
- * @param {import("./htmltaxon.js").TaxaColDef[]} [columns]
47
+ * @param {import("./types.js").TaxaColDef[]} [columns]
48
48
  * @returns {string}
49
49
  */
50
50
  function getListArray(listInfo, attributes = {}, columns) {
@@ -117,7 +117,7 @@ class PageRenderer extends BasePageRenderer {
117
117
  return html;
118
118
  }
119
119
 
120
- /** @typedef {{name:string,filename:string,include:function(import("./taxon.js").Taxon):boolean,columns?:import("./htmltaxon.js").TaxaColDef[],listInfo?:ListInfo[]}} ListInfo */
120
+ /** @typedef {{name:string,filename:string,include:function(import("./types.js").Taxon):boolean,columns?:import("./types.js").TaxaColDef[],listInfo?:ListInfo[]}} ListInfo */
121
121
  /** @type {{title:string,listInfo:ListInfo[]}[]} */
122
122
  const sections = [
123
123
  {
@@ -227,8 +227,8 @@ class PageTaxonList extends GenericPage {
227
227
 
228
228
  /**
229
229
  *
230
- * @param {import("./taxon.js").Taxon[]} taxa
231
- * @param {import("./htmltaxon.js").TaxaColDef[]|undefined} columns
230
+ * @param {import("./types.js").Taxon[]} taxa
231
+ * @param {import("./types.js").TaxaColDef[]|undefined} columns
232
232
  */
233
233
  render(taxa, columns) {
234
234
  let html = this.getDefaultIntro();
@@ -0,0 +1,104 @@
1
+ import { Files } from "../files.js";
2
+ import { Config } from "../config.js";
3
+ import { Taxonomy } from "./taxonomy.js";
4
+
5
+ /**
6
+ * @typedef {{id:string,section:string,taxa?:import("../types.js").Taxon[]}} FamilyData
7
+ */
8
+
9
+ export class Family extends Taxonomy {
10
+ #name;
11
+ #data;
12
+
13
+ /**
14
+ * @param {string} name
15
+ * @param {FamilyData} data
16
+ */
17
+ constructor(name, data) {
18
+ super({ "jepson id": data.id });
19
+ this.#name = name;
20
+ this.#data = data;
21
+ }
22
+
23
+ /**
24
+ * @param {import("../types.js").Taxon} taxon
25
+ */
26
+ addTaxon(taxon) {
27
+ if (!this.#data.taxa) {
28
+ this.#data.taxa = [];
29
+ }
30
+ this.#data.taxa.push(taxon);
31
+ Sections.addTaxon(this.getSectionName(), taxon);
32
+ }
33
+
34
+ getBaseFileName() {
35
+ return this.getName();
36
+ }
37
+
38
+ getFileName(ext = "html") {
39
+ return this.getBaseFileName() + "." + ext;
40
+ }
41
+
42
+ getName() {
43
+ return this.#name;
44
+ }
45
+
46
+ getSectionName() {
47
+ return this.#data.section;
48
+ }
49
+
50
+ getTaxa() {
51
+ return this.#data.taxa;
52
+ }
53
+ }
54
+
55
+ export class Families {
56
+ #families;
57
+
58
+ constructor() {
59
+ const dataDir = Config.getPackageDir() + "/data";
60
+
61
+ this.#families = JSON.parse(Files.read(dataDir + "/families.json"));
62
+ for (const [k, v] of Object.entries(this.#families)) {
63
+ this.#families[k] = new Family(k, v);
64
+ }
65
+ }
66
+
67
+ /**
68
+ * @returns {Family[]}
69
+ */
70
+ getFamilies() {
71
+ return Object.values(this.#families).sort((a, b) =>
72
+ a.getName().localeCompare(b.getName()),
73
+ );
74
+ }
75
+
76
+ /**
77
+ * @param {string} familyName
78
+ */
79
+ getFamily(familyName) {
80
+ return this.#families[familyName];
81
+ }
82
+ }
83
+
84
+ export class Sections {
85
+ /** @type {Object<string,import("../types.js").Taxon[]>} */
86
+ static #sections = {};
87
+
88
+ /**
89
+ * @param {string} name
90
+ * @param {import("../types.js").Taxon} taxon
91
+ */
92
+ static addTaxon(name, taxon) {
93
+ let section = this.#sections[name];
94
+ if (!section) {
95
+ section = [];
96
+ this.#sections[name] = section;
97
+ }
98
+ section.push(taxon);
99
+ }
100
+
101
+ static getSections() {
102
+ return this.#sections;
103
+ }
104
+ }
@@ -1,16 +1,16 @@
1
1
  import * as fs from "node:fs";
2
2
  import path from "node:path";
3
3
 
4
- import { Config } from "./config.js";
5
- import { CSV } from "./csv.js";
6
- import { Genera } from "./genera.js";
4
+ import { Config } from "../config.js";
5
+ import { CSV } from "../csv.js";
6
+ import { Genera } from "../genera.js";
7
7
  import { Taxon } from "./taxon.js";
8
8
  import { Families } from "./families.js";
9
- import { FlowerColor } from "./flowercolor.js";
10
- import { TaxaCSV } from "./tools/taxacsv.js";
11
- import { ErrorLog } from "./errorlog.js";
12
- import { Program } from "./program.js";
13
- import { Photo } from "./photo.js";
9
+ import { FlowerColor } from "../flowercolor.js";
10
+ import { TaxaCSV } from "../tools/taxacsv.js";
11
+ import { ErrorLog } from "../errorlog.js";
12
+ import { Program } from "../program.js";
13
+ import { Photo } from "../photo.js";
14
14
 
15
15
  /**
16
16
  * @typedef {{Current: string;Former: string;Type: string;}} SynonymData
@@ -40,11 +40,11 @@ class Taxa {
40
40
  #isSubset;
41
41
 
42
42
  /**
43
- * @param {Object<string,import("./index.js").TaxonData>|true} inclusionList
43
+ * @param {Object<string,import("../index.js").TaxonData>|true} inclusionList
44
44
  * @param {ErrorLog} errorLog
45
45
  * @param {boolean} showFlowerErrors
46
- * @param {function(import("./index.js").TaxonData,Genera):Taxon} taxonFactory
47
- * @param {import("./index.js").TaxonData[]} [extraTaxa=[]]
46
+ * @param {function(import("../index.js").TaxonData,Genera):Taxon} taxonFactory
47
+ * @param {import("../index.js").TaxonData[]} [extraTaxa=[]]
48
48
  * @param {SynonymData[]} [extraSynonyms=[]]
49
49
  * @param {boolean} includePhotos
50
50
  */
@@ -114,9 +114,9 @@ class Taxa {
114
114
  */
115
115
  #loadPhotosFromFile(dataDir, filename) {
116
116
  if (!fs.existsSync(path.join(dataDir, filename))) return;
117
- /** @type {import("./utils/inat-tools.js").InatCsvPhoto[]} */
117
+ /** @type {import("../utils/inat-tools.js").InatCsvPhoto[]} */
118
118
  const csvPhotos = CSV.parseFile(dataDir, filename).map((row) => {
119
- /** @type {import("./utils/inat-tools.js").InatLicenseCode} */
119
+ /** @type {import("../utils/inat-tools.js").InatLicenseCode} */
120
120
  let licenseCode = "cc-by";
121
121
  if (row.licenseCode === "cc-by-nc-sa") licenseCode = "cc-by-nc-sa";
122
122
  else if (row.licenseCode === "cc-by-nc") licenseCode = "cc-by-nc";
@@ -224,7 +224,7 @@ class Taxa {
224
224
 
225
225
  /**
226
226
  * @param {SynonymData[]} synCSV
227
- * @param {Object<string,import("./index.js").TaxonData>|boolean} inclusionList
227
+ * @param {Object<string,import("../index.js").TaxonData>|boolean} inclusionList
228
228
  */
229
229
  #loadSyns(synCSV, inclusionList) {
230
230
  for (const syn of synCSV) {
@@ -245,9 +245,9 @@ class Taxa {
245
245
  }
246
246
 
247
247
  /**
248
- * @param {import("./index.js").TaxonData[]} taxaCSV
249
- * @param {Object<string,import("./index.js").TaxonData>|true} inclusionList
250
- * @param {function(import("./index.js").TaxonData,Genera):Taxon} taxonFactory
248
+ * @param {import("../index.js").TaxonData[]} taxaCSV
249
+ * @param {Object<string,import("../index.js").TaxonData>|true} inclusionList
250
+ * @param {function(import("../index.js").TaxonData,Genera):Taxon} taxonFactory
251
251
  * @param {Genera} genera
252
252
  * @param {boolean} showFlowerErrors
253
253
  */
@@ -255,7 +255,7 @@ class Taxa {
255
255
  for (const row of taxaCSV) {
256
256
  const name = row["taxon_name"];
257
257
 
258
- /** @type {import("./index.js").TaxonData|{status?:import("./index.js").NativeStatusCode}} */
258
+ /** @type {import("../index.js").TaxonData|{status?:import("../index.js").NativeStatusCode}} */
259
259
  let taxon_overrides = {};
260
260
  if (inclusionList !== true) {
261
261
  taxon_overrides = inclusionList[name];