@ca-plant-list/ca-plant-list 0.4.26 → 0.4.28
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/data/exceptions.json +0 -27
- package/data/genera.json +52 -28
- package/data/glossary/anther.md +3 -0
- package/data/glossary/filament.md +3 -0
- package/data/glossary/stamen.md +3 -0
- package/data/illustrations/inkscape/stamen.svg +132 -0
- package/data/inatobsphotos.csv +0 -5
- package/data/inattaxonphotos.csv +69 -64
- package/data/synonyms.csv +155 -164
- package/data/taxa.csv +38 -38
- package/data/text/Dichelostemma-congestum.md +1 -0
- package/data/text/Dipterostemon-capitatus-subsp-capitatus.md +1 -0
- package/generators/eleventy/layouts/h1.njk +6 -0
- package/generators/eleventy/layouts/html.njk +55 -0
- package/lib/basepagerenderer.js +35 -15
- package/lib/config.js +5 -3
- package/lib/ebook/ebookpage.js +1 -4
- package/lib/ebook/ebooksitegenerator.js +4 -12
- package/lib/ebook/glossarypages.js +1 -3
- package/lib/ebook/plantbook.js +1 -1
- package/lib/files.js +1 -0
- package/lib/htmltaxon.js +8 -19
- package/lib/index.d.ts +20 -8
- package/lib/index.js +4 -2
- package/lib/jekyll.js +40 -59
- package/lib/markdown.js +3 -5
- package/lib/sitegenerator.js +68 -12
- package/lib/taxonomy/taxon.js +5 -1
- package/lib/tools/cch2.js +37 -18
- package/lib/tools/jepsonfamilies.js +1 -1
- package/lib/types.js +4 -0
- package/lib/utils/eleventyGenerator.js +82 -0
- package/lib/utils/htmlFragments.js +19 -0
- package/lib/web/glossarypages.js +6 -10
- package/lib/web/pageFamily.js +14 -14
- package/lib/web/pageGeneric.js +78 -0
- package/lib/web/{pagetaxon.js → pageTaxon.js} +4 -4
- package/lib/web/pageTaxonList.js +53 -0
- package/lib/{pagerenderer.js → web/renderAllPages.js} +38 -80
- package/package.json +12 -10
- package/scripts/build-site.js +20 -52
- package/scripts/cpl-photos.js +61 -24
- package/scripts/cpl-tools.js +4 -1
- package/static/assets/js/nameSearchData.js +2 -0
- package/{jekyll → static}/assets/js/name_search.js +12 -14
- package/static/name_search.html +15 -0
- package/jekyll/_includes/glossary.html +0 -0
- package/jekyll/name_search.html +0 -17
- package/lib/genericpage.js +0 -88
- /package/{jekyll → generators}/_includes/analytics.html +0 -0
- /package/{jekyll → generators}/_includes/menu_extra.html +0 -0
- /package/{jekyll → generators/jekyll}/_config.yml +0 -0
- /package/{jekyll → generators/jekyll}/_layouts/default.html +0 -0
- /package/{jekyll → generators/jekyll}/_layouts/html.html +0 -0
- /package/{jekyll → static}/assets/css/main.css +0 -0
- /package/{jekyll → static}/assets/js/ui.js +0 -0
- /package/{jekyll → static}/assets/js/utils.js +0 -0
- /package/{jekyll → static}/index.md +0 -0
package/lib/index.d.ts
CHANGED
@@ -15,6 +15,10 @@ type RefSourceCode =
|
|
15
15
|
| "jepson"
|
16
16
|
| "rpi";
|
17
17
|
|
18
|
+
type SiteGeneratorOptions = {
|
19
|
+
passThroughPatterns?: string[];
|
20
|
+
};
|
21
|
+
|
18
22
|
type TaxaColDef<T> = {
|
19
23
|
title: string;
|
20
24
|
class?: string;
|
@@ -53,8 +57,13 @@ export type TaxonOverrides = {
|
|
53
57
|
// Classes
|
54
58
|
|
55
59
|
export class BasePageRenderer {
|
56
|
-
static
|
60
|
+
static newSiteGenerator(
|
61
|
+
config: Config,
|
57
62
|
outputDir: string,
|
63
|
+
options?: SiteGeneratorOptions,
|
64
|
+
): SiteGenerator;
|
65
|
+
static renderBasePages<T extends Taxon>(
|
66
|
+
siteGenerator: SiteGenerator,
|
58
67
|
taxa: Taxa<T>,
|
59
68
|
familyCols?: TaxaColDef<T>[],
|
60
69
|
): void;
|
@@ -150,6 +159,10 @@ export class HTML {
|
|
150
159
|
): string;
|
151
160
|
}
|
152
161
|
|
162
|
+
export class HTMLFragments {
|
163
|
+
static getMarkdownSection(filePath: string): string;
|
164
|
+
}
|
165
|
+
|
153
166
|
export class HTMLTaxon {
|
154
167
|
static addLink(
|
155
168
|
links: string[],
|
@@ -174,13 +187,6 @@ export class HTMLTaxon {
|
|
174
187
|
header: string,
|
175
188
|
className?: string,
|
176
189
|
): string;
|
177
|
-
static getMarkdownSection(filePath: string): string;
|
178
|
-
}
|
179
|
-
|
180
|
-
export class Jekyll {
|
181
|
-
static hasInclude(baseDir: string, path: string): boolean;
|
182
|
-
static include(fileName: string): string;
|
183
|
-
static writeInclude(baseDir: string, path: string, data: string): void;
|
184
190
|
}
|
185
191
|
|
186
192
|
export class Photo {
|
@@ -196,6 +202,12 @@ export class Program {
|
|
196
202
|
static getProgram(): Command;
|
197
203
|
}
|
198
204
|
|
205
|
+
export class SiteGenerator {
|
206
|
+
generate(outputDir: string): Promise<void>;
|
207
|
+
getBaseDir(): string;
|
208
|
+
getFrontMatter(atts: Record<string, string | undefined>): string;
|
209
|
+
}
|
210
|
+
|
199
211
|
export class Taxa<T> {
|
200
212
|
constructor(
|
201
213
|
inclusionList: Record<string, TaxonOverrides> | true,
|
package/lib/index.js
CHANGED
@@ -7,10 +7,11 @@ import { ExternalSites } from "./externalsites.js";
|
|
7
7
|
import { Families } from "./taxonomy/families.js";
|
8
8
|
import { Files } from "./files.js";
|
9
9
|
import { HTML } from "./html.js";
|
10
|
+
import { HTMLFragments } from "./utils/htmlFragments.js";
|
10
11
|
import { HTMLTaxon } from "./htmltaxon.js";
|
11
|
-
import { Jekyll } from "./jekyll.js";
|
12
12
|
import { PlantBook } from "./ebook/plantbook.js";
|
13
13
|
import { Program } from "./program.js";
|
14
|
+
import { SiteGenerator } from "./sitegenerator.js";
|
14
15
|
import { Taxa } from "./taxonomy/taxa.js";
|
15
16
|
import { Taxon } from "./taxonomy/taxon.js";
|
16
17
|
|
@@ -24,10 +25,11 @@ export {
|
|
24
25
|
Families,
|
25
26
|
Files,
|
26
27
|
HTML,
|
28
|
+
HTMLFragments,
|
27
29
|
HTMLTaxon,
|
28
|
-
Jekyll,
|
29
30
|
PlantBook,
|
30
31
|
Program,
|
32
|
+
SiteGenerator,
|
31
33
|
Taxa,
|
32
34
|
Taxon,
|
33
35
|
};
|
package/lib/jekyll.js
CHANGED
@@ -1,71 +1,52 @@
|
|
1
|
+
import * as child_process from "node:child_process";
|
2
|
+
import * as path from "node:path";
|
1
3
|
import { Files } from "./files.js";
|
2
4
|
import { SiteGenerator } from "./sitegenerator.js";
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
import { Config } from "./config.js";
|
6
|
+
|
7
|
+
export class Jekyll extends SiteGenerator {
|
8
|
+
copyGeneratorFiles() {
|
9
|
+
// First copy default files from package.
|
10
|
+
Files.copyDir(
|
11
|
+
path.join(Config.getPackageDir(), "./generators/jekyll"),
|
12
|
+
this.getBaseDir(),
|
13
|
+
);
|
14
|
+
// Then copy files from current dir (which may override default files).
|
15
|
+
Files.copyDir("./generators/jekyll", this.getBaseDir());
|
12
16
|
}
|
13
17
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
async generate() {
|
19
|
+
/**
|
20
|
+
* @param {string[]} configFiles
|
21
|
+
* @param {string} dir
|
22
|
+
* @param {string} name
|
23
|
+
*/
|
24
|
+
function addConfigFile(configFiles, dir, name) {
|
25
|
+
const fullPath = path.join(dir, name);
|
26
|
+
if (Files.exists(fullPath)) {
|
27
|
+
configFiles.push(fullPath);
|
28
|
+
}
|
21
29
|
}
|
22
|
-
if (!atts.layout) {
|
23
|
-
lines.push("layout: default");
|
24
|
-
}
|
25
|
-
lines.push(FRONT_DELIM);
|
26
|
-
return lines.join("\n") + "\n";
|
27
|
-
}
|
28
30
|
|
29
|
-
|
30
|
-
|
31
|
-
* @param {string} path
|
32
|
-
*/
|
33
|
-
static hasInclude(baseDir, path) {
|
34
|
-
return Files.exists(baseDir + "/_includes/" + path);
|
35
|
-
}
|
31
|
+
const srcDir = "./output";
|
32
|
+
const destDir = "./public";
|
36
33
|
|
37
|
-
|
38
|
-
|
39
|
-
*/
|
40
|
-
static include(path) {
|
41
|
-
// This works for .md includes; should have conditional logic to detect other types.
|
42
|
-
return (
|
43
|
-
"{% capture my_include %}{% include " +
|
44
|
-
path +
|
45
|
-
" %}{% endcapture %}{{ my_include | markdownify }}"
|
46
|
-
);
|
47
|
-
}
|
34
|
+
// Remove existing files.
|
35
|
+
Files.rmDir(destDir);
|
48
36
|
|
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);
|
56
|
-
}
|
37
|
+
const options = ["--source", srcDir, "--destination", destDir];
|
57
38
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
39
|
+
// Find out what config files are available.
|
40
|
+
/** @type {string[]} */
|
41
|
+
const configFiles = [];
|
42
|
+
addConfigFile(configFiles, srcDir, "_config.yml");
|
43
|
+
addConfigFile(configFiles, srcDir, "_config-local.yml");
|
44
|
+
addConfigFile(configFiles, ".", "_config-dev.yml");
|
45
|
+
options.push("--config", `"${configFiles.join()}"`);
|
46
|
+
|
47
|
+
const result = child_process.execSync(
|
48
|
+
"bundle exec jekyll build " + options.join(" "),
|
67
49
|
);
|
50
|
+
console.log(result.toString());
|
68
51
|
}
|
69
52
|
}
|
70
|
-
|
71
|
-
export { Jekyll };
|
package/lib/markdown.js
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
import markdownIt from "markdown-it";
|
2
2
|
import { Files } from "./files.js";
|
3
3
|
|
4
|
-
class Markdown {
|
4
|
+
export class Markdown {
|
5
5
|
static #md = new markdownIt({ xhtmlOut: true });
|
6
6
|
|
7
7
|
/**
|
8
8
|
* @param {string} filePath
|
9
|
-
* @returns {string
|
9
|
+
* @returns {string}
|
10
10
|
*/
|
11
11
|
static fileToHTML(filePath) {
|
12
12
|
if (!Files.exists(filePath)) {
|
13
|
-
return;
|
13
|
+
return "";
|
14
14
|
}
|
15
15
|
return this.strToHTML(Files.read(filePath));
|
16
16
|
}
|
@@ -22,5 +22,3 @@ class Markdown {
|
|
22
22
|
return this.#md.render(str);
|
23
23
|
}
|
24
24
|
}
|
25
|
-
|
26
|
-
export { Markdown };
|
package/lib/sitegenerator.js
CHANGED
@@ -1,16 +1,29 @@
|
|
1
|
+
import path from "node:path";
|
1
2
|
import { optimize } from "svgo-ll";
|
2
3
|
|
3
4
|
import { Config } from "./config.js";
|
4
5
|
import { Files } from "./files.js";
|
5
6
|
|
6
|
-
|
7
|
+
const FRONT_DELIM = "---";
|
8
|
+
|
9
|
+
export class SiteGenerator {
|
10
|
+
#config;
|
7
11
|
#baseDir;
|
12
|
+
#options;
|
8
13
|
|
9
14
|
/**
|
15
|
+
* @param {Config} config
|
10
16
|
* @param {string} baseDir
|
17
|
+
* @param {import("./index.js").SiteGeneratorOptions} [options]
|
11
18
|
*/
|
12
|
-
constructor(baseDir) {
|
19
|
+
constructor(config, baseDir, options = {}) {
|
20
|
+
this.#config = config;
|
13
21
|
this.#baseDir = baseDir;
|
22
|
+
this.#options = options;
|
23
|
+
}
|
24
|
+
|
25
|
+
copyGeneratorFiles() {
|
26
|
+
throw new Error("must be implemented by subclass");
|
14
27
|
}
|
15
28
|
|
16
29
|
/**
|
@@ -23,11 +36,11 @@ class SiteGenerator {
|
|
23
36
|
*/
|
24
37
|
function createFlowerColorIcons(outputDir, flowerColors) {
|
25
38
|
// Read generic input.
|
26
|
-
const inputFileName =
|
39
|
+
const inputFileName = path.join(outputDir, "flower.svg");
|
27
40
|
const srcSVG = Files.read(inputFileName);
|
28
41
|
for (const color of flowerColors) {
|
29
42
|
Files.write(
|
30
|
-
|
43
|
+
path.join(outputDir, "f-" + color.getColorName() + ".svg"),
|
31
44
|
srcSVG.replace("#ff0", color.getColorCode()),
|
32
45
|
);
|
33
46
|
}
|
@@ -59,26 +72,69 @@ class SiteGenerator {
|
|
59
72
|
createFlowerColorIcons(outputDir, flowerColors);
|
60
73
|
}
|
61
74
|
|
75
|
+
copyStaticFiles() {
|
76
|
+
// First copy default files from ca-plant-list.
|
77
|
+
Files.copyDir(
|
78
|
+
path.join(Config.getPackageDir(), "static"),
|
79
|
+
this.#baseDir,
|
80
|
+
);
|
81
|
+
// Then copy files from current directory (which may override default files).
|
82
|
+
Files.copyDir("./static", this.#baseDir);
|
83
|
+
}
|
84
|
+
|
85
|
+
/**
|
86
|
+
* @param {string} webDir
|
87
|
+
*/
|
88
|
+
// eslint-disable-next-line no-unused-vars
|
89
|
+
async generate(webDir) {
|
90
|
+
throw new Error("must be implemented by subclass");
|
91
|
+
}
|
92
|
+
|
62
93
|
getBaseDir() {
|
63
94
|
return this.#baseDir;
|
64
95
|
}
|
65
96
|
|
97
|
+
getConfig() {
|
98
|
+
return this.#config;
|
99
|
+
}
|
100
|
+
|
66
101
|
/**
|
67
|
-
* @param {string}
|
102
|
+
* @param {Object<string,string|undefined>} atts
|
68
103
|
*/
|
69
|
-
|
70
|
-
|
104
|
+
getFrontMatter(atts) {
|
105
|
+
const lines = [FRONT_DELIM];
|
106
|
+
for (const [k, v] of Object.entries(atts)) {
|
107
|
+
if (v) {
|
108
|
+
lines.push(k + ': "' + v + '"');
|
109
|
+
}
|
110
|
+
}
|
111
|
+
lines.push(FRONT_DELIM);
|
112
|
+
return lines.join("\n") + "\n\n";
|
113
|
+
}
|
114
|
+
|
115
|
+
/**
|
116
|
+
* @returns {string[]}
|
117
|
+
*/
|
118
|
+
getPassThroughPatterns() {
|
119
|
+
return this.#options.passThroughPatterns ?? [];
|
120
|
+
}
|
121
|
+
|
122
|
+
/**
|
123
|
+
* @param {string} outputSubdir
|
124
|
+
*/
|
125
|
+
mkdir(outputSubdir) {
|
126
|
+
Files.mkdir(path.join(this.#baseDir, outputSubdir));
|
71
127
|
}
|
72
128
|
|
73
129
|
/**
|
74
130
|
* @param {string} content
|
75
|
-
* @param {
|
131
|
+
* @param {Object<string,string>} attributes
|
76
132
|
* @param {string} filename
|
77
133
|
*/
|
78
|
-
// eslint-disable-next-line no-unused-vars
|
79
134
|
writeTemplate(content, attributes, filename) {
|
80
|
-
|
135
|
+
Files.write(
|
136
|
+
path.join(this.getBaseDir(), filename),
|
137
|
+
this.getFrontMatter(attributes) + content,
|
138
|
+
);
|
81
139
|
}
|
82
140
|
}
|
83
|
-
|
84
|
-
export { SiteGenerator };
|
package/lib/taxonomy/taxon.js
CHANGED
package/lib/tools/cch2.js
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
import path from "node:path";
|
2
|
+
import { renameSync } from "node:fs";
|
3
|
+
import puppeteer from "puppeteer";
|
2
4
|
import { CSV } from "../csv.js";
|
3
5
|
import { TaxaCSV } from "./taxacsv.js";
|
4
6
|
import { Files } from "../files.js";
|
5
|
-
import puppeteer from "puppeteer";
|
6
|
-
import { renameSync } from "node:fs";
|
7
7
|
|
8
8
|
/**
|
9
9
|
* @typedef {{id:string}} CCHTaxon
|
@@ -29,12 +29,12 @@ export class CCH2 {
|
|
29
29
|
) {
|
30
30
|
const toolsDataPath = path.join(toolsDataDir, "cch2");
|
31
31
|
|
32
|
-
const cchTaxa = await getCCHTaxa(toolsDataPath
|
32
|
+
const cchTaxa = await getCCHTaxa(toolsDataPath);
|
33
33
|
|
34
34
|
const idsToUpdate = new Map();
|
35
35
|
for (const taxon of taxa.getTaxonList()) {
|
36
36
|
const name = taxon.getName();
|
37
|
-
const cchTaxon = cchTaxa
|
37
|
+
const cchTaxon = getCCHTaxon(taxon, cchTaxa);
|
38
38
|
if (!cchTaxon) {
|
39
39
|
if (!exceptions.hasException(name, "cch", "notincch")) {
|
40
40
|
errorLog.log(name, "not found in CCH data");
|
@@ -106,27 +106,18 @@ export class CCH2 {
|
|
106
106
|
|
107
107
|
/**
|
108
108
|
* @param {string} toolsDataPath
|
109
|
-
* @param {import("../types.js").Taxa} taxa
|
110
109
|
* @returns {Promise<CCHTaxa>}
|
111
110
|
*/
|
112
|
-
async function getCCHTaxa(toolsDataPath
|
111
|
+
async function getCCHTaxa(toolsDataPath) {
|
113
112
|
/**
|
114
|
-
* @param {{taxonID:string,scientificName:string,rankID:string,acceptance:"0"|"1",acceptedTaxonID:string}} record
|
113
|
+
* @param {{taxonID:string,scientificName:string,rankID:string,acceptance:"0"|"1",acceptedTaxonID:string,acceptedScientificName:string}} record
|
115
114
|
*/
|
116
115
|
function callback(record) {
|
117
116
|
if (parseInt(record.rankID) < 220) {
|
118
117
|
// Ignore ranks above species.
|
119
118
|
return;
|
120
119
|
}
|
121
|
-
|
122
|
-
// If we're not tracking the taxon, ignore it.
|
123
|
-
return;
|
124
|
-
}
|
125
|
-
if (record.acceptance !== "1" && data.has(record.scientificName)) {
|
126
|
-
// Only add the synonym if there is no main entry.
|
127
|
-
return;
|
128
|
-
}
|
129
|
-
data.set(record.scientificName, { id: record.acceptedTaxonID });
|
120
|
+
cchTaxa.set(record.scientificName, { id: record.taxonID });
|
130
121
|
}
|
131
122
|
|
132
123
|
const fileName = path.join(toolsDataPath, "taxa.csv");
|
@@ -134,11 +125,39 @@ async function getCCHTaxa(toolsDataPath, taxa) {
|
|
134
125
|
await retrieveDataFile(toolsDataPath);
|
135
126
|
}
|
136
127
|
|
137
|
-
const
|
128
|
+
const cchTaxa = new Map();
|
138
129
|
|
139
130
|
await CSV.parseFileStream(fileName, callback);
|
140
131
|
|
141
|
-
return
|
132
|
+
return cchTaxa;
|
133
|
+
}
|
134
|
+
|
135
|
+
/**
|
136
|
+
* @param {import("../types.js").Taxon} taxon
|
137
|
+
* @param {CCHTaxa} cchTaxa
|
138
|
+
* @returns {CCHTaxon|undefined}
|
139
|
+
*/
|
140
|
+
function getCCHTaxon(taxon, cchTaxa) {
|
141
|
+
/**
|
142
|
+
* @param {string} name
|
143
|
+
*/
|
144
|
+
function getTaxon(name) {
|
145
|
+
return cchTaxa.get(name);
|
146
|
+
}
|
147
|
+
|
148
|
+
const name = taxon.getName();
|
149
|
+
const cchTaxon = getTaxon(name);
|
150
|
+
if (cchTaxon) {
|
151
|
+
return cchTaxon;
|
152
|
+
}
|
153
|
+
|
154
|
+
// No reference for the current name; try synonyms and see if any of them work.
|
155
|
+
for (const synonym of taxon.getSynonyms()) {
|
156
|
+
const cchTaxon = getTaxon(synonym);
|
157
|
+
if (cchTaxon) {
|
158
|
+
return cchTaxon;
|
159
|
+
}
|
160
|
+
}
|
142
161
|
}
|
143
162
|
|
144
163
|
/**
|
@@ -8,7 +8,7 @@ export class JepsonFamilies {
|
|
8
8
|
* @param {string} outputdir
|
9
9
|
*/
|
10
10
|
static async build(toolsDataDir, outputdir) {
|
11
|
-
const url = "https://ucjeps.berkeley.edu/
|
11
|
+
const url = "https://ucjeps.berkeley.edu/IJM_keys/toc.html";
|
12
12
|
const indexFileName = path.basename(url);
|
13
13
|
const toolsDataPath = toolsDataDir + "/jepsonfam";
|
14
14
|
const indexFilePath = toolsDataPath + "/" + indexFileName;
|
package/lib/types.js
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
/**
|
2
|
+
* Types
|
3
|
+
* @typedef {{t:string,c?:string,s?:string[]}} NameSearchData
|
4
|
+
*
|
2
5
|
* Classes
|
3
6
|
* @typedef {import("./config.js").Config} Config
|
4
7
|
* @typedef {import("./taxonomy/families.js").Families} Families
|
5
8
|
* @typedef {import("./taxonomy/families.js").Family} Family
|
9
|
+
* @typedef {import("./sitegenerator.js").SiteGenerator} SiteGenerator
|
6
10
|
* @typedef {import("./taxonomy/taxa.js").Taxa} Taxa
|
7
11
|
* @typedef {import("./index.js").TaxaColDef<import("./types.js").Taxon>} TaxaColDef
|
8
12
|
* @typedef {import("./taxonomy/taxon.js").Taxon} Taxon
|
@@ -0,0 +1,82 @@
|
|
1
|
+
// @ts-ignore
|
2
|
+
import { Eleventy } from "@11ty/eleventy";
|
3
|
+
import { SiteGenerator } from "../sitegenerator.js";
|
4
|
+
import path from "node:path";
|
5
|
+
import { Files } from "../files.js";
|
6
|
+
import { Config } from "../config.js";
|
7
|
+
|
8
|
+
export class EleventyGenerator extends SiteGenerator {
|
9
|
+
copyGeneratorFiles() {
|
10
|
+
// First copy default files from package.
|
11
|
+
const layoutSrc = "./generators/eleventy/layouts";
|
12
|
+
const commonSrc = "./generators/_includes";
|
13
|
+
const dest = path.join(this.getBaseDir(), "_includes");
|
14
|
+
|
15
|
+
Files.copyDir(path.join(Config.getPackageDir(), commonSrc), dest);
|
16
|
+
Files.copyDir(path.join(Config.getPackageDir(), layoutSrc), dest);
|
17
|
+
|
18
|
+
// Then copy files from current dir (which may override default files).
|
19
|
+
if (Files.isDir(commonSrc)) {
|
20
|
+
Files.copyDir(commonSrc, dest);
|
21
|
+
}
|
22
|
+
if (Files.isDir(layoutSrc)) {
|
23
|
+
Files.copyDir(layoutSrc, dest);
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
/**
|
28
|
+
* @param {string} webDir
|
29
|
+
*/
|
30
|
+
async generate(webDir) {
|
31
|
+
const srcDir = this.getBaseDir();
|
32
|
+
const config = this.getConfig();
|
33
|
+
const generator = this;
|
34
|
+
let elev = new Eleventy(srcDir, webDir, {
|
35
|
+
quietMode: true,
|
36
|
+
config:
|
37
|
+
// @ts-ignore
|
38
|
+
function (eleventyConfig) {
|
39
|
+
// Not running in project root, so using .gitignore will break things.
|
40
|
+
eleventyConfig.setUseGitIgnore(false);
|
41
|
+
|
42
|
+
// Don't change file system structure when writing output files.
|
43
|
+
eleventyConfig.addGlobalData("permalink", () => {
|
44
|
+
// @ts-ignore
|
45
|
+
return (data) => {
|
46
|
+
// Include directories in the generated content.
|
47
|
+
const inputPath = path.relative(
|
48
|
+
srcDir,
|
49
|
+
data.page.inputPath,
|
50
|
+
);
|
51
|
+
// Remove the file extension.
|
52
|
+
const parsed = path.parse(inputPath);
|
53
|
+
return path.join(parsed.dir, `${parsed.name}.html`);
|
54
|
+
};
|
55
|
+
});
|
56
|
+
|
57
|
+
// Use layout with <h1> by default.
|
58
|
+
eleventyConfig.addGlobalData("layout", "h1.njk");
|
59
|
+
|
60
|
+
// Set site name for use in nav bar.
|
61
|
+
eleventyConfig.addGlobalData(
|
62
|
+
"siteName",
|
63
|
+
config.getSiteName(),
|
64
|
+
);
|
65
|
+
|
66
|
+
const passThroughPatterns = [
|
67
|
+
"assets",
|
68
|
+
"i",
|
69
|
+
"errors.tsv",
|
70
|
+
...generator.getPassThroughPatterns(),
|
71
|
+
];
|
72
|
+
for (const pattern of passThroughPatterns) {
|
73
|
+
eleventyConfig.addPassthroughCopy(
|
74
|
+
// Eleventy apparently can't handle windows paths in globs, so change it.
|
75
|
+
path.join(srcDir, pattern).replaceAll("\\", "/"),
|
76
|
+
);
|
77
|
+
}
|
78
|
+
},
|
79
|
+
});
|
80
|
+
await elev.write();
|
81
|
+
}
|
82
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { HTML } from "../html.js";
|
2
|
+
import { Markdown } from "../markdown.js";
|
3
|
+
|
4
|
+
/**
|
5
|
+
* Utilities to create HTML fragments specific to ca-plant-list.
|
6
|
+
*/
|
7
|
+
export class HTMLFragments {
|
8
|
+
/**
|
9
|
+
* @param {string} filePath
|
10
|
+
* @returns {string}
|
11
|
+
*/
|
12
|
+
static getMarkdownSection(filePath) {
|
13
|
+
const footerMarkdown = Markdown.fileToHTML(filePath);
|
14
|
+
if (footerMarkdown) {
|
15
|
+
return HTML.wrap("div", footerMarkdown, "section");
|
16
|
+
}
|
17
|
+
return "";
|
18
|
+
}
|
19
|
+
}
|
package/lib/web/glossarypages.js
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
import { Glossary } from "../plants/glossary.js";
|
2
2
|
import { Markdown } from "../markdown.js";
|
3
3
|
import { HTML } from "../html.js";
|
4
|
-
import
|
4
|
+
import path from "node:path";
|
5
5
|
|
6
6
|
const ENTRY_DIR = "g";
|
7
7
|
|
8
|
-
class GlossaryPages {
|
8
|
+
export class GlossaryPages {
|
9
9
|
#siteGenerator;
|
10
10
|
#glossary;
|
11
11
|
|
@@ -22,14 +22,13 @@ class GlossaryPages {
|
|
22
22
|
*/
|
23
23
|
#generateEntryPage(entry) {
|
24
24
|
const title = entry.getTermName();
|
25
|
-
let html = HTML.
|
26
|
-
html += HTML.wrap("div", Markdown.strToHTML(entry.getMarkdown()), {
|
25
|
+
let html = HTML.wrap("div", Markdown.strToHTML(entry.getMarkdown()), {
|
27
26
|
class: "glossary",
|
28
27
|
});
|
29
28
|
this.#siteGenerator.writeTemplate(
|
30
29
|
html,
|
31
30
|
{ title: title },
|
32
|
-
|
31
|
+
path.posix.join(ENTRY_DIR, title + ".html"),
|
33
32
|
);
|
34
33
|
}
|
35
34
|
|
@@ -49,13 +48,12 @@ class GlossaryPages {
|
|
49
48
|
for (const entry of entries) {
|
50
49
|
links.push(
|
51
50
|
HTML.getLink(
|
52
|
-
|
51
|
+
path.posix.join(ENTRY_DIR, entry.getHTMLFileName()),
|
53
52
|
entry.getTermName(),
|
54
53
|
),
|
55
54
|
);
|
56
55
|
}
|
57
|
-
|
58
|
-
html += HTML.wrap("ol", HTML.arrayToLI(links));
|
56
|
+
const html = HTML.wrap("ol", HTML.arrayToLI(links));
|
59
57
|
this.#siteGenerator.writeTemplate(
|
60
58
|
html,
|
61
59
|
{ title: "Glossary" },
|
@@ -72,5 +70,3 @@ class GlossaryPages {
|
|
72
70
|
this.#generateEntryPages();
|
73
71
|
}
|
74
72
|
}
|
75
|
-
|
76
|
-
export { GlossaryPages };
|