@rr0/cms 0.1.20 → 0.1.22
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/dist/OpenGraphCommand.d.ts +3 -3
- package/dist/OpenGraphCommand.js +4 -5
- package/dist/OpenGraphCommand.test.js +1 -3
- package/dist/RR0Build.d.ts +0 -1
- package/dist/RR0Build.js +35 -28
- package/dist/RR0Build.test.js +26 -27
- package/dist/RR0ContentStep.d.ts +13 -9
- package/dist/RR0ContentStep.js +15 -35
- package/dist/book/BookService.test.js +5 -4
- package/dist/people/People.test.js +1 -1
- package/dist/people/PeopleFactory.test.js +1 -1
- package/dist/people/PeopleRegexReplaceCommand.test.js +1 -1
- package/dist/people/PeopleReplacer.test.js +2 -2
- package/dist/people/PeopleService.d.ts +3 -1
- package/dist/people/PeopleService.js +4 -4
- package/dist/source/PersistentSourceRegistry.d.ts +2 -1
- package/dist/source/PersistentSourceRegistry.js +2 -2
- package/dist/source/SourceFactory.d.ts +3 -1
- package/dist/source/SourceFactory.js +3 -3
- package/dist/source/SourceRegistry.d.ts +2 -2
- package/dist/source/SourceRegistry.js +2 -2
- package/dist/test/RR0TestUtil.js +1 -2
- package/dist/time/Time.d.ts +0 -15
- package/dist/time/Time.js +0 -57
- package/dist/time/TimeEventRenderer.test.js +1 -1
- package/dist/time/TimeLinkDefaultHandler.js +12 -10
- package/dist/time/TimeService.d.ts +19 -1
- package/dist/time/TimeService.js +78 -1
- package/dist/time/{Time.test.js → TimeService.test.js} +6 -6
- package/dist/time/TitleReplaceCommand.test.js +1 -2
- package/dist/time/datasource/ChronologyReplacer.test.js +4 -3
- package/dist/time/datasource/DatasourceTestCase.js +1 -1
- package/package.json +2 -2
- /package/dist/time/{Time.test.d.ts → TimeService.test.d.ts} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ReplaceCommand } from "ssg-api/dist/src/step/content/replace/ReplaceCommand.js";
|
|
2
2
|
import { HtmlRR0Context } from "./RR0Context.js";
|
|
3
3
|
import { Canvas, CanvasRenderingContext2D } from "canvas";
|
|
4
|
-
import {
|
|
4
|
+
import { TimeService } from "./time/index.js";
|
|
5
5
|
/**
|
|
6
6
|
* Create a preview image for each page sharing.
|
|
7
7
|
*/
|
|
@@ -9,11 +9,11 @@ export declare class OpenGraphCommand implements ReplaceCommand<HtmlRR0Context>
|
|
|
9
9
|
protected outDir: string;
|
|
10
10
|
protected timeFiles: string[];
|
|
11
11
|
protected baseUrl: string;
|
|
12
|
-
protected
|
|
12
|
+
protected timeService: TimeService;
|
|
13
13
|
protected width: number;
|
|
14
14
|
protected height: number;
|
|
15
15
|
protected num: number;
|
|
16
|
-
constructor(outDir: string, timeFiles: string[], baseUrl: string,
|
|
16
|
+
constructor(outDir: string, timeFiles: string[], baseUrl: string, timeService: TimeService, width?: number, height?: number);
|
|
17
17
|
execute(context: HtmlRR0Context): Promise<void>;
|
|
18
18
|
getInfoStr(context: HtmlRR0Context): string;
|
|
19
19
|
contentStepEnd(): Promise<void>;
|
package/dist/OpenGraphCommand.js
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { createCanvas, loadImage } from "canvas";
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import path from "path";
|
|
4
|
-
import { RR0ContentStep } from "./RR0ContentStep.js";
|
|
5
4
|
import assert from "assert";
|
|
6
5
|
/**
|
|
7
6
|
* Create a preview image for each page sharing.
|
|
8
7
|
*/
|
|
9
8
|
export class OpenGraphCommand {
|
|
10
|
-
constructor(outDir, timeFiles, baseUrl,
|
|
9
|
+
constructor(outDir, timeFiles, baseUrl, timeService, width = 1200, height = 600) {
|
|
11
10
|
this.outDir = outDir;
|
|
12
11
|
this.timeFiles = timeFiles;
|
|
13
12
|
this.baseUrl = baseUrl;
|
|
14
|
-
this.
|
|
13
|
+
this.timeService = timeService;
|
|
15
14
|
this.width = width;
|
|
16
15
|
this.height = height;
|
|
17
16
|
this.num = 0;
|
|
@@ -49,14 +48,14 @@ export class OpenGraphCommand {
|
|
|
49
48
|
timeStr = "Chronologie";
|
|
50
49
|
}
|
|
51
50
|
else {
|
|
52
|
-
const timeContext =
|
|
51
|
+
const timeContext = this.timeService.gSetTimeFromPath(context, fileName);
|
|
53
52
|
if (timeContext) {
|
|
54
53
|
context.time.setYear(timeContext.getYear());
|
|
55
54
|
context.time.setMonth(timeContext.getMonth());
|
|
56
55
|
context.time.setDayOfMonth(timeContext.getDayOfMonth());
|
|
57
56
|
context.time.setHour(undefined);
|
|
58
57
|
context.time.setMinutes(undefined);
|
|
59
|
-
timeStr = this.
|
|
58
|
+
timeStr = this.timeService.textBuilder.build(context);
|
|
60
59
|
}
|
|
61
60
|
}
|
|
62
61
|
const copyrightStr = context.file.meta.copyright || "RR0.org";
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { OpenGraphCommand } from "./OpenGraphCommand.js";
|
|
2
2
|
import { rr0TestUtil } from "./test/index.js";
|
|
3
3
|
import { describe, expect, test } from "@javarome/testscript";
|
|
4
|
-
import { TimeTextBuilder } from "./time/index.js";
|
|
5
4
|
describe("OpenGraphCommand", () => {
|
|
6
5
|
const outDir = "/out";
|
|
7
6
|
test("time page", () => {
|
|
8
7
|
const timeFile = rr0TestUtil.time.filePath("0/0/6/5/index.html");
|
|
9
8
|
const context = rr0TestUtil.newHtmlContext(timeFile, "");
|
|
10
|
-
const
|
|
11
|
-
const command = new OpenGraphCommand(outDir, [context.file.name], "https://rr0.org", timeTextBuilder);
|
|
9
|
+
const command = new OpenGraphCommand(outDir, [context.file.name], "https://rr0.org", rr0TestUtil.time.getService());
|
|
12
10
|
expect(command.getInfoStr(context)).toBe("Chronologie, RR0.org");
|
|
13
11
|
});
|
|
14
12
|
});
|
package/dist/RR0Build.d.ts
CHANGED
package/dist/RR0Build.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import fs from "fs";
|
|
3
|
-
import { CaseSummaryRenderer, ChronologyReplacerFactory, CsvMapper, EventReplacer, EventReplacerFactory, HttpSource, RR0Mapping, SsiTitleReplaceCommand,
|
|
3
|
+
import { CaseSummaryRenderer, ChronologyReplacerFactory, CsvMapper, EventReplacer, EventReplacerFactory, HttpSource, RR0Mapping, SsiTitleReplaceCommand, TimeElementFactory, TimeLinkDefaultHandler, TimeReplacer, TimeReplacerFactory, TimeService, TimeTextBuilder, TimeUrlBuilder } from "./time";
|
|
4
4
|
import { CaseDirectoryStep, CaseFactory, CaseService } from "./science/index.js";
|
|
5
5
|
import { GooglePlaceService, PlaceReplacerFactory } from "./place/index.js";
|
|
6
6
|
import { OrganizationFactory, OrganizationService } from "./org/index.js";
|
|
@@ -56,7 +56,7 @@ export class RR0Build {
|
|
|
56
56
|
this.orgService = new OrganizationService([], "org", undefined);
|
|
57
57
|
const timeTextBuilder = this.timeTextBuilder = new TimeTextBuilder(options.timeFormat);
|
|
58
58
|
const timeOptions = options.timeOptions;
|
|
59
|
-
const timeRoot =
|
|
59
|
+
const timeRoot = timeOptions.root;
|
|
60
60
|
const timeUrlBuilder = new TimeUrlBuilder({ rootDir: timeRoot });
|
|
61
61
|
const eventFactory = new RR0EventFactory();
|
|
62
62
|
const sightingFactory = new TypedDataFactory(eventFactory, "sighting", ["index"]);
|
|
@@ -83,19 +83,19 @@ export class RR0Build {
|
|
|
83
83
|
let dataService = this.dataService;
|
|
84
84
|
const caseService = new CaseService(dataService, this.caseFactory, timeElementFactory, caseFiles);
|
|
85
85
|
const peopleFiles = await this.peopleFactory.getFiles();
|
|
86
|
-
const peopleService = new PeopleService(dataService, this.peopleFactory, peopleFiles);
|
|
86
|
+
const peopleService = new PeopleService(dataService, this.peopleFactory, peopleFiles, timeService);
|
|
87
87
|
const peopleList = await peopleService.getAll();
|
|
88
88
|
context.setVar("peopleFilesCount", peopleList.length);
|
|
89
89
|
const bookMeta = new Map();
|
|
90
90
|
const bookLinks = new Map();
|
|
91
91
|
const config = this.config;
|
|
92
|
-
const ufoCaseDirectoryFile = this.options.
|
|
93
|
-
const ufoCasesExclusions = this.options.ufoCasesExclusions
|
|
92
|
+
const ufoCaseDirectoryFile = this.options.ufoCaseDirectoryFile;
|
|
93
|
+
const ufoCasesExclusions = this.options.ufoCasesExclusions;
|
|
94
94
|
const ufoCasesStep = new CaseDirectoryStep(caseService, caseService.files, ufoCasesExclusions, ufoCaseDirectoryFile, outputFunc, config);
|
|
95
95
|
const peopleDirectoryFactory = new PeopleDirectoryStepFactory(outputFunc, config, peopleService, this.options.directoryExcluded);
|
|
96
96
|
const directoryOptions = this.options.directoryOptions;
|
|
97
97
|
for (const directoryOption in directoryOptions) {
|
|
98
|
-
directoryOptions[directoryOption] =
|
|
98
|
+
directoryOptions[directoryOption] = directoryOptions[directoryOption];
|
|
99
99
|
}
|
|
100
100
|
const peopleSteps = await peopleDirectoryFactory.create(directoryOptions);
|
|
101
101
|
// Publish case.json files so that vraiufo.com will find them
|
|
@@ -103,10 +103,11 @@ export class RR0Build {
|
|
|
103
103
|
copies.push(...(ufoCasesStep.config.rootDirs).map(dir => path.join(dir, "case.json")));
|
|
104
104
|
const outDir = this.options.outDir;
|
|
105
105
|
await writeFile(path.join(outDir, "casesDirs.json"), JSON.stringify(ufoCasesStep.config.rootDirs), "utf-8");
|
|
106
|
-
|
|
106
|
+
const dirsContainingPeopleJson = peopleSteps.reduce((rootDirs, peopleStep) => {
|
|
107
107
|
rootDirs.push(...peopleStep.config.rootDirs);
|
|
108
108
|
return rootDirs;
|
|
109
|
-
}, [])
|
|
109
|
+
}, []);
|
|
110
|
+
copies.push(...dirsContainingPeopleJson.map(dir => path.join(dir, "people.json")));
|
|
110
111
|
await writeFile(path.join(outDir, "peopleDirs.json"), JSON.stringify(peopleList.map(people => people.dirName)), "utf-8");
|
|
111
112
|
const timeTextBuilder = this.timeTextBuilder;
|
|
112
113
|
const searchVisitor = new SearchVisitor({ notIndexedUrls: ["404.html", "Referencement.html"], indexWords: false }, timeTextBuilder);
|
|
@@ -114,8 +115,8 @@ export class RR0Build {
|
|
|
114
115
|
const http = new HttpSource();
|
|
115
116
|
const baseUrl = this.options.siteBaseUrl;
|
|
116
117
|
const timeFormat = this.options.timeFormat;
|
|
117
|
-
const sourceRegistryFileName = this.options.
|
|
118
|
-
const sourceFactory = new PersistentSourceRegistry(dataService, http, baseUrl, sourceRegistryFileName, timeFormat);
|
|
118
|
+
const sourceRegistryFileName = this.options.sourceRegistryFileName;
|
|
119
|
+
const sourceFactory = new PersistentSourceRegistry(dataService, http, baseUrl, sourceRegistryFileName, timeFormat, timeService);
|
|
119
120
|
const noteCounter = new NoteFileCounter();
|
|
120
121
|
const noteRenderer = new NoteRenderer(noteCounter);
|
|
121
122
|
const caseRenderer = new CaseSummaryRenderer(noteRenderer, sourceFactory, sourceRenderer, timeElementFactory);
|
|
@@ -128,7 +129,7 @@ export class RR0Build {
|
|
|
128
129
|
], caseRenderer));
|
|
129
130
|
const timeDefaultHandler = (context) => {
|
|
130
131
|
let title;
|
|
131
|
-
title =
|
|
132
|
+
title = timeService.titleFromFile(context, context.file.name, timeTextBuilder);
|
|
132
133
|
return title;
|
|
133
134
|
};
|
|
134
135
|
const pageReplaceCommands = [
|
|
@@ -188,19 +189,22 @@ export class RR0Build {
|
|
|
188
189
|
return path.join(outDir, "netlify.toml");
|
|
189
190
|
}
|
|
190
191
|
};
|
|
191
|
-
const
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
192
|
+
const contentRoots = this.options.contentRoots;
|
|
193
|
+
const contentStepOptions = {
|
|
194
|
+
contentConfigs: [htAccessToNetlifyConfig, {
|
|
195
|
+
roots: contentRoots,
|
|
196
|
+
replacements: [new class extends SsiIncludeReplaceCommand {
|
|
197
|
+
filePath(context, fileNameArg) {
|
|
198
|
+
const dirName = path.dirname(context.file.name);
|
|
199
|
+
return fileNameArg.startsWith("/") ?
|
|
200
|
+
path.join(process.cwd(), fileNameArg) : path.join(dirName, fileNameArg);
|
|
201
|
+
}
|
|
202
|
+
}([csvTransformer])],
|
|
203
|
+
getOutputPath
|
|
204
|
+
}],
|
|
205
|
+
outputFunc, fileVisitors: [], contentVisitors: [], force, name: "content includes", toProcess
|
|
206
|
+
};
|
|
207
|
+
const includeStep = new RR0ContentStep(contentStepOptions, timeService);
|
|
204
208
|
ssg.add(includeStep);
|
|
205
209
|
ssg.add(ufoCasesStep);
|
|
206
210
|
ssg.add(...peopleSteps);
|
|
@@ -216,9 +220,12 @@ export class RR0Build {
|
|
|
216
220
|
new OutlineReplaceCommand(),
|
|
217
221
|
new AnchorReplaceCommand(baseUrl, [new CaseAnchorHandler(caseService, timeTextBuilder), new DataAnchorHandler(dataService)]),
|
|
218
222
|
new ImageCommand(outDir, 275, 500),
|
|
219
|
-
new OpenGraphCommand(outDir, timeFiles, baseUrl,
|
|
223
|
+
new OpenGraphCommand(outDir, timeFiles, baseUrl, timeService)
|
|
220
224
|
];
|
|
221
|
-
ssg.add(new RR0ContentStep(
|
|
225
|
+
ssg.add(new RR0ContentStep({
|
|
226
|
+
contentConfigs: [{ roots: contentRoots, replacements: contentReplacements, getOutputPath }],
|
|
227
|
+
outputFunc, fileVisitors: [], contentVisitors, force, name: "contents replacements", toProcess
|
|
228
|
+
}, timeService));
|
|
222
229
|
}
|
|
223
230
|
if (args.books) {
|
|
224
231
|
ssg.add(await BookDirectoryStep.create(outputFunc, config, bookMeta, bookLinks));
|
|
@@ -233,8 +240,8 @@ export class RR0Build {
|
|
|
233
240
|
if (copies) {
|
|
234
241
|
const copyConfig = {
|
|
235
242
|
getOutputPath,
|
|
236
|
-
sourcePatterns:
|
|
237
|
-
options: { ignore: ["node_modules/**", "out/**"]
|
|
243
|
+
sourcePatterns: Array.from(new Set(copies)),
|
|
244
|
+
options: { ignore: ["node_modules/**", "out/**"] }
|
|
238
245
|
};
|
|
239
246
|
ssg.add(new CopyStep(copyConfig));
|
|
240
247
|
}
|
package/dist/RR0Build.test.js
CHANGED
|
@@ -31,7 +31,7 @@ describe("Build", () => {
|
|
|
31
31
|
"tech/**/*.html",
|
|
32
32
|
"udb/*.html",
|
|
33
33
|
"js/**/*.html"
|
|
34
|
-
];
|
|
34
|
+
].map(testFilePath);
|
|
35
35
|
const copiesArg = args.copies;
|
|
36
36
|
const copies = copiesArg ? copiesArg : [
|
|
37
37
|
"favicon.ico", "manifest.json", "opensearch.xml", "apple-touch-icon.png", "apple-touch-icon_400x400.png", "screenshot1.jpg",
|
|
@@ -47,14 +47,14 @@ describe("Build", () => {
|
|
|
47
47
|
"time/DualRangeComponent.mjs",
|
|
48
48
|
"index/index.js", "lang/form.js", "lang/form.css", "lang/speech.js", "lang/speech.css",
|
|
49
49
|
"croyance/divin/theisme/mono/livre/islam/coran/index.js"
|
|
50
|
-
];
|
|
50
|
+
].map(testFilePath);
|
|
51
51
|
const outDir = "out";
|
|
52
52
|
const googleMapsApiKey = process.env.GOOGLE_MAPS_API_KEY;
|
|
53
53
|
if (!googleMapsApiKey) {
|
|
54
54
|
throw Error("GOOGLE_MAPS_API_KEY is required");
|
|
55
55
|
}
|
|
56
56
|
const timeOptions = {
|
|
57
|
-
root: "time",
|
|
57
|
+
root: testFilePath("time"),
|
|
58
58
|
files: []
|
|
59
59
|
};
|
|
60
60
|
const timeFormat = {
|
|
@@ -66,13 +66,13 @@ describe("Build", () => {
|
|
|
66
66
|
minute: "2-digit"
|
|
67
67
|
};
|
|
68
68
|
async function getTimeFiles() {
|
|
69
|
-
const minusYearFiles = await glob("time/-?/?/?/?/index.html");
|
|
70
|
-
const year1Files = await glob("time/?/index.html");
|
|
71
|
-
const year2Files = await glob("time/?/?/index.html");
|
|
72
|
-
const year3Files = await glob("time/?/?/?/index.html");
|
|
73
|
-
const year4Files = await glob("time/?/?/?/?/index.html");
|
|
74
|
-
const monthFiles = await glob("time/?/?/?/?/??/index.html");
|
|
75
|
-
const dayFiles = await glob("time/?/?/?/?/??/??/index.html");
|
|
69
|
+
const minusYearFiles = await glob(testFilePath("time/-?/?/?/?/index.html"));
|
|
70
|
+
const year1Files = await glob(testFilePath("time/?/index.html"));
|
|
71
|
+
const year2Files = await glob(testFilePath("time/?/?/index.html"));
|
|
72
|
+
const year3Files = await glob(testFilePath("time/?/?/?/index.html"));
|
|
73
|
+
const year4Files = await glob(testFilePath("time/?/?/?/?/index.html"));
|
|
74
|
+
const monthFiles = await glob(testFilePath("time/?/?/?/?/??/index.html"));
|
|
75
|
+
const dayFiles = await glob(testFilePath("time/?/?/?/?/??/??/index.html"));
|
|
76
76
|
return year1Files.concat(year2Files).concat(year3Files).concat(year4Files).concat(minusYearFiles).concat(monthFiles).concat(dayFiles).sort();
|
|
77
77
|
}
|
|
78
78
|
const directoryPages = [
|
|
@@ -82,30 +82,29 @@ describe("Build", () => {
|
|
|
82
82
|
].map(testFilePath);
|
|
83
83
|
getTimeFiles().then(async (timeFiles) => {
|
|
84
84
|
const directoryOptions = {
|
|
85
|
-
root: "people/index.html",
|
|
86
|
-
scientists: "people/scientifiques.html",
|
|
87
|
-
ufologists: "people/ufologues.html",
|
|
88
|
-
ufoWitnesses: "people/witness/index.html",
|
|
89
|
-
astronomers: "people/astronomes.html",
|
|
90
|
-
contactees: "people/contactes.html",
|
|
91
|
-
pilots: "people/pilotes.html",
|
|
92
|
-
military: "people/militaires.html",
|
|
93
|
-
softwareEngineers: "tech/info/Personnes.html",
|
|
94
|
-
politicians: "people/politicians.html",
|
|
95
|
-
rulers: "people/dirigeants.html"
|
|
85
|
+
root: testFilePath("people/index.html"),
|
|
86
|
+
scientists: testFilePath("people/scientifiques.html"),
|
|
87
|
+
ufologists: testFilePath("people/ufologues.html"),
|
|
88
|
+
ufoWitnesses: testFilePath("people/witness/index.html"),
|
|
89
|
+
astronomers: testFilePath("people/astronomes.html"),
|
|
90
|
+
contactees: testFilePath("people/contactes.html"),
|
|
91
|
+
pilots: testFilePath("people/pilotes.html"),
|
|
92
|
+
military: testFilePath("people/militaires.html"),
|
|
93
|
+
softwareEngineers: testFilePath("tech/info/Personnes.html"),
|
|
94
|
+
politicians: testFilePath("people/politicians.html"),
|
|
95
|
+
rulers: testFilePath("people/dirigeants.html")
|
|
96
96
|
};
|
|
97
|
-
const sourceRegistryFileName = "source/index.json";
|
|
97
|
+
const sourceRegistryFileName = testFilePath("source/index.json");
|
|
98
98
|
const siteBaseUrl = "https://rr0.org/";
|
|
99
99
|
const mail = "rr0@rr0.org";
|
|
100
100
|
const build = new RR0Build({
|
|
101
101
|
contentRoots, copies, outDir, locale: "fr", googleMapsApiKey, mail, timeOptions,
|
|
102
102
|
siteBaseUrl, timeFormat, timeFiles, directoryPages,
|
|
103
|
-
ufoCaseDirectoryFile: "science/crypto/ufo/enquete/dossier/index.html",
|
|
104
|
-
ufoCasesExclusions: ["science/crypto/ufo/enquete/dossier/canular"],
|
|
103
|
+
ufoCaseDirectoryFile: testFilePath("science/crypto/ufo/enquete/dossier/index.html"),
|
|
104
|
+
ufoCasesExclusions: ["science/crypto/ufo/enquete/dossier/canular"].map(testFilePath),
|
|
105
105
|
sourceRegistryFileName,
|
|
106
|
-
directoryExcluded: ["people/Astronomers_fichiers", "people/witness", "people/author"],
|
|
107
|
-
directoryOptions
|
|
108
|
-
inDir: testFilePath
|
|
106
|
+
directoryExcluded: ["people/Astronomers_fichiers", "people/witness", "people/author"].map(testFilePath),
|
|
107
|
+
directoryOptions
|
|
109
108
|
});
|
|
110
109
|
await build.run(args);
|
|
111
110
|
});
|
package/dist/RR0ContentStep.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ContentStep, ContentStepConfig, ContentStepResult, OutputFunc } from "ssg-api";
|
|
2
2
|
import { HtmlRR0Context } from "./RR0Context.js";
|
|
3
|
-
import {
|
|
3
|
+
import { TimeService } from "./time/index.js";
|
|
4
4
|
export interface ContentVisitor {
|
|
5
5
|
visit(context: HtmlRR0Context): Promise<void>;
|
|
6
6
|
}
|
|
@@ -8,16 +8,20 @@ export interface FileVisitor {
|
|
|
8
8
|
visit(context: HtmlRR0Context, processFile: boolean): Promise<void>;
|
|
9
9
|
contentStepEnd(): Promise<void>;
|
|
10
10
|
}
|
|
11
|
+
export interface RR0ContentStepOptions {
|
|
12
|
+
contentConfigs: ContentStepConfig[];
|
|
13
|
+
outputFunc: OutputFunc;
|
|
14
|
+
fileVisitors?: FileVisitor[];
|
|
15
|
+
contentVisitors?: ContentVisitor[];
|
|
16
|
+
force: boolean;
|
|
17
|
+
name: string;
|
|
18
|
+
toProcess: Set<string>;
|
|
19
|
+
}
|
|
11
20
|
export declare class RR0ContentStep extends ContentStep<HtmlRR0Context> {
|
|
12
|
-
protected
|
|
13
|
-
protected
|
|
14
|
-
|
|
15
|
-
protected toProcess: Set<string>;
|
|
16
|
-
constructor(contentConfigs: ContentStepConfig[], outputFunc: OutputFunc, fileVisitors: FileVisitor[], contentVisitors: ContentVisitor[], force: boolean, name: string, toProcess: Set<string>);
|
|
17
|
-
static setTimeFromPath(context: HtmlRR0Context, filePath: string): TimeContext | undefined;
|
|
21
|
+
protected options: RR0ContentStepOptions;
|
|
22
|
+
protected timeService: TimeService;
|
|
23
|
+
constructor(options: RR0ContentStepOptions, timeService: TimeService);
|
|
18
24
|
protected processFile(context: HtmlRR0Context, filePath: string, contentsConfig: ContentStepConfig): Promise<string | undefined>;
|
|
19
|
-
protected setContextFromFile(context: HtmlRR0Context, filePath: string): void;
|
|
20
|
-
protected setTimeFromPath(context: HtmlRR0Context, filePath: string): void;
|
|
21
25
|
protected shouldProcessFile(context: HtmlRR0Context, contentsConfig: ContentStepConfig): Promise<boolean>;
|
|
22
26
|
protected shouldProcessContent(context: HtmlRR0Context, contentsConfig: ContentStepConfig): Promise<boolean>;
|
|
23
27
|
protected postExecute(result: ContentStepResult): Promise<ContentStepResult>;
|
package/dist/RR0ContentStep.js
CHANGED
|
@@ -1,54 +1,34 @@
|
|
|
1
1
|
import { ContentStep } from "ssg-api";
|
|
2
|
-
import { Time } from "./time/index.js";
|
|
3
2
|
export class RR0ContentStep extends ContentStep {
|
|
4
|
-
constructor(
|
|
5
|
-
super(contentConfigs, outputFunc, name);
|
|
6
|
-
this.
|
|
7
|
-
this.
|
|
8
|
-
this.
|
|
9
|
-
this.
|
|
10
|
-
}
|
|
11
|
-
static setTimeFromPath(context, filePath) {
|
|
12
|
-
const time = context.time;
|
|
13
|
-
time.reset();
|
|
14
|
-
const newTimeContext = Time.contextFromFileName(context, filePath);
|
|
15
|
-
if (newTimeContext) {
|
|
16
|
-
time.setYear(newTimeContext.getYear());
|
|
17
|
-
time.setMonth(newTimeContext.getMonth());
|
|
18
|
-
time.setDayOfMonth(newTimeContext.getDayOfMonth());
|
|
19
|
-
// context.time.from = context.time
|
|
20
|
-
}
|
|
21
|
-
return newTimeContext;
|
|
3
|
+
constructor(options, timeService) {
|
|
4
|
+
super(options.contentConfigs, options.outputFunc, options.name);
|
|
5
|
+
this.options = options;
|
|
6
|
+
this.timeService = timeService;
|
|
7
|
+
this.options.fileVisitors = options.fileVisitors || [];
|
|
8
|
+
this.options.contentVisitors = options.contentVisitors || [];
|
|
22
9
|
}
|
|
23
10
|
async processFile(context, filePath, contentsConfig) {
|
|
24
|
-
this.setContextFromFile(context, filePath);
|
|
11
|
+
this.timeService.setContextFromFile(context, filePath);
|
|
25
12
|
return super.processFile(context, filePath, contentsConfig);
|
|
26
13
|
}
|
|
27
|
-
setContextFromFile(context, filePath) {
|
|
28
|
-
this.setTimeFromPath(context, filePath);
|
|
29
|
-
}
|
|
30
|
-
setTimeFromPath(context, filePath) {
|
|
31
|
-
context.time.reset(); // Don't use time context from previous page.
|
|
32
|
-
RR0ContentStep.setTimeFromPath(context, filePath);
|
|
33
|
-
}
|
|
34
14
|
async shouldProcessFile(context, contentsConfig) {
|
|
35
15
|
const fileHasChanged = await super.shouldProcessFile(context, contentsConfig);
|
|
36
|
-
const fileIsForced = this.toProcess.has(context.file.name);
|
|
37
|
-
const processFile = this.force || fileIsForced || fileHasChanged;
|
|
16
|
+
const fileIsForced = this.options.toProcess.has(context.file.name);
|
|
17
|
+
const processFile = this.options.force || fileIsForced || fileHasChanged;
|
|
38
18
|
if (processFile) {
|
|
39
|
-
this.toProcess.add(context.file.name);
|
|
19
|
+
this.options.toProcess.add(context.file.name);
|
|
40
20
|
}
|
|
41
|
-
for (const fileVisitor of this.fileVisitors) {
|
|
21
|
+
for (const fileVisitor of this.options.fileVisitors) {
|
|
42
22
|
await fileVisitor.visit(context, processFile);
|
|
43
23
|
}
|
|
44
24
|
return processFile;
|
|
45
25
|
}
|
|
46
26
|
async shouldProcessContent(context, contentsConfig) {
|
|
47
|
-
const fileIsForced = this.toProcess.has(context.file.name);
|
|
27
|
+
const fileIsForced = this.options.toProcess.has(context.file.name);
|
|
48
28
|
const showProcess = await super.shouldProcessContent(context, contentsConfig);
|
|
49
|
-
const should = this.force || fileIsForced || showProcess;
|
|
29
|
+
const should = this.options.force || fileIsForced || showProcess;
|
|
50
30
|
if (should) {
|
|
51
|
-
for (const contentVisitor of this.contentVisitors) {
|
|
31
|
+
for (const contentVisitor of this.options.contentVisitors) {
|
|
52
32
|
await contentVisitor.visit(context);
|
|
53
33
|
}
|
|
54
34
|
}
|
|
@@ -56,7 +36,7 @@ export class RR0ContentStep extends ContentStep {
|
|
|
56
36
|
}
|
|
57
37
|
async postExecute(result) {
|
|
58
38
|
await super.postExecute(result);
|
|
59
|
-
for (const fileVisitor of this.fileVisitors) {
|
|
39
|
+
for (const fileVisitor of this.options.fileVisitors) {
|
|
60
40
|
await fileVisitor.contentStepEnd();
|
|
61
41
|
}
|
|
62
42
|
return result;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { ConsoleLogger } from "ssg-api";
|
|
2
2
|
import { CLI } from "../util/cli/CLI.js";
|
|
3
3
|
import path from "path";
|
|
4
|
-
import {
|
|
4
|
+
import { PeopleService } from "../people";
|
|
5
5
|
import { AllDataService, RR0EventFactory, TypedDataFactory } from "@rr0/data";
|
|
6
6
|
import { BookService } from "./BookService";
|
|
7
7
|
import { TimeUrlBuilder } from "../time";
|
|
8
|
-
import { testFilePath } from "../test";
|
|
8
|
+
import { rr0TestUtil, testFilePath } from "../test";
|
|
9
9
|
const logger = new ConsoleLogger("rr0-books");
|
|
10
10
|
const args = new CLI().getArgs();
|
|
11
11
|
const fileName = args.import;
|
|
12
12
|
const dry = args.dry === "true";
|
|
13
|
-
const peopleFactory =
|
|
13
|
+
const peopleFactory = rr0TestUtil.peopleFactory;
|
|
14
14
|
const eventFactory = new RR0EventFactory();
|
|
15
15
|
const bookFactory = new TypedDataFactory(eventFactory, "book");
|
|
16
16
|
const dataService = new AllDataService([bookFactory, peopleFactory]);
|
|
@@ -26,7 +26,8 @@ const timeOptions = {
|
|
|
26
26
|
};
|
|
27
27
|
const timeUrlBuilder = new TimeUrlBuilder({ rootDir: timeOptions.root });
|
|
28
28
|
let files = [];
|
|
29
|
-
const
|
|
29
|
+
const peopleService = new PeopleService(dataService, peopleFactory, files, rr0TestUtil.time.getService());
|
|
30
|
+
const books = new BookService(logger, dry, peopleService, timeUrlBuilder, config);
|
|
30
31
|
books.import(fileName).then((result) => {
|
|
31
32
|
logger.log("Wrote", result.length, "books");
|
|
32
33
|
});
|
|
@@ -12,7 +12,7 @@ describe("People", () => {
|
|
|
12
12
|
path.join(peopleRoot, "h/HynekJosefAllen"),
|
|
13
13
|
path.join(peopleRoot, "v/VonBraunWerner")
|
|
14
14
|
];
|
|
15
|
-
const service = new PeopleService(new AllDataService([]), rr0TestUtil.peopleFactory, peopleFiles);
|
|
15
|
+
const service = new PeopleService(new AllDataService([]), rr0TestUtil.peopleFactory, peopleFiles, rr0TestUtil.time.getService());
|
|
16
16
|
test("age", async () => {
|
|
17
17
|
const [hynek] = await service.getFromDir("HynekJosefAllen");
|
|
18
18
|
expect(hynek.isDeceased()).toBe(false);
|
|
@@ -14,7 +14,7 @@ describe("PeopleFactory", () => {
|
|
|
14
14
|
path.join(peopleRoot, "h/HynekJosefAllen"),
|
|
15
15
|
path.join(peopleRoot, "v/VonBraunWerner")
|
|
16
16
|
];
|
|
17
|
-
const factory = new PeopleService(dataService, rr0TestUtil.peopleFactory, peopleFiles);
|
|
17
|
+
const factory = new PeopleService(dataService, rr0TestUtil.peopleFactory, peopleFiles, rr0TestUtil.time.getService());
|
|
18
18
|
test("build people with one first name", () => {
|
|
19
19
|
expect(factory.createFromFullName("Jérôme Beau")).toEqual(new People(["Jérôme"], "Beau", [], [], [], false, undefined, undefined, undefined, "people/b/BeauJerome"));
|
|
20
20
|
});
|
|
@@ -8,7 +8,7 @@ describe("ClassDomReplaceCommand", () => {
|
|
|
8
8
|
test("replaces", async () => {
|
|
9
9
|
const peopleRoot = "src/people";
|
|
10
10
|
const peopleFiles = [path.join(peopleRoot, "b/BeauJerome")];
|
|
11
|
-
const peopleService = new PeopleService(rr0TestUtil.dataService, rr0TestUtil.peopleFactory, peopleFiles);
|
|
11
|
+
const peopleService = new PeopleService(rr0TestUtil.dataService, rr0TestUtil.peopleFactory, peopleFiles, rr0TestUtil.time.getService());
|
|
12
12
|
const command = new ClassDomReplaceCommand(new PeopleReplacerFactory(peopleService), "people");
|
|
13
13
|
const context = rr0TestUtil.time.newHtmlContext("1/9/9/0/08/index.html", `<span class="people">Jérôme Beau</span>`);
|
|
14
14
|
await command.execute(context);
|
|
@@ -22,7 +22,7 @@ describe("PeopleReplacer", () => {
|
|
|
22
22
|
}
|
|
23
23
|
test("ignore brackets", async () => {
|
|
24
24
|
const dataService = new AllDataService([peopleFactory]);
|
|
25
|
-
const replacer = new PeopleReplacer(new PeopleService(dataService, peopleFactory, peopleFiles));
|
|
25
|
+
const replacer = new PeopleReplacer(new PeopleService(dataService, peopleFactory, peopleFiles, rr0TestUtil.time.getService()));
|
|
26
26
|
const context = rr0TestUtil.time.newHtmlContext("1/9/9/0/08/index.html", "");
|
|
27
27
|
{
|
|
28
28
|
const lastnameFirstElement = createPeopleElement(context, "Hynek, Josef Allen (Northwestern University, Evanston, Illinois)");
|
|
@@ -37,7 +37,7 @@ describe("PeopleReplacer", () => {
|
|
|
37
37
|
});
|
|
38
38
|
test("replace people tags", async () => {
|
|
39
39
|
const dataService = new AllDataService([peopleFactory]);
|
|
40
|
-
const replacer = new PeopleReplacer(new PeopleService(dataService, peopleFactory, peopleFiles));
|
|
40
|
+
const replacer = new PeopleReplacer(new PeopleService(dataService, peopleFactory, peopleFiles, rr0TestUtil.time.getService()));
|
|
41
41
|
const context = rr0TestUtil.time.newHtmlContext("1/9/9/0/08/index.html", "");
|
|
42
42
|
{
|
|
43
43
|
const peopleWithTitle = createPeopleElement(context, "Ronald Reagan", "Ronald Wilson Reagan");
|
|
@@ -4,10 +4,12 @@ import { CountryCode } from "../org/index.js";
|
|
|
4
4
|
import { Occupation } from "./Occupation.js";
|
|
5
5
|
import { PeopleFactory } from "./PeopleFactory.js";
|
|
6
6
|
import { AbstractDataService, AllDataService } from "@rr0/data";
|
|
7
|
+
import { TimeService } from "../time";
|
|
7
8
|
export declare class PeopleService extends AbstractDataService<People> {
|
|
8
9
|
protected peopleFactory: PeopleFactory;
|
|
10
|
+
protected timeService: TimeService;
|
|
9
11
|
readonly cache: Map<string, People>;
|
|
10
|
-
constructor(dataService: AllDataService, peopleFactory: PeopleFactory, files: string[]);
|
|
12
|
+
constructor(dataService: AllDataService, peopleFactory: PeopleFactory, files: string[], timeService: TimeService);
|
|
11
13
|
createFromFullName(fullName: string): People;
|
|
12
14
|
getAll(): Promise<People[]>;
|
|
13
15
|
getFromDirs(dirNames: string[]): Promise<People[]>;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { People } from "./People.js";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import { Time } from "../time/Time.js";
|
|
4
3
|
import { Gender } from "@rr0/common";
|
|
5
4
|
import { AbstractDataFactory, AbstractDataService } from "@rr0/data";
|
|
6
5
|
export class PeopleService extends AbstractDataService {
|
|
7
|
-
constructor(dataService, peopleFactory, files) {
|
|
6
|
+
constructor(dataService, peopleFactory, files, timeService) {
|
|
8
7
|
super(dataService, peopleFactory, files);
|
|
9
8
|
this.peopleFactory = peopleFactory;
|
|
9
|
+
this.timeService = timeService;
|
|
10
10
|
this.cache = new Map();
|
|
11
11
|
}
|
|
12
12
|
createFromFullName(fullName) {
|
|
@@ -79,12 +79,12 @@ export class PeopleService extends AbstractDataService {
|
|
|
79
79
|
}
|
|
80
80
|
let birthTimeStr = people.birthTime;
|
|
81
81
|
if (birthTimeStr) {
|
|
82
|
-
const birthTime = people.birthTime =
|
|
82
|
+
const birthTime = people.birthTime = this.timeService.dateFromIso(birthTimeStr);
|
|
83
83
|
birthTimeStr = birthTime.getFullYear().toString();
|
|
84
84
|
}
|
|
85
85
|
let deathTimeStr = people.deathTime;
|
|
86
86
|
if (deathTimeStr) {
|
|
87
|
-
const deathTime = people.deathTime =
|
|
87
|
+
const deathTime = people.deathTime = this.timeService.dateFromIso(deathTimeStr);
|
|
88
88
|
deathTimeStr = deathTime.getFullYear().toString();
|
|
89
89
|
}
|
|
90
90
|
if (people.isDeceased()) {
|
|
@@ -2,12 +2,13 @@ import { HttpSource } from "../time/datasource/HttpSource.js";
|
|
|
2
2
|
import { SourceRegistry } from "./SourceRegistry.js";
|
|
3
3
|
import { AllDataService } from "@rr0/data";
|
|
4
4
|
import { Source } from "@rr0/data/dist/source";
|
|
5
|
+
import { TimeService } from "../time";
|
|
5
6
|
/**
|
|
6
7
|
* Create Source objects and register them.
|
|
7
8
|
*/
|
|
8
9
|
export declare class PersistentSourceRegistry extends SourceRegistry {
|
|
9
10
|
protected fileName: string;
|
|
10
|
-
constructor(dataService: AllDataService, http: HttpSource, baseUrl: string, fileName: string, options: Intl.DateTimeFormatOptions);
|
|
11
|
+
constructor(dataService: AllDataService, http: HttpSource, baseUrl: string, fileName: string, options: Intl.DateTimeFormatOptions, time: TimeService);
|
|
11
12
|
protected get(href: string): Promise<Source>;
|
|
12
13
|
protected register(href: string, source: Source): Promise<void>;
|
|
13
14
|
}
|
|
@@ -4,8 +4,8 @@ import { FileContents } from "@javarome/fileutil";
|
|
|
4
4
|
* Create Source objects and register them.
|
|
5
5
|
*/
|
|
6
6
|
export class PersistentSourceRegistry extends SourceRegistry {
|
|
7
|
-
constructor(dataService, http, baseUrl, fileName, options) {
|
|
8
|
-
super(dataService, http, baseUrl, options);
|
|
7
|
+
constructor(dataService, http, baseUrl, fileName, options, time) {
|
|
8
|
+
super(dataService, http, baseUrl, options, time);
|
|
9
9
|
this.fileName = fileName;
|
|
10
10
|
try {
|
|
11
11
|
const registryFileContents = FileContents.read(fileName, "utf-8").contents;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HtmlRR0Context } from "../RR0Context.js";
|
|
2
2
|
import { HttpSource } from "../time/datasource/HttpSource.js";
|
|
3
|
+
import { TimeService } from "../time";
|
|
3
4
|
import { AllDataService } from "@rr0/data";
|
|
4
5
|
import { Source } from "@rr0/data/dist/source";
|
|
5
6
|
/**
|
|
@@ -10,7 +11,8 @@ export declare class SourceFactory {
|
|
|
10
11
|
protected http: HttpSource;
|
|
11
12
|
protected baseUrl: string;
|
|
12
13
|
protected options: Intl.DateTimeFormatOptions;
|
|
13
|
-
|
|
14
|
+
protected time: TimeService;
|
|
15
|
+
constructor(dataService: AllDataService, http: HttpSource, baseUrl: string, options: Intl.DateTimeFormatOptions, time: TimeService);
|
|
14
16
|
/**
|
|
15
17
|
* Create a Source object from an anchor's URL.
|
|
16
18
|
*
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import { TimeContext } from "@rr0/time";
|
|
3
3
|
import { JSDOM } from "jsdom";
|
|
4
|
-
import { Time } from "../time";
|
|
5
4
|
import { FileContents } from "@javarome/fileutil";
|
|
6
5
|
/**
|
|
7
6
|
* Create Source objects.
|
|
8
7
|
*/
|
|
9
8
|
export class SourceFactory {
|
|
10
|
-
constructor(dataService, http, baseUrl, options) {
|
|
9
|
+
constructor(dataService, http, baseUrl, options, time) {
|
|
11
10
|
this.dataService = dataService;
|
|
12
11
|
this.http = http;
|
|
13
12
|
this.baseUrl = baseUrl;
|
|
14
13
|
this.options = options;
|
|
14
|
+
this.time = time;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
17
|
* Create a Source object from an anchor's URL.
|
|
@@ -65,7 +65,7 @@ export class SourceFactory {
|
|
|
65
65
|
}
|
|
66
66
|
const publication = source.publication;
|
|
67
67
|
if (publication && !publication.time) {
|
|
68
|
-
publication.time =
|
|
68
|
+
publication.time = this.time.contextFromFileName(context, href);
|
|
69
69
|
}
|
|
70
70
|
if (hash) {
|
|
71
71
|
source.index = hash;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HtmlRR0Context } from "../RR0Context.js";
|
|
2
|
-
import { HttpSource } from "../time/index.js";
|
|
2
|
+
import { HttpSource, TimeService } from "../time/index.js";
|
|
3
3
|
import { SourceFactory } from "./SourceFactory.js";
|
|
4
4
|
import { AllDataService } from "@rr0/data";
|
|
5
5
|
import { Source } from "@rr0/data/dist/source";
|
|
@@ -8,7 +8,7 @@ import { Source } from "@rr0/data/dist/source";
|
|
|
8
8
|
*/
|
|
9
9
|
export declare class SourceRegistry extends SourceFactory {
|
|
10
10
|
registry: {};
|
|
11
|
-
constructor(dataService: AllDataService, http: HttpSource, baseUrl: string, options: Intl.DateTimeFormatOptions);
|
|
11
|
+
constructor(dataService: AllDataService, http: HttpSource, baseUrl: string, options: Intl.DateTimeFormatOptions, time: TimeService);
|
|
12
12
|
/**
|
|
13
13
|
* Create a Source object from an anchor's URL.
|
|
14
14
|
*
|
|
@@ -3,8 +3,8 @@ import { SourceFactory } from "./SourceFactory.js";
|
|
|
3
3
|
* Create Source objects and register them.
|
|
4
4
|
*/
|
|
5
5
|
export class SourceRegistry extends SourceFactory {
|
|
6
|
-
constructor(dataService, http, baseUrl, options) {
|
|
7
|
-
super(dataService, http, baseUrl, options);
|
|
6
|
+
constructor(dataService, http, baseUrl, options, time) {
|
|
7
|
+
super(dataService, http, baseUrl, options, time);
|
|
8
8
|
this.registry = {};
|
|
9
9
|
}
|
|
10
10
|
/**
|
package/dist/test/RR0TestUtil.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import { RR0ContextImpl } from "../RR0Context.js";
|
|
3
|
-
import { Time } from "../time/index.js";
|
|
4
3
|
import { HtmlFileContents } from "ssg-api";
|
|
5
4
|
import { OrganizationFactory } from "../org/index.js";
|
|
6
5
|
import { CaseFactory } from "../science/index.js";
|
|
@@ -65,7 +64,7 @@ export class RR0TestUtil {
|
|
|
65
64
|
const lang = currentFile.lang;
|
|
66
65
|
context.file = new HtmlFileContents(currentFile.name, currentFile.encoding, currentFile.contents, currentFile.lastModified, lang, { author: [] }, {}, title);
|
|
67
66
|
const htmlContext = context;
|
|
68
|
-
const timeContext =
|
|
67
|
+
const timeContext = this.time.getService().contextFromFileName(htmlContext, inputFileName);
|
|
69
68
|
Object.assign(htmlContext.time, timeContext);
|
|
70
69
|
return htmlContext;
|
|
71
70
|
}
|
package/dist/time/Time.d.ts
CHANGED
|
@@ -1,17 +1,2 @@
|
|
|
1
|
-
import { TimeTextBuilder } from "./text/TimeTextBuilder.js";
|
|
2
|
-
import { TimeContext } from "@rr0/time";
|
|
3
|
-
import { HtmlRR0Context } from "../RR0Context.js";
|
|
4
1
|
export declare class Time {
|
|
5
|
-
static readonly timePathRegex: RegExp;
|
|
6
|
-
/**
|
|
7
|
-
* Instantiate a Date object matching an ISO date ("1972-08-12 16:34" for instance).
|
|
8
|
-
*
|
|
9
|
-
* Approximated dates like "~1972" will be converted to exact dates ("1972").
|
|
10
|
-
*
|
|
11
|
-
* @param isoDate
|
|
12
|
-
*/
|
|
13
|
-
static dateFromIso(isoDate: string): Date;
|
|
14
|
-
static parseFileName(fileName: string): RegExpExecArray | null;
|
|
15
|
-
static titleFromFile(context: HtmlRR0Context, fileName: string, timeTextBuilder: TimeTextBuilder): string | undefined;
|
|
16
|
-
static contextFromFileName(context: HtmlRR0Context, fileName?: string): TimeContext | undefined;
|
|
17
2
|
}
|
package/dist/time/Time.js
CHANGED
|
@@ -1,59 +1,2 @@
|
|
|
1
|
-
import { RR0ContextImpl } from "../RR0Context.js";
|
|
2
|
-
import { StringUtil } from "../util/string/StringUtil.js";
|
|
3
1
|
export class Time {
|
|
4
|
-
/**
|
|
5
|
-
* Instantiate a Date object matching an ISO date ("1972-08-12 16:34" for instance).
|
|
6
|
-
*
|
|
7
|
-
* Approximated dates like "~1972" will be converted to exact dates ("1972").
|
|
8
|
-
*
|
|
9
|
-
* @param isoDate
|
|
10
|
-
*/
|
|
11
|
-
static dateFromIso(isoDate) {
|
|
12
|
-
isoDate = isoDate.replace("~", "");
|
|
13
|
-
if (isoDate.charAt(0) === "-") {
|
|
14
|
-
isoDate = "-" + "0".repeat(7 - isoDate.length) + isoDate.substring(1);
|
|
15
|
-
}
|
|
16
|
-
return new Date(isoDate);
|
|
17
|
-
}
|
|
18
|
-
static parseFileName(fileName) {
|
|
19
|
-
return Time.timePathRegex.exec(fileName);
|
|
20
|
-
}
|
|
21
|
-
static titleFromFile(context, fileName, timeTextBuilder) {
|
|
22
|
-
let title;
|
|
23
|
-
const timeContext = Time.contextFromFileName(context, fileName);
|
|
24
|
-
if (timeContext) {
|
|
25
|
-
const pageContext = new RR0ContextImpl(context.locale, timeContext, context.config, context.people, context.file);
|
|
26
|
-
title = timeTextBuilder.build(pageContext);
|
|
27
|
-
title = StringUtil.capitalizeFirstLetter(title);
|
|
28
|
-
}
|
|
29
|
-
return title;
|
|
30
|
-
}
|
|
31
|
-
static contextFromFileName(context, fileName = context.file.name) {
|
|
32
|
-
let timeContext;
|
|
33
|
-
let elems;
|
|
34
|
-
if (fileName.endsWith("index.html")) {
|
|
35
|
-
while ((elems = fileName.split("/")).length < 6) {
|
|
36
|
-
fileName = elems.slice(0, elems.length - 1).join("/") + "/0/index.html";
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
const timeExec = Time.parseFileName(fileName);
|
|
40
|
-
if (timeExec && timeExec.length > 5) {
|
|
41
|
-
const pageContext = context.clone();
|
|
42
|
-
timeContext = pageContext.time;
|
|
43
|
-
const m = parseInt(timeExec[2], 10);
|
|
44
|
-
const c = parseInt(timeExec[3], 10);
|
|
45
|
-
const d = parseInt(timeExec[4], 10);
|
|
46
|
-
const u = parseInt(timeExec[5], 10);
|
|
47
|
-
const year = (timeExec[1] ? -1 : 1) * (m * 1000 + c * 100 + d * 10 + u);
|
|
48
|
-
timeContext.setYear(year);
|
|
49
|
-
const monthStr = timeExec[6];
|
|
50
|
-
timeContext.setMonth(monthStr ? parseInt(monthStr, 10) : undefined);
|
|
51
|
-
const dayStr = timeExec[7];
|
|
52
|
-
timeContext.setDayOfMonth(dayStr ? parseInt(dayStr, 10) : undefined);
|
|
53
|
-
timeContext.setHour(undefined);
|
|
54
|
-
timeContext.setMinutes(undefined);
|
|
55
|
-
}
|
|
56
|
-
return timeContext;
|
|
57
|
-
}
|
|
58
2
|
}
|
|
59
|
-
Time.timePathRegex = /time\/(-)?(\d)\/(\d)\/(\d)\/(\d)\/?(\d{2})?\/?(\d{2})?\/?(index(_[a-z]{2})?.html)?/;
|
|
@@ -13,7 +13,7 @@ describe("TimeEventRenderer", () => {
|
|
|
13
13
|
const dataService = new AllDataService([]);
|
|
14
14
|
const baseUrl = "https://rr0.org";
|
|
15
15
|
const http = new HttpSource();
|
|
16
|
-
const sourceFactory = new SourceFactory(dataService, http, baseUrl, rr0TestUtil.intlOptions);
|
|
16
|
+
const sourceFactory = new SourceFactory(dataService, http, baseUrl, rr0TestUtil.intlOptions, rr0TestUtil.time.getService());
|
|
17
17
|
const renderer = new CaseSummaryRenderer(new NoteRenderer(new NoteFileCounter()), sourceFactory, new SourceRenderer(rr0TestUtil.time.timeTextBuilder), rr0TestUtil.time.timeElementFactory);
|
|
18
18
|
test("render event", async () => {
|
|
19
19
|
const context = rr0TestUtil.time.newHtmlContext("1/9/7/0/03/index.html");
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Time } from "./Time.js";
|
|
2
1
|
import { LinkType } from "ssg-api";
|
|
3
2
|
export class TimeLinkDefaultHandler {
|
|
4
3
|
constructor(service, timeTextBuilder) {
|
|
@@ -8,9 +7,10 @@ export class TimeLinkDefaultHandler {
|
|
|
8
7
|
contents(context) {
|
|
9
8
|
const prevLink = this.prev(context);
|
|
10
9
|
if (prevLink) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
const service = this.service;
|
|
11
|
+
let contentUrl = service.matchExistingTimeFile(prevLink.url.substring(1));
|
|
12
|
+
if (contentUrl != service.root) {
|
|
13
|
+
const text = service.titleFromFile(context, contentUrl, this.timeTextBuilder);
|
|
14
14
|
if (text) {
|
|
15
15
|
return { type: LinkType.prev, text, url: "/" + contentUrl };
|
|
16
16
|
}
|
|
@@ -20,11 +20,12 @@ export class TimeLinkDefaultHandler {
|
|
|
20
20
|
next(context) {
|
|
21
21
|
let fileName = context.file.name;
|
|
22
22
|
if (this.isTimeFile(fileName)) {
|
|
23
|
-
const
|
|
23
|
+
const service = this.service;
|
|
24
|
+
const pos = service.files.indexOf(fileName);
|
|
24
25
|
if (pos >= 0) {
|
|
25
|
-
const nextFile =
|
|
26
|
+
const nextFile = service.files[pos + 1];
|
|
26
27
|
if (nextFile) {
|
|
27
|
-
const text =
|
|
28
|
+
const text = service.titleFromFile(context, nextFile, this.timeTextBuilder);
|
|
28
29
|
return { type: LinkType.next, text, url: "/" + nextFile };
|
|
29
30
|
}
|
|
30
31
|
}
|
|
@@ -33,11 +34,12 @@ export class TimeLinkDefaultHandler {
|
|
|
33
34
|
prev(context) {
|
|
34
35
|
let fileName = context.file.name;
|
|
35
36
|
if (this.isTimeFile(fileName)) {
|
|
36
|
-
const
|
|
37
|
+
const service = this.service;
|
|
38
|
+
const pos = service.files.indexOf(fileName);
|
|
37
39
|
if (pos >= 0) {
|
|
38
|
-
const prevFile =
|
|
40
|
+
const prevFile = service.files[pos - 1];
|
|
39
41
|
if (prevFile) {
|
|
40
|
-
const text =
|
|
42
|
+
const text = service.titleFromFile(context, prevFile, this.timeTextBuilder);
|
|
41
43
|
if (text) {
|
|
42
44
|
return { type: LinkType.prev, text, url: "/" + prevFile };
|
|
43
45
|
}
|
|
@@ -2,6 +2,8 @@ import { TimeRenderer } from "./html/TimeRenderer.js";
|
|
|
2
2
|
import { TimeTextBuilder } from "./text/TimeTextBuilder.js";
|
|
3
3
|
import { TimeUrlBuilder } from "./TimeUrlBuilder";
|
|
4
4
|
import { AbstractDataService, AllDataService, RR0Event } from "@rr0/data";
|
|
5
|
+
import { HtmlRR0Context } from "../RR0Context";
|
|
6
|
+
import { TimeContext } from "@rr0/time";
|
|
5
7
|
export type TimeServiceOptions = {
|
|
6
8
|
readonly root: string;
|
|
7
9
|
readonly files: string[];
|
|
@@ -9,12 +11,28 @@ export type TimeServiceOptions = {
|
|
|
9
11
|
export declare class TimeService extends AbstractDataService<RR0Event> {
|
|
10
12
|
readonly textBuilder: TimeTextBuilder;
|
|
11
13
|
readonly urlBuilder: TimeUrlBuilder;
|
|
14
|
+
readonly timePathRegex: RegExp;
|
|
15
|
+
static readonly defaultRegex: RegExp;
|
|
12
16
|
readonly renderer: TimeRenderer;
|
|
13
17
|
readonly root: string;
|
|
14
|
-
constructor(dataService: AllDataService, textBuilder: TimeTextBuilder, urlBuilder: TimeUrlBuilder, options: TimeServiceOptions);
|
|
18
|
+
constructor(dataService: AllDataService, textBuilder: TimeTextBuilder, urlBuilder: TimeUrlBuilder, options: TimeServiceOptions, timePathRegex?: RegExp);
|
|
15
19
|
isTimeFile(filePath: string): boolean;
|
|
16
20
|
/**
|
|
17
21
|
* @return the found time URL or undefined if not found.
|
|
18
22
|
*/
|
|
19
23
|
matchExistingTimeFile(url: string): string | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Instantiate a Date object matching an ISO date ("1972-08-12 16:34" for instance).
|
|
26
|
+
*
|
|
27
|
+
* Approximated dates like "~1972" will be converted to exact dates ("1972").
|
|
28
|
+
*
|
|
29
|
+
* @param isoDate
|
|
30
|
+
*/
|
|
31
|
+
dateFromIso(isoDate: string): Date;
|
|
32
|
+
parseFileName(fileName: string): RegExpExecArray | null;
|
|
33
|
+
titleFromFile(context: HtmlRR0Context, fileName: string, timeTextBuilder: TimeTextBuilder): string | undefined;
|
|
34
|
+
contextFromFileName(context: HtmlRR0Context, fileName?: string): TimeContext | undefined;
|
|
35
|
+
gSetTimeFromPath(context: HtmlRR0Context, filePath: string): TimeContext | undefined;
|
|
36
|
+
setContextFromFile(context: HtmlRR0Context, filePath: string): void;
|
|
37
|
+
protected setTimeFromPath(context: HtmlRR0Context, filePath: string): void;
|
|
20
38
|
}
|
package/dist/time/TimeService.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { TimeRenderer } from "./html/TimeRenderer.js";
|
|
2
2
|
import { AbstractDataService } from "@rr0/data";
|
|
3
|
+
import { RR0ContextImpl } from "../RR0Context";
|
|
4
|
+
import { StringUtil } from "../util";
|
|
3
5
|
export class TimeService extends AbstractDataService {
|
|
4
|
-
constructor(dataService, textBuilder, urlBuilder, options) {
|
|
6
|
+
constructor(dataService, textBuilder, urlBuilder, options, timePathRegex = TimeService.defaultRegex) {
|
|
5
7
|
super(dataService, null, options.files);
|
|
6
8
|
this.textBuilder = textBuilder;
|
|
7
9
|
this.urlBuilder = urlBuilder;
|
|
10
|
+
this.timePathRegex = timePathRegex;
|
|
8
11
|
this.root = options.root;
|
|
9
12
|
this.renderer = new TimeRenderer(this, this.textBuilder);
|
|
10
13
|
}
|
|
@@ -21,4 +24,78 @@ export class TimeService extends AbstractDataService {
|
|
|
21
24
|
}
|
|
22
25
|
return url === this.root ? undefined : url;
|
|
23
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Instantiate a Date object matching an ISO date ("1972-08-12 16:34" for instance).
|
|
29
|
+
*
|
|
30
|
+
* Approximated dates like "~1972" will be converted to exact dates ("1972").
|
|
31
|
+
*
|
|
32
|
+
* @param isoDate
|
|
33
|
+
*/
|
|
34
|
+
dateFromIso(isoDate) {
|
|
35
|
+
isoDate = isoDate.replace("~", "");
|
|
36
|
+
if (isoDate.charAt(0) === "-") {
|
|
37
|
+
isoDate = "-" + "0".repeat(7 - isoDate.length) + isoDate.substring(1);
|
|
38
|
+
}
|
|
39
|
+
return new Date(isoDate);
|
|
40
|
+
}
|
|
41
|
+
parseFileName(fileName) {
|
|
42
|
+
return this.timePathRegex.exec(fileName);
|
|
43
|
+
}
|
|
44
|
+
titleFromFile(context, fileName, timeTextBuilder) {
|
|
45
|
+
let title;
|
|
46
|
+
const timeContext = this.contextFromFileName(context, fileName);
|
|
47
|
+
if (timeContext) {
|
|
48
|
+
const pageContext = new RR0ContextImpl(context.locale, timeContext, context.config, context.people, context.file);
|
|
49
|
+
title = timeTextBuilder.build(pageContext);
|
|
50
|
+
title = StringUtil.capitalizeFirstLetter(title);
|
|
51
|
+
}
|
|
52
|
+
return title;
|
|
53
|
+
}
|
|
54
|
+
contextFromFileName(context, fileName = context.file.name) {
|
|
55
|
+
let timeContext;
|
|
56
|
+
let elems;
|
|
57
|
+
if (fileName.endsWith("index.html")) {
|
|
58
|
+
while ((elems = fileName.split("/")).length < 6) {
|
|
59
|
+
fileName = elems.slice(0, elems.length - 1).join("/") + "/0/index.html";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const timeExec = this.parseFileName(fileName);
|
|
63
|
+
if (timeExec && timeExec.length > 5) {
|
|
64
|
+
const pageContext = context.clone();
|
|
65
|
+
timeContext = pageContext.time;
|
|
66
|
+
const m = parseInt(timeExec[2], 10);
|
|
67
|
+
const c = parseInt(timeExec[3], 10);
|
|
68
|
+
const d = parseInt(timeExec[4], 10);
|
|
69
|
+
const u = parseInt(timeExec[5], 10);
|
|
70
|
+
const year = (timeExec[1] ? -1 : 1) * (m * 1000 + c * 100 + d * 10 + u);
|
|
71
|
+
timeContext.setYear(year);
|
|
72
|
+
const monthStr = timeExec[6];
|
|
73
|
+
timeContext.setMonth(monthStr ? parseInt(monthStr, 10) : undefined);
|
|
74
|
+
const dayStr = timeExec[7];
|
|
75
|
+
timeContext.setDayOfMonth(dayStr ? parseInt(dayStr, 10) : undefined);
|
|
76
|
+
timeContext.setHour(undefined);
|
|
77
|
+
timeContext.setMinutes(undefined);
|
|
78
|
+
}
|
|
79
|
+
return timeContext;
|
|
80
|
+
}
|
|
81
|
+
gSetTimeFromPath(context, filePath) {
|
|
82
|
+
const time = context.time;
|
|
83
|
+
time.reset();
|
|
84
|
+
const newTimeContext = this.contextFromFileName(context, filePath);
|
|
85
|
+
if (newTimeContext) {
|
|
86
|
+
time.setYear(newTimeContext.getYear());
|
|
87
|
+
time.setMonth(newTimeContext.getMonth());
|
|
88
|
+
time.setDayOfMonth(newTimeContext.getDayOfMonth());
|
|
89
|
+
// context.time.from = context.time
|
|
90
|
+
}
|
|
91
|
+
return newTimeContext;
|
|
92
|
+
}
|
|
93
|
+
setContextFromFile(context, filePath) {
|
|
94
|
+
this.setTimeFromPath(context, filePath);
|
|
95
|
+
}
|
|
96
|
+
setTimeFromPath(context, filePath) {
|
|
97
|
+
context.time.reset(); // Don't use time context from previous page.
|
|
98
|
+
this.gSetTimeFromPath(context, filePath);
|
|
99
|
+
}
|
|
24
100
|
}
|
|
101
|
+
TimeService.defaultRegex = /time\/(-)?(\d)\/(\d)\/(\d)\/(\d)\/?(\d{2})?\/?(\d{2})?\/?(index(_[a-z]{2})?.html)?/;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { Time } from "./Time.js";
|
|
2
1
|
import { TimeContext } from "@rr0/time";
|
|
3
2
|
import { RR0ContextImpl } from "../RR0Context.js";
|
|
4
3
|
import { describe, expect, test } from "@javarome/testscript";
|
|
5
4
|
import { rr0TestUtil } from "../test/index.js";
|
|
6
5
|
import { FileContents } from "@javarome/fileutil";
|
|
7
6
|
describe("Time", () => {
|
|
7
|
+
const time = rr0TestUtil.time.getService();
|
|
8
8
|
test("parse", () => {
|
|
9
|
-
const exec =
|
|
9
|
+
const exec = time.parseFileName("time/-0/0/1/1/index.html");
|
|
10
10
|
let pos = 0;
|
|
11
11
|
expect(exec[++pos]).toBe("-");
|
|
12
12
|
expect(exec[++pos]).toBe("0");
|
|
@@ -23,23 +23,23 @@ describe("Time", () => {
|
|
|
23
23
|
const context = new RR0ContextImpl("fr", timeContext, config);
|
|
24
24
|
test("recognize year before 0 AD", () => {
|
|
25
25
|
context.file = new FileContents("time/-0/0/1/1/index.html", "utf-8", "", new Date("2012-08-12"), { lang: "fr", variants: [] });
|
|
26
|
-
const newTimeContext =
|
|
26
|
+
const newTimeContext = time.contextFromFileName(context);
|
|
27
27
|
expect(newTimeContext.getYear()).toBe(-11);
|
|
28
28
|
});
|
|
29
29
|
test("recognize year after 0 AD", () => {
|
|
30
30
|
context.file = new FileContents("time/1/9/7/2/index.html", "utf-8", "", new Date("2012-08-12"), { lang: "fr", variants: [] });
|
|
31
|
-
const newTimeContext =
|
|
31
|
+
const newTimeContext = time.contextFromFileName(context);
|
|
32
32
|
expect(newTimeContext.getYear()).toBe(1972);
|
|
33
33
|
});
|
|
34
34
|
test("recognize month", () => {
|
|
35
35
|
context.file = new FileContents("time/1/9/7/2/08/index.html", "utf-8", "", new Date("2012-08-12"), { lang: "fr", variants: [] });
|
|
36
|
-
const newTimeContext =
|
|
36
|
+
const newTimeContext = time.contextFromFileName(context);
|
|
37
37
|
expect(newTimeContext.getYear()).toBe(1972);
|
|
38
38
|
expect(newTimeContext.getMonth()).toBe(8);
|
|
39
39
|
});
|
|
40
40
|
test("recognize day", () => {
|
|
41
41
|
context.file = new FileContents("time/1/9/7/2/08/12/index.html", "utf-8", "", new Date("2012-08-12"), { lang: "fr", variants: [] });
|
|
42
|
-
const newTimeContext =
|
|
42
|
+
const newTimeContext = time.contextFromFileName(context);
|
|
43
43
|
expect(newTimeContext.getYear()).toBe(1972);
|
|
44
44
|
expect(newTimeContext.getMonth()).toBe(8);
|
|
45
45
|
expect(newTimeContext.getDayOfMonth()).toBe(12);
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { SsiTitleReplaceCommand } from "./SsiTitleReplaceCommand.js";
|
|
2
2
|
import { rr0TestUtil } from "../test/index.js";
|
|
3
3
|
import { describe, expect, test } from "@javarome/testscript";
|
|
4
|
-
import { Time } from "./Time.js";
|
|
5
4
|
describe("TitleReplaceCommand", () => {
|
|
6
5
|
let timeTextBuilder = rr0TestUtil.time.timeTextBuilder;
|
|
7
6
|
const timeDefaultHandler = (context) => {
|
|
8
7
|
let title;
|
|
9
|
-
title =
|
|
8
|
+
title = rr0TestUtil.time.getService().titleFromFile(context, context.file.name, timeTextBuilder);
|
|
10
9
|
return title;
|
|
11
10
|
};
|
|
12
11
|
describe("Time page", () => {
|
|
@@ -15,11 +15,12 @@ describe("ChronologyReplacer", () => {
|
|
|
15
15
|
const dataService = new AllDataService([]);
|
|
16
16
|
const baseUrl = "https://rr0.org";
|
|
17
17
|
const http = new HttpSource();
|
|
18
|
-
const
|
|
18
|
+
const timeTestUtil = rr0TestUtil.time;
|
|
19
|
+
const sourceFactory = new SourceFactory(dataService, http, baseUrl, rr0TestUtil.intlOptions, timeTestUtil.getService());
|
|
19
20
|
const timeTextBuilder = new TimeTextBuilder(rr0TestUtil.intlOptions);
|
|
20
|
-
const caseRenderer = new CaseSummaryRenderer(new NoteRenderer(new NoteFileCounter()), sourceFactory, new SourceRenderer(timeTextBuilder),
|
|
21
|
+
const caseRenderer = new CaseSummaryRenderer(new NoteRenderer(new NoteFileCounter()), sourceFactory, new SourceRenderer(timeTextBuilder), timeTestUtil.timeElementFactory);
|
|
21
22
|
chronologyReplacer = new ChronologyReplacer([urecatRR0Mapping], caseRenderer);
|
|
22
|
-
context =
|
|
23
|
+
context = timeTestUtil.newHtmlContext("index.html");
|
|
23
24
|
context.time.setYear(undefined);
|
|
24
25
|
// context.time.setMonth(3)
|
|
25
26
|
});
|
|
@@ -41,8 +41,8 @@ export class DatasourceTestCase {
|
|
|
41
41
|
const dataService = new AllDataService([]);
|
|
42
42
|
const baseUrl = "https://rr0.org";
|
|
43
43
|
const http = new HttpSource();
|
|
44
|
-
const sourceFactory = new SourceFactory(dataService, http, baseUrl, this.intlOptions);
|
|
45
44
|
const timeService = await rr0TestUtil.time.getService();
|
|
45
|
+
const sourceFactory = new SourceFactory(dataService, http, baseUrl, this.intlOptions, timeService);
|
|
46
46
|
const timeElementFactory = new TimeElementFactory(new TimeRenderer(timeService, this.timeTextBuilder));
|
|
47
47
|
const eventRenderer = new CaseSummaryRenderer(new NoteRenderer(new NoteFileCounter()), sourceFactory, new SourceRenderer(this.timeTextBuilder), timeElementFactory);
|
|
48
48
|
const items = [];
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@rr0/cms",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"author": "Jérôme Beau <rr0@rr0.org> (https://rr0.org)",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.22",
|
|
6
6
|
"description": "RR0 Content Management System (CMS)",
|
|
7
7
|
"exports": "./dist/index.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@rr0/place": "^0.3.2",
|
|
35
35
|
"@rr0/data": "^0.1.2",
|
|
36
36
|
"@javarome/fileutil": "^0.3.6",
|
|
37
|
-
"ssg-api": "^1.16.
|
|
37
|
+
"ssg-api": "^1.16.12",
|
|
38
38
|
"canvas": "^2.11.2",
|
|
39
39
|
"csv-parser": "^3.0.0",
|
|
40
40
|
"glob": "^11.0.0",
|
|
File without changes
|