@ca-plant-list/ca-plant-list 0.1.6 → 0.1.8
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.
- package/lib/basepagerenderer.js +1 -1
- package/lib/files.js +34 -2
- package/lib/html.js +3 -4
- package/lib/index.d.ts +27 -0
- package/lib/pagerenderer.js +20 -12
- package/lib/taxa.js +39 -12
- package/lib/taxon.js +12 -4
- package/package.json +10 -5
- package/tsconfig.json +14 -0
package/lib/basepagerenderer.js
CHANGED
@@ -7,7 +7,7 @@ class BasePageRenderer {
|
|
7
7
|
static render( outputDir, Taxa ) {
|
8
8
|
|
9
9
|
// Copy static files
|
10
|
-
fs.rmSync( outputDir, { force: true, recursive: true, maxRetries: 2, retryDelay:
|
10
|
+
fs.rmSync( outputDir, { force: true, recursive: true, maxRetries: 2, retryDelay: 1000 } );
|
11
11
|
// First copy default Jekyll files from package.
|
12
12
|
fs.cpSync( Config.getPackageDir() + "/jekyll", outputDir, { recursive: true } );
|
13
13
|
// Then copy Jekyll files from current dir (which may override default files).
|
package/lib/files.js
CHANGED
@@ -1,17 +1,49 @@
|
|
1
1
|
import * as fs from "node:fs";
|
2
|
+
import { default as unzipper } from "unzipper";
|
2
3
|
|
3
4
|
class Files {
|
4
5
|
|
6
|
+
static createFileFromStream( fileName, inStream ) {
|
7
|
+
|
8
|
+
function implementation( fileName, inStream, resolve ) {
|
9
|
+
const outStream = fs.createWriteStream( fileName );
|
10
|
+
outStream.on( "finish", () => { resolve( true ); } );
|
11
|
+
inStream.pipe( outStream );
|
12
|
+
}
|
13
|
+
|
14
|
+
return new Promise( ( resolve ) => { implementation( fileName, inStream, resolve ); } );
|
15
|
+
}
|
16
|
+
|
5
17
|
static async fetch( url, targetFileName ) {
|
6
18
|
const response = await fetch( url );
|
7
|
-
const data = await response.
|
8
|
-
|
19
|
+
const data = await response.blob();
|
20
|
+
const buffer = await data.arrayBuffer();
|
21
|
+
fs.writeFileSync( targetFileName, Buffer.from( buffer ) );
|
9
22
|
}
|
10
23
|
|
11
24
|
static read( path ) {
|
12
25
|
return fs.readFileSync( path, "utf8" );
|
13
26
|
}
|
14
27
|
|
28
|
+
static write( path, data ) {
|
29
|
+
if ( fs.existsSync( path ) ) {
|
30
|
+
throw new Error( path + " already exists" );
|
31
|
+
}
|
32
|
+
fs.writeFileSync( path, data );
|
33
|
+
}
|
34
|
+
|
35
|
+
static async zipFileExtract( zipFilePath, fileNameToUnzip, targetFilePath ) {
|
36
|
+
|
37
|
+
const zipDir = await unzipper.Open.file( zipFilePath );
|
38
|
+
for ( const entry of zipDir.files ) {
|
39
|
+
if ( entry.path === fileNameToUnzip ) {
|
40
|
+
await this.createFileFromStream( targetFilePath, entry.stream() );
|
41
|
+
break;
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
}
|
46
|
+
|
15
47
|
}
|
16
48
|
|
17
49
|
export { Files };
|
package/lib/html.js
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
/**
|
2
2
|
* @deprecated
|
3
3
|
*/
|
4
|
-
const HTML_OPTIONS = {
|
4
|
+
export const HTML_OPTIONS = {
|
5
5
|
OPEN_NEW: 1,
|
6
6
|
NO_ESCAPE: 2,
|
7
7
|
};
|
8
8
|
|
9
|
-
|
9
|
+
/** HTML utility functions. */
|
10
|
+
export class HTML {
|
10
11
|
|
11
12
|
static arrayToLI( items ) {
|
12
13
|
return items.reduce( ( itemHTML, currVal ) => itemHTML + "<li>" + currVal + "</li>", "" );
|
@@ -77,5 +78,3 @@ class HTML {
|
|
77
78
|
}
|
78
79
|
|
79
80
|
}
|
80
|
-
|
81
|
-
export { HTML, HTML_OPTIONS };
|
package/lib/index.d.ts
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
export class Files {
|
2
|
+
static createFileFromStream(fileName: any, inStream: any): Promise<any>;
|
3
|
+
static fetch(url: any, targetFileName: any): Promise<void>;
|
4
|
+
static read(path: any): string;
|
5
|
+
static write(path: any, data: any): void;
|
6
|
+
static zipFileExtract(zipFilePath: any, fileNameToUnzip: any, targetFilePath: any): Promise<void>;
|
7
|
+
}
|
8
|
+
export namespace HTML_OPTIONS {
|
9
|
+
const OPEN_NEW: number;
|
10
|
+
const NO_ESCAPE: number;
|
11
|
+
}
|
12
|
+
/** HTML utility functions. */
|
13
|
+
export class HTML {
|
14
|
+
static arrayToLI(items: any): any;
|
15
|
+
static escapeAttribute(value: any): any;
|
16
|
+
static escapeText(text: any): any;
|
17
|
+
/**
|
18
|
+
* @deprecated
|
19
|
+
*/
|
20
|
+
static getElement(elName: any, text: any, attributes?: {}, options?: number): string;
|
21
|
+
static "__#2@#getElement"(elName: any, text: any, attributes: any, escape: any): string;
|
22
|
+
static getLink(href: any, linkText: any, attributes?: {}, options?: number): string;
|
23
|
+
static renderAttribute(n: any, v: any): string;
|
24
|
+
static renderAttributes(attributes: any): string;
|
25
|
+
static textElement(elName: any, text: any, attributes?: {}): string;
|
26
|
+
static wrap(elName: any, text: any, attributes?: {}): string;
|
27
|
+
}
|
package/lib/pagerenderer.js
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
import * as fs from "node:fs";
|
2
|
-
import { HTML
|
3
|
-
import { Taxa } from "./taxa.js";
|
2
|
+
import { HTML } from "./html.js";
|
3
|
+
import { Taxa, COLUMNS } from "./taxa.js";
|
4
4
|
import { HTMLPage } from "./htmlpage.js";
|
5
5
|
import { PageTaxon } from "./pagetaxon.js";
|
6
6
|
import { Config } from "./config.js";
|
7
7
|
import { RarePlants } from "./rareplants.js";
|
8
8
|
import { BasePageRenderer } from "./basepagerenderer.js";
|
9
9
|
|
10
|
+
const RPI_CESA = [ COLUMNS.COL_SPECIES, COLUMNS.COL_COMMON_NAME, COLUMNS.COL_CESA ];
|
11
|
+
const RPI_COLUMNS = [ COLUMNS.COL_SPECIES, COLUMNS.COL_COMMON_NAME, COLUMNS.COL_CNPS_RANK ];
|
12
|
+
|
10
13
|
class PageRenderer extends BasePageRenderer {
|
11
14
|
|
12
15
|
static render( outputDir ) {
|
@@ -24,7 +27,8 @@ class PageRenderer extends BasePageRenderer {
|
|
24
27
|
|
25
28
|
static renderLists( outputDir ) {
|
26
29
|
|
27
|
-
function getListArray( listInfo, attributes = {} ) {
|
30
|
+
function getListArray( listInfo, attributes = {}, columns ) {
|
31
|
+
|
28
32
|
const listArray = [];
|
29
33
|
for ( const list of listInfo ) {
|
30
34
|
const taxa = [];
|
@@ -45,23 +49,25 @@ class PageRenderer extends BasePageRenderer {
|
|
45
49
|
fs.writeFileSync( outputDir + "/calflora_" + list.filename + ".txt", calfloraTaxa.join( "\n" ) );
|
46
50
|
fs.writeFileSync( outputDir + "/inat_" + list.filename + ".txt", iNatTaxa.join( "\n" ) );
|
47
51
|
|
48
|
-
|
52
|
+
const cols = columns ? columns : list.columns;
|
53
|
+
new PageTaxonList().render( outputDir, taxa, list.filename, list.name, cols );
|
49
54
|
|
50
55
|
// Check for sublists.
|
51
|
-
const subListHTML = list.listInfo ? getListArray( list.listInfo, { class: "indent" } ) : "";
|
56
|
+
const subListHTML = list.listInfo ? getListArray( list.listInfo, { class: "indent" }, cols ) : "";
|
52
57
|
|
53
58
|
listArray.push( HTML.getLink( "./" + list.filename + ".html", list.name ) + " (" + taxa.length + ")" + subListHTML );
|
54
59
|
}
|
60
|
+
|
55
61
|
return renderList( listArray, attributes );
|
56
62
|
}
|
57
63
|
|
58
64
|
function renderList( listsHTML, attributes = {} ) {
|
59
|
-
return HTML.
|
65
|
+
return HTML.wrap( "ul", HTML.arrayToLI( listsHTML ), attributes );
|
60
66
|
}
|
61
67
|
|
62
68
|
function renderSection( title, listsHTML ) {
|
63
69
|
let html = "<div class=\"section\">";
|
64
|
-
html += HTML.
|
70
|
+
html += HTML.textElement( "h2", title );
|
65
71
|
html += listsHTML;
|
66
72
|
html += "</div>";
|
67
73
|
return html;
|
@@ -83,6 +89,7 @@ class PageRenderer extends BasePageRenderer {
|
|
83
89
|
name: "CNPS Ranked Plants",
|
84
90
|
filename: "list_rpi",
|
85
91
|
include: ( t ) => t.getRPIRank() !== undefined,
|
92
|
+
columns: RPI_COLUMNS,
|
86
93
|
listInfo: [
|
87
94
|
{
|
88
95
|
name: RarePlants.getRPIRankDescription( "1A" ),
|
@@ -120,6 +127,7 @@ class PageRenderer extends BasePageRenderer {
|
|
120
127
|
name: "California Endangered Species Act",
|
121
128
|
filename: "list_cesa",
|
122
129
|
include: ( t ) => t.getCESA() !== undefined,
|
130
|
+
columns: RPI_CESA,
|
123
131
|
listInfo: [
|
124
132
|
{
|
125
133
|
name: RarePlants.getCESADescription( "CE" ),
|
@@ -150,7 +158,7 @@ class PageRenderer extends BasePageRenderer {
|
|
150
158
|
let html = "<div class=\"wrapper\">";
|
151
159
|
for ( const section of sections ) {
|
152
160
|
|
153
|
-
const listHTML = getListArray( section.listInfo );
|
161
|
+
const listHTML = getListArray( section.listInfo, section.listInfo.columns );
|
154
162
|
|
155
163
|
if ( listHTML.length > 0 ) {
|
156
164
|
html += renderSection( section.title, listHTML );
|
@@ -170,20 +178,20 @@ class PageRenderer extends BasePageRenderer {
|
|
170
178
|
|
171
179
|
class PageTaxonList extends HTMLPage {
|
172
180
|
|
173
|
-
render( outputDir, taxa, baseName, title ) {
|
181
|
+
render( outputDir, taxa, baseName, title, columns ) {
|
174
182
|
|
175
183
|
let html = this.getFrontMatter( title );
|
176
184
|
|
177
|
-
html += HTML.
|
185
|
+
html += HTML.textElement( "h1", title );
|
178
186
|
|
179
187
|
html += "<div class=\"wrapper\">";
|
180
188
|
|
181
189
|
html += "<div class=\"section\">";
|
182
|
-
html += Taxa.getHTMLTable( taxa );
|
190
|
+
html += Taxa.getHTMLTable( taxa, columns );
|
183
191
|
html += "</div>";
|
184
192
|
|
185
193
|
html += "<div class=\"section\">";
|
186
|
-
html += HTML.
|
194
|
+
html += HTML.textElement( "h2", "Download" );
|
187
195
|
html += "<ul>";
|
188
196
|
html += "<li>" + HTML.getLink( "./calflora_" + baseName + ".txt", "Calflora List" ) + "</li>";
|
189
197
|
html += "<li>" + HTML.getLink( "./inat_" + baseName + ".txt", "iNaturalist List" ) + "</li>";
|
package/lib/taxa.js
CHANGED
@@ -1,29 +1,56 @@
|
|
1
1
|
import { Taxon } from "./taxon.js";
|
2
2
|
import { ErrorLog } from "./errorlog.js";
|
3
|
-
import { HTML
|
3
|
+
import { HTML } from "./html.js";
|
4
4
|
import { CSV } from "./csv.js";
|
5
|
+
import { RarePlants } from "./rareplants.js";
|
6
|
+
|
7
|
+
const COLUMNS = {
|
8
|
+
COL_CESA: "CESA",
|
9
|
+
COL_COMMON_NAME: "Common Name",
|
10
|
+
COL_CNPS_RANK: "CNPS Rank",
|
11
|
+
COL_SPECIES: "Species",
|
12
|
+
};
|
13
|
+
|
14
|
+
const DEFAULT_COLUMNS = [ COLUMNS.COL_SPECIES, COLUMNS.COL_COMMON_NAME ];
|
5
15
|
|
6
16
|
class Taxa {
|
7
17
|
|
8
18
|
static #taxa = {};
|
9
19
|
static #sortedTaxa;
|
10
20
|
|
11
|
-
static getHTMLTable( taxa ) {
|
21
|
+
static getHTMLTable( taxa, columns = DEFAULT_COLUMNS ) {
|
22
|
+
|
23
|
+
let includeRPI = true;
|
24
|
+
|
12
25
|
let html = "<table><thead>";
|
13
|
-
|
14
|
-
|
26
|
+
for ( const column of columns ) {
|
27
|
+
html += HTML.textElement( "th", column );
|
28
|
+
if ( column === COLUMNS.COL_CNPS_RANK ) {
|
29
|
+
// Don't show rarity with species link if CNPS Rank column is included.
|
30
|
+
includeRPI = false;
|
31
|
+
}
|
32
|
+
}
|
15
33
|
html += "</thead>";
|
16
34
|
html += "<tbody>";
|
17
35
|
|
18
36
|
for ( const taxon of taxa ) {
|
19
37
|
html += "<tr>";
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
38
|
+
for ( const column of columns ) {
|
39
|
+
switch ( column ) {
|
40
|
+
case COLUMNS.COL_CESA:
|
41
|
+
html += HTML.textElement( "td", RarePlants.getCESADescription( taxon.getCESA() ) );
|
42
|
+
break;
|
43
|
+
case COLUMNS.COL_COMMON_NAME:
|
44
|
+
html += HTML.textElement( "td", taxon.getCommonNames().join( ", " ) );
|
45
|
+
break;
|
46
|
+
case COLUMNS.COL_CNPS_RANK:
|
47
|
+
html += HTML.wrap( "td", HTML.wrap( "span", taxon.getRPIRankAndThreat(), taxon.getRPIRankAndThreatTooltip( {} ) ) );
|
48
|
+
break;
|
49
|
+
case COLUMNS.COL_SPECIES:
|
50
|
+
html += HTML.wrap( "td", taxon.getHTMLLink( true, includeRPI ) );
|
51
|
+
break;
|
52
|
+
}
|
53
|
+
}
|
27
54
|
html += "</tr>";
|
28
55
|
}
|
29
56
|
|
@@ -93,4 +120,4 @@ class Taxa {
|
|
93
120
|
|
94
121
|
}
|
95
122
|
|
96
|
-
export { Taxa };
|
123
|
+
export { Taxa, COLUMNS };
|
package/lib/taxon.js
CHANGED
@@ -100,14 +100,17 @@ class Taxon {
|
|
100
100
|
return this.#genus;
|
101
101
|
}
|
102
102
|
|
103
|
-
getHTMLLink( href = true ) {
|
103
|
+
getHTMLLink( href = true, includeRPI = true ) {
|
104
104
|
href = href ? ( "./" + this.getFileName() ) : undefined;
|
105
|
-
|
105
|
+
let className = this.isNative() ? "native" : "non-native";
|
106
|
+
if ( includeRPI && this.isRare() ) {
|
107
|
+
className = "rare";
|
108
|
+
}
|
106
109
|
const attributes = { class: className };
|
107
110
|
if ( className === "rare" ) {
|
108
|
-
|
111
|
+
this.getRPIRankAndThreatTooltip( attributes );
|
109
112
|
}
|
110
|
-
return HTML.
|
113
|
+
return HTML.wrap( "span", HTML.getLink( href, this.getName() ), attributes );
|
111
114
|
}
|
112
115
|
|
113
116
|
getINatID() {
|
@@ -151,6 +154,11 @@ class Taxon {
|
|
151
154
|
return this.#rankRPI;
|
152
155
|
}
|
153
156
|
|
157
|
+
getRPIRankAndThreatTooltip( attributes ) {
|
158
|
+
attributes[ "title" ] = RarePlants.getRPIRankAndThreatDescriptions( this.getRPIRankAndThreat() ).join( "\n" );
|
159
|
+
return attributes;
|
160
|
+
}
|
161
|
+
|
154
162
|
getRPITaxonLink() {
|
155
163
|
const rpiID = this.getRPIID();
|
156
164
|
if ( !rpiID ) {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@ca-plant-list/ca-plant-list",
|
3
|
-
"version": "0.1.
|
3
|
+
"version": "0.1.8",
|
4
4
|
"description": "Tools to create Jekyll files for a website listing plants in an area of California.",
|
5
5
|
"license": "MIT",
|
6
6
|
"repository": {
|
@@ -10,16 +10,21 @@
|
|
10
10
|
"homepage": "https://github.com/ca-plants/ca-plant-list",
|
11
11
|
"type": "module",
|
12
12
|
"exports": {
|
13
|
-
".": "./lib/index.js"
|
13
|
+
".": "./lib/index.js",
|
14
|
+
"./HTML": "./lib/HTML.js"
|
14
15
|
},
|
16
|
+
"types": "./lib/index.d.ts",
|
15
17
|
"bin": {
|
16
18
|
"ca-plant-list": "build-site.js"
|
17
19
|
},
|
18
20
|
"dependencies": {
|
19
21
|
"command-line-args": "^5.2.1",
|
20
|
-
"csv-parse": "^5.3.1"
|
22
|
+
"csv-parse": "^5.3.1",
|
23
|
+
"unzipper": "^0.10.11"
|
21
24
|
},
|
22
25
|
"devDependencies": {
|
23
|
-
"
|
26
|
+
"@types/node": "^18.11.9",
|
27
|
+
"eslint": "^8.26.0",
|
28
|
+
"typescript": "^4.9.3"
|
24
29
|
}
|
25
|
-
}
|
30
|
+
}
|
package/tsconfig.json
ADDED