@ca-plant-list/ca-plant-list 0.3.2 → 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 (54) hide show
  1. package/.vscode/settings.json +4 -2
  2. package/data/exceptions.json +0 -3
  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 +54 -52
  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/Viola-douglasii.md +1 -0
  37. package/data/text/Viola-pedunculata.md +1 -0
  38. package/data/text/Viola-purpurea-subsp-quercetorum.md +1 -0
  39. package/ebook/css/main.css +5 -0
  40. package/lib/basepagerenderer.js +30 -28
  41. package/lib/dateutils.js +36 -16
  42. package/lib/ebook/pages/taxonpage.js +63 -36
  43. package/lib/errorlog.js +16 -11
  44. package/lib/families.js +109 -71
  45. package/lib/files.js +103 -45
  46. package/lib/generictaxaloader.js +15 -7
  47. package/lib/index.js +38 -3
  48. package/lib/taxa.js +164 -87
  49. package/lib/taxaloader.js +28 -15
  50. package/lib/taxaprocessor.js +6 -8
  51. package/lib/taxon.js +109 -56
  52. package/package.json +4 -6
  53. package/scripts/build-ebook.js +30 -25
  54. package/lib/index.d.ts +0 -345
@@ -0,0 +1 @@
1
+ Style 2–4 mm long. Lower leaves with deep lobes; lobes similar. Corolla 4-12 mm wide.
@@ -0,0 +1 @@
1
+ Style less than 2 mm long. Lower leaves cut or shallow-lobed; lobes dissimilar. Corolla 1-5 mm wide.
@@ -0,0 +1 @@
1
+ Corolla with 2 lips. Lower lip usually has 2 red spots.
@@ -0,0 +1 @@
1
+ Corolla symmetrical, circular.
@@ -0,0 +1 @@
1
+ Leaf blade usually more than twice as long as wide. Filament tube usually 3 to 4 mm wide. Anther usually dark purple. [Peduncle](./g/peduncle.html) usually green.
@@ -0,0 +1 @@
1
+ Leaf blade usually less than twice as long as wide. Filament tube usually less than 3 mm wide. [Peduncle](./g/peduncle.html) usually red.
@@ -0,0 +1 @@
1
+ Annual. Stipules on upper stem having two or more linear lobes.
@@ -0,0 +1 @@
1
+ Difficult to distinguish from _T. laciniatus_, with which it likely hybridizes.
@@ -0,0 +1 @@
1
+ Difficult to distinguish from _T. curvipes_, with which it likely hybridizes.
@@ -0,0 +1 @@
1
+ Leaves compound.
@@ -0,0 +1 @@
1
+ Leaves not compound. No basal leaves.
@@ -0,0 +1 @@
1
+ Leaves not compound.
@@ -8,7 +8,12 @@ div.flr {
8
8
  align-items: center;
9
9
  }
10
10
 
11
+ div.section {
12
+ margin-bottom: .5rem;
13
+ }
14
+
11
15
  img.flr {
16
+ padding-right: .25rem;
12
17
  width: 1rem;
13
18
  }
14
19
 
@@ -6,53 +6,55 @@ import { Taxa } from "./taxa.js";
6
6
  import { GlossaryPages } from "./web/glossarypages.js";
7
7
 
8
8
  class BasePageRenderer {
9
-
10
- static render( outputDir, taxa, familyCols ) {
11
-
12
- const siteGenerator = new Jekyll( outputDir );
9
+ /**
10
+ * @param {string} outputDir
11
+ * @param {Taxa} taxa
12
+ * @param {*} familyCols
13
+ */
14
+ static render(outputDir, taxa, familyCols) {
15
+ const siteGenerator = new Jekyll(outputDir);
13
16
 
14
17
  // Copy static files
15
18
  // First copy default Jekyll files from package.
16
- Files.copyDir( Config.getPackageDir() + "/jekyll", outputDir );
19
+ Files.copyDir(Config.getPackageDir() + "/jekyll", outputDir);
17
20
  // Then copy Jekyll files from current dir (which may override default files).
18
- Files.copyDir( "jekyll", outputDir );
21
+ Files.copyDir("jekyll", outputDir);
19
22
 
20
23
  // Copy illustrations.
21
- siteGenerator.copyIllustrations( Taxa.getFlowerColors() );
24
+ siteGenerator.copyIllustrations(Taxa.getFlowerColors());
22
25
 
23
- Families.renderPages( outputDir, familyCols );
26
+ Families.renderPages(outputDir, familyCols);
24
27
 
25
- new GlossaryPages( siteGenerator ).renderPages();
26
-
27
- this.renderTools( outputDir, taxa );
28
+ new GlossaryPages(siteGenerator).renderPages();
28
29
 
30
+ this.renderTools(outputDir, taxa);
29
31
  }
30
32
 
31
- static renderTools( outputDir, taxa ) {
32
-
33
+ /**
34
+ * @param {string} outputDir
35
+ * @param {Taxa} taxa
36
+ */
37
+ static renderTools(outputDir, taxa) {
33
38
  const names = [];
34
- for ( const taxon of taxa.getTaxonList() ) {
39
+ for (const taxon of taxa.getTaxonList()) {
35
40
  const row = [];
36
- row.push( taxon.getName() );
37
- const cn = taxon.getCommonNames().join( ", " );
38
- if ( cn ) {
39
- row.push( cn );
41
+ row.push(taxon.getName());
42
+ const cn = taxon.getCommonNames().join(", ");
43
+ if (cn) {
44
+ row.push(cn);
40
45
  }
41
46
  const synonyms = [];
42
- for ( const syn of taxon.getSynonyms() ) {
43
- synonyms.push( syn );
47
+ for (const syn of taxon.getSynonyms()) {
48
+ synonyms.push(syn);
44
49
  }
45
- if ( synonyms.length > 0 ) {
46
- row[ 2 ] = synonyms;
50
+ if (synonyms.length > 0) {
51
+ row[2] = synonyms;
47
52
  }
48
- names.push( row );
53
+ names.push(row);
49
54
  }
50
55
 
51
- Files.write( outputDir + "/_includes/names.json", JSON.stringify( names ) );
52
-
56
+ Files.write(outputDir + "/_includes/names.json", JSON.stringify(names));
53
57
  }
54
-
55
-
56
58
  }
57
59
 
58
- export { BasePageRenderer };
60
+ export { BasePageRenderer };
package/lib/dateutils.js CHANGED
@@ -14,30 +14,50 @@ const MONTH_NAMES = [
14
14
  ];
15
15
 
16
16
  class DateUtils {
17
-
18
- static getMonthName( monthNum ) {
19
- return MONTH_NAMES[ monthNum - 1 ];
17
+ /**
18
+ * @param {number} monthNum Starting with 1 for January.
19
+ * @returns {string}
20
+ */
21
+ static getMonthName(monthNum) {
22
+ return MONTH_NAMES[monthNum - 1];
20
23
  }
21
24
 
22
- static monthRangesOverlap( r1, r2 ) {
23
-
24
- function contains( r1, r2 ) {
25
- function inRange( v, r ) {
26
- return v >= r[ 0 ] && v <= r[ 1 ];
25
+ /**
26
+ * @param {[number,number]} r1
27
+ * @param {[number,number]} r2
28
+ * @returns {boolean}
29
+ */
30
+ static monthRangesOverlap(r1, r2) {
31
+ /**
32
+ * @param {[number,number]} r1
33
+ * @param {[number,number]} r2
34
+ */
35
+ function contains(r1, r2) {
36
+ /**
37
+ * @param {number} v
38
+ * @param {[number,number]} r
39
+ */
40
+ function inRange(v, r) {
41
+ return v >= r[0] && v <= r[1];
27
42
  }
28
- return inRange( r1[ 0 ], r2 ) || inRange( r1[ 1 ], r2 );
43
+ return inRange(r1[0], r2) || inRange(r1[1], r2);
29
44
  }
30
45
 
31
46
  // If ranges cross into next year, split them in 2.
32
- if ( r1[ 0 ] > r1[ 1 ] ) {
33
- return this.monthRangesOverlap( [ r1[ 0 ], 12 ], r2 ) || this.monthRangesOverlap( [ 1, r1[ 1 ] ], r2 );
47
+ if (r1[0] > r1[1]) {
48
+ return (
49
+ this.monthRangesOverlap([r1[0], 12], r2) ||
50
+ this.monthRangesOverlap([1, r1[1]], r2)
51
+ );
34
52
  }
35
- if ( r2[ 0 ] > r2[ 1 ] ) {
36
- return this.monthRangesOverlap( r1, [ r2[ 0 ], 12 ] ) || this.monthRangesOverlap( r1, [ 1, r2[ 1 ] ] );
53
+ if (r2[0] > r2[1]) {
54
+ return (
55
+ this.monthRangesOverlap(r1, [r2[0], 12]) ||
56
+ this.monthRangesOverlap(r1, [1, r2[1]])
57
+ );
37
58
  }
38
- return contains( r1, r2 ) || contains( r2, r1 );
59
+ return contains(r1, r2) || contains(r2, r1);
39
60
  }
40
-
41
61
  }
42
62
 
43
- export { DateUtils };
63
+ export { DateUtils };
@@ -4,88 +4,115 @@ import { EBookPage } from "../ebookpage.js";
4
4
  import { XHTML } from "../xhtml.js";
5
5
  import { Markdown } from "../../markdown.js";
6
6
  import { DateUtils } from "../../dateutils.js";
7
+ // eslint-disable-next-line no-unused-vars
8
+ import { Taxon } from "../../taxon.js";
7
9
 
8
10
  class TaxonPage extends EBookPage {
9
-
10
11
  #outputDir;
11
12
  #taxon;
12
13
  #photos;
13
14
 
14
- constructor( outputDir, taxon, photos ) {
15
- super( outputDir + "/" + taxon.getFileName(), taxon.getName() );
15
+ /**
16
+ *
17
+ * @param {string} outputDir
18
+ * @param {Taxon} taxon
19
+ * @param {*} photos
20
+ */
21
+ constructor(outputDir, taxon, photos) {
22
+ super(outputDir + "/" + taxon.getFileName(), taxon.getName());
16
23
  this.#outputDir = outputDir;
17
24
  this.#taxon = taxon;
18
25
  this.#photos = photos;
19
26
  }
20
27
 
21
28
  renderPageBody() {
22
-
23
- function renderBloomInfo( taxon ) {
29
+ /**
30
+ * @param {Taxon} taxon
31
+ */
32
+ function renderBloomInfo(taxon) {
24
33
  const colors = taxon.getFlowerColors();
25
34
  const monthStart = taxon.getBloomStart();
26
35
  const monthEnd = taxon.getBloomEnd();
27
- if ( !colors && !monthStart ) {
36
+ if (!colors && !monthStart) {
28
37
  return "";
29
38
  }
30
39
  let html = "";
31
- if ( colors ) {
32
- for ( const color of colors ) {
33
- html += XHTML.textElement( "img", "", { src: "./i/f-" + color + ".svg", class: "flr" } );
40
+ if (colors) {
41
+ for (const color of colors) {
42
+ html += XHTML.textElement("img", "", {
43
+ src: "./i/f-" + color + ".svg",
44
+ class: "flr",
45
+ });
34
46
  }
35
47
  }
36
- if ( monthStart ) {
37
- html += XHTML.textElement( "div", DateUtils.getMonthName( monthStart ) + "-" + DateUtils.getMonthName( monthEnd ) );
38
-
48
+ if (monthStart && monthEnd) {
49
+ html += XHTML.textElement(
50
+ "div",
51
+ DateUtils.getMonthName(monthStart) +
52
+ "-" +
53
+ DateUtils.getMonthName(monthEnd)
54
+ );
39
55
  }
40
- return XHTML.wrap( "div", html, { class: "flr" } );
56
+ return XHTML.wrap("div", html, { class: "section flr" });
41
57
  }
42
58
 
43
-
44
- function renderCustomText( name ) {
59
+ /**
60
+ * @param {string} name
61
+ */
62
+ function renderCustomText(name) {
45
63
  // See if there is custom text.
46
- const fileName = Config.getPackageDir() + "/data/text/" + name + ".md";
47
- if ( !Files.exists( fileName ) ) {
64
+ const fileName =
65
+ Config.getPackageDir() + "/data/text/" + name + ".md";
66
+ if (!Files.exists(fileName)) {
48
67
  return "";
49
68
  }
50
- const text = Files.read( fileName );
51
- return Markdown.strToHTML( text );
69
+ const text = Files.read(fileName);
70
+ return Markdown.strToHTML(text);
52
71
  }
53
72
 
54
73
  const name = this.#taxon.getName();
55
- let html = XHTML.textElement( "h1", name );
74
+ let html = XHTML.textElement("h1", name);
56
75
 
57
76
  const family = this.#taxon.getFamily();
58
- html += XHTML.wrap( "div", XHTML.getLink( family.getFileName(), family.getName() ) );
77
+ html += XHTML.wrap(
78
+ "div",
79
+ XHTML.getLink(family.getFileName(), family.getName()),
80
+ { class: "section" }
81
+ );
59
82
 
60
83
  const cn = this.#taxon.getCommonNames();
61
- if ( cn && cn.length > 0 ) {
62
- html += XHTML.textElement( "p", cn.join( ", " ) );
84
+ if (cn && cn.length > 0) {
85
+ html += XHTML.textElement("div", cn.join(", "), {
86
+ class: "section",
87
+ });
63
88
  }
64
89
 
65
- html += renderBloomInfo( this.#taxon );
90
+ html += renderBloomInfo(this.#taxon);
66
91
 
67
- html += renderCustomText( this.#taxon.getBaseFileName() );
92
+ html += renderCustomText(this.#taxon.getBaseFileName());
68
93
 
69
- if ( this.#photos ) {
94
+ if (this.#photos) {
70
95
  let photoHTML = "";
71
- for ( const photo of this.#photos ) {
96
+ for (const photo of this.#photos) {
72
97
  const src = photo.getSrc();
73
- const dimensions = sizeOf( this.#outputDir + "/" + src );
74
- let img = XHTML.textElement( "img", "", { src: src, style: "max-width:" + dimensions.width + "px" } );
98
+ const dimensions = sizeOf(this.#outputDir + "/" + src);
99
+ let img = XHTML.textElement("img", "", {
100
+ src: src,
101
+ style: "max-width:" + dimensions.width + "px",
102
+ });
75
103
  const caption = photo.getCaption();
76
- if ( caption ) {
77
- img += XHTML.textElement( "figcaption", caption );
104
+ if (caption) {
105
+ img += XHTML.textElement("figcaption", caption);
78
106
  }
79
- photoHTML += XHTML.wrap( "figure", img );
107
+ photoHTML += XHTML.wrap("figure", img);
80
108
  }
81
- if ( photoHTML ) {
82
- html += XHTML.wrap( "div", photoHTML );
109
+ if (photoHTML) {
110
+ html += XHTML.wrap("div", photoHTML);
83
111
  }
84
112
  }
85
113
 
86
114
  return html;
87
115
  }
88
-
89
116
  }
90
117
 
91
- export { TaxonPage };
118
+ export { TaxonPage };
package/lib/errorlog.js CHANGED
@@ -2,30 +2,35 @@ import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
 
4
4
  class ErrorLog {
5
-
6
5
  #fileName;
7
6
  #echo;
7
+ /** @type string[] */
8
8
  #errors = [];
9
9
 
10
- constructor( fileName, echo = false ) {
10
+ /**
11
+ * @param {string} fileName
12
+ * @param {boolean} echo
13
+ */
14
+ constructor(fileName, echo = false) {
11
15
  this.#fileName = fileName;
12
16
  this.#echo = echo;
13
17
  }
14
18
 
15
- log( ...args ) {
16
- if ( this.#echo ) {
17
- console.log( args.join() );
19
+ /**
20
+ * @param {...string} args
21
+ */
22
+ log(...args) {
23
+ if (this.#echo) {
24
+ console.log(args.join());
18
25
  }
19
- this.#errors.push( args.join( "\t" ) );
26
+ this.#errors.push(args.join("\t"));
20
27
  }
21
28
 
22
29
  write() {
23
30
  // Make sure directory exists.
24
- fs.mkdirSync( path.dirname( this.#fileName ), { recursive: true } );
25
-
26
- fs.writeFileSync( this.#fileName, this.#errors.join( "\n" ) );
31
+ fs.mkdirSync(path.dirname(this.#fileName), { recursive: true });
32
+ fs.writeFileSync(this.#fileName, this.#errors.join("\n"));
27
33
  }
28
-
29
34
  }
30
35
 
31
- export { ErrorLog };
36
+ export { ErrorLog };