@featurevisor/core 0.52.0 → 0.52.1
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/.eslintcache +1 -1
- package/CHANGELOG.md +8 -0
- package/coverage/clover.xml +2 -2
- package/coverage/lcov-report/index.html +1 -1
- package/coverage/lcov-report/lib/builder/allocator.js.html +1 -1
- package/coverage/lcov-report/lib/builder/index.html +1 -1
- package/coverage/lcov-report/lib/builder/traffic.js.html +1 -1
- package/coverage/lcov-report/src/builder/allocator.ts.html +1 -1
- package/coverage/lcov-report/src/builder/index.html +1 -1
- package/coverage/lcov-report/src/builder/traffic.ts.html +1 -1
- package/lib/site/exportSite.d.ts +2 -0
- package/lib/site/exportSite.js +34 -0
- package/lib/site/exportSite.js.map +1 -0
- package/lib/site/generateHistory.d.ts +3 -0
- package/lib/site/generateHistory.js +76 -0
- package/lib/site/generateHistory.js.map +1 -0
- package/lib/site/generateSiteSearchIndex.d.ts +4 -0
- package/lib/site/generateSiteSearchIndex.js +141 -0
- package/lib/site/generateSiteSearchIndex.js.map +1 -0
- package/lib/site/getLastModifiedFromHistory.d.ts +2 -0
- package/lib/site/getLastModifiedFromHistory.js +19 -0
- package/lib/site/getLastModifiedFromHistory.js.map +1 -0
- package/lib/site/getOwnerAndRepoFromUrl.d.ts +4 -0
- package/lib/site/getOwnerAndRepoFromUrl.js +21 -0
- package/lib/site/getOwnerAndRepoFromUrl.js.map +1 -0
- package/lib/site/getRelativePaths.d.ts +6 -0
- package/lib/site/getRelativePaths.js +16 -0
- package/lib/site/getRelativePaths.js.map +1 -0
- package/lib/site/getRepoDetails.d.ts +8 -0
- package/lib/site/getRepoDetails.js +49 -0
- package/lib/site/getRepoDetails.js.map +1 -0
- package/lib/site/index.d.ts +2 -0
- package/lib/site/index.js +19 -0
- package/lib/site/index.js.map +1 -0
- package/lib/site/serveSite.d.ts +2 -0
- package/lib/site/serveSite.js +55 -0
- package/lib/site/serveSite.js.map +1 -0
- package/package.json +2 -2
- package/src/site/exportSite.ts +53 -0
- package/src/site/generateHistory.ts +101 -0
- package/src/site/generateSiteSearchIndex.ts +203 -0
- package/src/site/getLastModifiedFromHistory.ts +21 -0
- package/src/site/getOwnerAndRepoFromUrl.ts +17 -0
- package/src/site/getRelativePaths.ts +24 -0
- package/src/site/getRepoDetails.ts +62 -0
- package/src/site/index.ts +2 -0
- package/src/site/serveSite.ts +60 -0
- package/lib/site.d.ts +0 -16
- package/lib/site.js +0 -368
- package/lib/site.js.map +0 -1
- package/src/site.ts +0 -515
package/src/site.ts
DELETED
|
@@ -1,515 +0,0 @@
|
|
|
1
|
-
import * as fs from "fs";
|
|
2
|
-
import * as path from "path";
|
|
3
|
-
import * as http from "http";
|
|
4
|
-
import { execSync } from "child_process";
|
|
5
|
-
|
|
6
|
-
import * as mkdirp from "mkdirp";
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
HistoryEntry,
|
|
10
|
-
LastModified,
|
|
11
|
-
SearchIndex,
|
|
12
|
-
FeatureKey,
|
|
13
|
-
SegmentKey,
|
|
14
|
-
AttributeKey,
|
|
15
|
-
Condition,
|
|
16
|
-
} from "@featurevisor/types";
|
|
17
|
-
|
|
18
|
-
import { ProjectConfig } from "./config";
|
|
19
|
-
import { Datasource } from "./datasource";
|
|
20
|
-
import { extractAttributeKeysFromConditions, extractSegmentKeysFromGroupSegments } from "./utils";
|
|
21
|
-
|
|
22
|
-
function getRelativePaths(rootDirectoryPath, projectConfig: ProjectConfig) {
|
|
23
|
-
const relativeFeaturesPath = path.relative(
|
|
24
|
-
rootDirectoryPath,
|
|
25
|
-
projectConfig.featuresDirectoryPath,
|
|
26
|
-
);
|
|
27
|
-
const relativeSegmentsPath = path.relative(
|
|
28
|
-
rootDirectoryPath,
|
|
29
|
-
projectConfig.segmentsDirectoryPath,
|
|
30
|
-
);
|
|
31
|
-
const relativeAttributesPath = path.relative(
|
|
32
|
-
rootDirectoryPath,
|
|
33
|
-
projectConfig.attributesDirectoryPath,
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
return {
|
|
37
|
-
relativeFeaturesPath,
|
|
38
|
-
relativeSegmentsPath,
|
|
39
|
-
relativeAttributesPath,
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function generateHistory(rootDirectoryPath, projectConfig: ProjectConfig): HistoryEntry[] {
|
|
44
|
-
try {
|
|
45
|
-
// raw history
|
|
46
|
-
const rawHistoryFilePath = path.join(projectConfig.siteExportDirectoryPath, "history-raw.txt");
|
|
47
|
-
|
|
48
|
-
const { relativeFeaturesPath, relativeSegmentsPath, relativeAttributesPath } = getRelativePaths(
|
|
49
|
-
rootDirectoryPath,
|
|
50
|
-
projectConfig,
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
const separator = "|";
|
|
54
|
-
|
|
55
|
-
const cmd = `git log --name-only --pretty=format:"%h${separator}%an${separator}%aI" --no-merges --relative -- ${relativeFeaturesPath} ${relativeSegmentsPath} ${relativeAttributesPath} > ${rawHistoryFilePath}`;
|
|
56
|
-
execSync(cmd);
|
|
57
|
-
|
|
58
|
-
console.log(`History (raw) generated at: ${rawHistoryFilePath}`);
|
|
59
|
-
|
|
60
|
-
// structured history
|
|
61
|
-
const rawHistory = fs.readFileSync(rawHistoryFilePath, "utf8");
|
|
62
|
-
|
|
63
|
-
const fullHistory: HistoryEntry[] = [];
|
|
64
|
-
|
|
65
|
-
let entry: HistoryEntry = {
|
|
66
|
-
commit: "",
|
|
67
|
-
author: "",
|
|
68
|
-
timestamp: "",
|
|
69
|
-
entities: [],
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
rawHistory.split("\n").forEach((line, index) => {
|
|
73
|
-
if (index === 0 && line.length === 0) {
|
|
74
|
-
// no history found
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (index > 0 && line.length === 0) {
|
|
79
|
-
// commit finished
|
|
80
|
-
fullHistory.push(entry);
|
|
81
|
-
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (line.indexOf(separator) > -1) {
|
|
86
|
-
// commit line
|
|
87
|
-
const parts = line.split("|");
|
|
88
|
-
|
|
89
|
-
entry = {
|
|
90
|
-
commit: parts[0],
|
|
91
|
-
author: parts[1],
|
|
92
|
-
timestamp: parts[2],
|
|
93
|
-
entities: [],
|
|
94
|
-
};
|
|
95
|
-
} else {
|
|
96
|
-
// file line
|
|
97
|
-
const lineSplit = line.split(path.sep);
|
|
98
|
-
const fileName = lineSplit.pop() as string;
|
|
99
|
-
const relativeDir = lineSplit.join(path.sep);
|
|
100
|
-
|
|
101
|
-
const key = fileName.replace("." + projectConfig.parser, "");
|
|
102
|
-
|
|
103
|
-
let type = "feature" as "attribute" | "segment" | "feature";
|
|
104
|
-
|
|
105
|
-
if (relativeDir === relativeSegmentsPath) {
|
|
106
|
-
type = "segment";
|
|
107
|
-
} else if (relativeDir === relativeAttributesPath) {
|
|
108
|
-
type = "attribute";
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
entry.entities.push({
|
|
112
|
-
type,
|
|
113
|
-
key,
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
const fullHistoryFilePath = path.join(
|
|
119
|
-
projectConfig.siteExportDirectoryPath,
|
|
120
|
-
"history-full.json",
|
|
121
|
-
);
|
|
122
|
-
fs.writeFileSync(fullHistoryFilePath, JSON.stringify(fullHistory));
|
|
123
|
-
console.log(`History (full) generated at: ${fullHistoryFilePath}`);
|
|
124
|
-
|
|
125
|
-
return fullHistory;
|
|
126
|
-
} catch (error) {
|
|
127
|
-
console.error(
|
|
128
|
-
`Error when generating history from git: ${error.status}\n${error.stderr.toString()}`,
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
return [];
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export function getLastModifiedFromHistory(
|
|
136
|
-
fullHistory: HistoryEntry[],
|
|
137
|
-
type,
|
|
138
|
-
key,
|
|
139
|
-
): LastModified | undefined {
|
|
140
|
-
const lastModified = fullHistory.find((entry) => {
|
|
141
|
-
return entry.entities.find((entity) => {
|
|
142
|
-
return entity.type === type && entity.key === key;
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
if (lastModified) {
|
|
147
|
-
return {
|
|
148
|
-
commit: lastModified.commit,
|
|
149
|
-
timestamp: lastModified.timestamp,
|
|
150
|
-
author: lastModified.author,
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function getOwnerAndRepoFromUrl(url: string): { owner: string; repo: string } {
|
|
156
|
-
let owner;
|
|
157
|
-
let repo;
|
|
158
|
-
|
|
159
|
-
if (url.startsWith("https://")) {
|
|
160
|
-
const parts = url.split("/");
|
|
161
|
-
repo = (parts.pop() as string).replace(".git", "");
|
|
162
|
-
owner = parts.pop();
|
|
163
|
-
} else if (url.startsWith("git@")) {
|
|
164
|
-
const urlParts = url.split(":");
|
|
165
|
-
const parts = urlParts[1].split("/");
|
|
166
|
-
repo = (parts.pop() as string).replace(".git", "");
|
|
167
|
-
owner = parts.pop();
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return { owner, repo };
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
interface RepoDetails {
|
|
174
|
-
branch: string;
|
|
175
|
-
remoteUrl: string;
|
|
176
|
-
blobUrl: string;
|
|
177
|
-
commitUrl: string;
|
|
178
|
-
topLevelPath: string;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
export function getDetailsFromRepo(): RepoDetails | undefined {
|
|
182
|
-
try {
|
|
183
|
-
const topLevelPathOutput = execSync(`git rev-parse --show-toplevel`);
|
|
184
|
-
const topLevelPath = topLevelPathOutput.toString().trim();
|
|
185
|
-
|
|
186
|
-
const remoteUrlOutput = execSync(`git remote get-url origin`);
|
|
187
|
-
const remoteUrl = remoteUrlOutput.toString().trim();
|
|
188
|
-
|
|
189
|
-
const branchOutput = execSync(`git rev-parse --abbrev-ref HEAD`);
|
|
190
|
-
const branch = branchOutput.toString().trim();
|
|
191
|
-
|
|
192
|
-
if (!remoteUrl || !branch) {
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const { owner, repo } = getOwnerAndRepoFromUrl(remoteUrl);
|
|
197
|
-
|
|
198
|
-
if (!owner || !repo) {
|
|
199
|
-
return;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
let blobUrl;
|
|
203
|
-
let commitUrl;
|
|
204
|
-
|
|
205
|
-
if (remoteUrl.indexOf("github.com") > -1) {
|
|
206
|
-
blobUrl = `https://github.com/${owner}/${repo}/blob/${branch}/{{blobPath}}`;
|
|
207
|
-
commitUrl = `https://github.com/${owner}/${repo}/commit/{{hash}}`;
|
|
208
|
-
} else if (remoteUrl.indexOf("bitbucket.org") > -1) {
|
|
209
|
-
blobUrl = `https://bitbucket.org/${owner}/${repo}/src/${branch}/{{blobPath}}`;
|
|
210
|
-
commitUrl = `https://bitbucket.org/${owner}/${repo}/commits/{{hash}}`;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
if (!blobUrl || !commitUrl) {
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return {
|
|
218
|
-
branch,
|
|
219
|
-
remoteUrl,
|
|
220
|
-
blobUrl,
|
|
221
|
-
commitUrl,
|
|
222
|
-
topLevelPath,
|
|
223
|
-
};
|
|
224
|
-
} catch (e) {
|
|
225
|
-
console.error(e);
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
export function generateSiteSearchIndex(
|
|
233
|
-
rootDirectoryPath: string,
|
|
234
|
-
projectConfig: ProjectConfig,
|
|
235
|
-
fullHistory: HistoryEntry[],
|
|
236
|
-
repoDetails: RepoDetails | undefined,
|
|
237
|
-
): SearchIndex {
|
|
238
|
-
const result: SearchIndex = {
|
|
239
|
-
links: undefined,
|
|
240
|
-
entities: {
|
|
241
|
-
attributes: [],
|
|
242
|
-
segments: [],
|
|
243
|
-
features: [],
|
|
244
|
-
},
|
|
245
|
-
};
|
|
246
|
-
const datasource = new Datasource(projectConfig);
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Links
|
|
250
|
-
*/
|
|
251
|
-
if (repoDetails) {
|
|
252
|
-
const { relativeAttributesPath, relativeSegmentsPath, relativeFeaturesPath } = getRelativePaths(
|
|
253
|
-
rootDirectoryPath,
|
|
254
|
-
projectConfig,
|
|
255
|
-
);
|
|
256
|
-
|
|
257
|
-
let prefix = "";
|
|
258
|
-
if (repoDetails.topLevelPath !== rootDirectoryPath) {
|
|
259
|
-
prefix = rootDirectoryPath.replace(repoDetails.topLevelPath + "/", "") + "/";
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
result.links = {
|
|
263
|
-
attribute: repoDetails.blobUrl.replace(
|
|
264
|
-
"{{blobPath}}",
|
|
265
|
-
prefix + relativeAttributesPath + "/{{key}}." + datasource.getExtension(),
|
|
266
|
-
),
|
|
267
|
-
segment: repoDetails.blobUrl.replace(
|
|
268
|
-
"{{blobPath}}",
|
|
269
|
-
prefix + relativeSegmentsPath + "/{{key}}." + datasource.getExtension(),
|
|
270
|
-
),
|
|
271
|
-
feature: repoDetails.blobUrl.replace(
|
|
272
|
-
"{{blobPath}}",
|
|
273
|
-
prefix + relativeFeaturesPath + "/{{key}}." + datasource.getExtension(),
|
|
274
|
-
),
|
|
275
|
-
commit: repoDetails.commitUrl,
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Entities
|
|
281
|
-
*/
|
|
282
|
-
// usage
|
|
283
|
-
const attributesUsedInFeatures: {
|
|
284
|
-
[key: AttributeKey]: Set<FeatureKey>;
|
|
285
|
-
} = {};
|
|
286
|
-
const attributesUsedInSegments: {
|
|
287
|
-
[key: AttributeKey]: Set<SegmentKey>;
|
|
288
|
-
} = {};
|
|
289
|
-
const segmentsUsedInFeatures: {
|
|
290
|
-
[key: SegmentKey]: Set<FeatureKey>;
|
|
291
|
-
} = {};
|
|
292
|
-
|
|
293
|
-
// features
|
|
294
|
-
const featureFiles = datasource.listFeatures();
|
|
295
|
-
featureFiles.forEach((entityName) => {
|
|
296
|
-
const parsed = datasource.readFeature(entityName);
|
|
297
|
-
|
|
298
|
-
if (Array.isArray(parsed.variations)) {
|
|
299
|
-
parsed.variations.forEach((variation) => {
|
|
300
|
-
if (!variation.variables) {
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
variation.variables.forEach((v) => {
|
|
305
|
-
if (v.overrides) {
|
|
306
|
-
v.overrides.forEach((o) => {
|
|
307
|
-
if (o.conditions) {
|
|
308
|
-
extractAttributeKeysFromConditions(o.conditions).forEach((attributeKey) => {
|
|
309
|
-
if (!attributesUsedInFeatures[attributeKey]) {
|
|
310
|
-
attributesUsedInFeatures[attributeKey] = new Set();
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
attributesUsedInFeatures[attributeKey].add(entityName);
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
if (o.segments && o.segments !== "*") {
|
|
318
|
-
extractSegmentKeysFromGroupSegments(o.segments).forEach((segmentKey) => {
|
|
319
|
-
if (!segmentsUsedInFeatures[segmentKey]) {
|
|
320
|
-
segmentsUsedInFeatures[segmentKey] = new Set();
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
segmentsUsedInFeatures[segmentKey].add(entityName);
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
});
|
|
327
|
-
}
|
|
328
|
-
});
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
Object.keys(parsed.environments).forEach((environmentKey) => {
|
|
333
|
-
const env = parsed.environments[environmentKey];
|
|
334
|
-
|
|
335
|
-
env.rules.forEach((rule) => {
|
|
336
|
-
if (rule.segments && rule.segments !== "*") {
|
|
337
|
-
extractSegmentKeysFromGroupSegments(rule.segments).forEach((segmentKey) => {
|
|
338
|
-
if (!segmentsUsedInFeatures[segmentKey]) {
|
|
339
|
-
segmentsUsedInFeatures[segmentKey] = new Set();
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
segmentsUsedInFeatures[segmentKey].add(entityName);
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
if (env.force) {
|
|
348
|
-
env.force.forEach((force) => {
|
|
349
|
-
if (force.segments && force.segments !== "*") {
|
|
350
|
-
extractSegmentKeysFromGroupSegments(force.segments).forEach((segmentKey) => {
|
|
351
|
-
if (!segmentsUsedInFeatures[segmentKey]) {
|
|
352
|
-
segmentsUsedInFeatures[segmentKey] = new Set();
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
segmentsUsedInFeatures[segmentKey].add(entityName);
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
if (force.conditions) {
|
|
360
|
-
extractAttributeKeysFromConditions(force.conditions).forEach((attributeKey) => {
|
|
361
|
-
if (!attributesUsedInFeatures[attributeKey]) {
|
|
362
|
-
attributesUsedInFeatures[attributeKey] = new Set();
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
attributesUsedInFeatures[attributeKey].add(entityName);
|
|
366
|
-
});
|
|
367
|
-
}
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
result.entities.features.push({
|
|
373
|
-
...parsed,
|
|
374
|
-
key: entityName,
|
|
375
|
-
lastModified: getLastModifiedFromHistory(fullHistory, "feature", entityName),
|
|
376
|
-
});
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
// segments
|
|
380
|
-
const segmentFiles = datasource.listSegments();
|
|
381
|
-
segmentFiles.forEach((entityName) => {
|
|
382
|
-
const parsed = datasource.readSegment(entityName);
|
|
383
|
-
|
|
384
|
-
extractAttributeKeysFromConditions(parsed.conditions as Condition | Condition[]).forEach(
|
|
385
|
-
(attributeKey) => {
|
|
386
|
-
if (!attributesUsedInSegments[attributeKey]) {
|
|
387
|
-
attributesUsedInSegments[attributeKey] = new Set();
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
attributesUsedInSegments[attributeKey].add(entityName);
|
|
391
|
-
},
|
|
392
|
-
);
|
|
393
|
-
|
|
394
|
-
result.entities.segments.push({
|
|
395
|
-
...parsed,
|
|
396
|
-
key: entityName,
|
|
397
|
-
lastModified: getLastModifiedFromHistory(fullHistory, "segment", entityName),
|
|
398
|
-
usedInFeatures: Array.from(segmentsUsedInFeatures[entityName] || []),
|
|
399
|
-
});
|
|
400
|
-
});
|
|
401
|
-
|
|
402
|
-
// attributes
|
|
403
|
-
const attributeFiles = datasource.listAttributes();
|
|
404
|
-
attributeFiles.forEach((entityName) => {
|
|
405
|
-
const parsed = datasource.readAttribute(entityName);
|
|
406
|
-
|
|
407
|
-
result.entities.attributes.push({
|
|
408
|
-
...parsed,
|
|
409
|
-
key: entityName,
|
|
410
|
-
lastModified: getLastModifiedFromHistory(fullHistory, "attribute", entityName),
|
|
411
|
-
usedInFeatures: Array.from(attributesUsedInFeatures[entityName] || []),
|
|
412
|
-
usedInSegments: Array.from(attributesUsedInSegments[entityName] || []),
|
|
413
|
-
});
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
return result;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
export function exportSite(rootDirectoryPath: string, projectConfig: ProjectConfig) {
|
|
420
|
-
const hasError = false;
|
|
421
|
-
|
|
422
|
-
mkdirp.sync(projectConfig.siteExportDirectoryPath);
|
|
423
|
-
|
|
424
|
-
const sitePackagePath = path.dirname(require.resolve("@featurevisor/site/package.json"));
|
|
425
|
-
|
|
426
|
-
// copy site dist
|
|
427
|
-
const siteDistPath = path.join(sitePackagePath, "dist");
|
|
428
|
-
fs.cpSync(siteDistPath, projectConfig.siteExportDirectoryPath, { recursive: true });
|
|
429
|
-
|
|
430
|
-
const sitePublicPath = path.join(sitePackagePath, "public");
|
|
431
|
-
fs.cpSync(sitePublicPath, projectConfig.siteExportDirectoryPath, { recursive: true });
|
|
432
|
-
|
|
433
|
-
console.log("Site dist copied to:", projectConfig.siteExportDirectoryPath);
|
|
434
|
-
|
|
435
|
-
// generate history
|
|
436
|
-
const fullHistory = generateHistory(rootDirectoryPath, projectConfig);
|
|
437
|
-
|
|
438
|
-
// site search index
|
|
439
|
-
const repoDetails = getDetailsFromRepo();
|
|
440
|
-
const searchIndex = generateSiteSearchIndex(
|
|
441
|
-
rootDirectoryPath,
|
|
442
|
-
projectConfig,
|
|
443
|
-
fullHistory,
|
|
444
|
-
repoDetails,
|
|
445
|
-
);
|
|
446
|
-
const searchIndexFilePath = path.join(projectConfig.siteExportDirectoryPath, "search-index.json");
|
|
447
|
-
fs.writeFileSync(searchIndexFilePath, JSON.stringify(searchIndex));
|
|
448
|
-
console.log(`Site search index written at: ${searchIndexFilePath}`);
|
|
449
|
-
|
|
450
|
-
// copy datafiles
|
|
451
|
-
fs.cpSync(
|
|
452
|
-
projectConfig.outputDirectoryPath,
|
|
453
|
-
path.join(projectConfig.siteExportDirectoryPath, "datafiles"),
|
|
454
|
-
{ recursive: true },
|
|
455
|
-
);
|
|
456
|
-
|
|
457
|
-
// @TODO: replace placeoholders in index.html
|
|
458
|
-
|
|
459
|
-
return hasError;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
export function serveSite(
|
|
463
|
-
rootDirectoryPath: string,
|
|
464
|
-
projectConfig: ProjectConfig,
|
|
465
|
-
options: any = {},
|
|
466
|
-
) {
|
|
467
|
-
const port = options.p || 3000;
|
|
468
|
-
|
|
469
|
-
http
|
|
470
|
-
.createServer(function (request, response) {
|
|
471
|
-
const requestedUrl = request.url;
|
|
472
|
-
const filePath =
|
|
473
|
-
requestedUrl === "/"
|
|
474
|
-
? path.join(projectConfig.siteExportDirectoryPath, "index.html")
|
|
475
|
-
: path.join(projectConfig.siteExportDirectoryPath, requestedUrl as string);
|
|
476
|
-
|
|
477
|
-
console.log("requesting: " + filePath + "");
|
|
478
|
-
|
|
479
|
-
const extname = path.extname(filePath);
|
|
480
|
-
let contentType = "text/html";
|
|
481
|
-
switch (extname) {
|
|
482
|
-
case ".js":
|
|
483
|
-
contentType = "text/javascript";
|
|
484
|
-
break;
|
|
485
|
-
case ".css":
|
|
486
|
-
contentType = "text/css";
|
|
487
|
-
break;
|
|
488
|
-
case ".json":
|
|
489
|
-
contentType = "application/json";
|
|
490
|
-
break;
|
|
491
|
-
case ".png":
|
|
492
|
-
contentType = "image/png";
|
|
493
|
-
break;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
fs.readFile(filePath, function (error, content) {
|
|
497
|
-
if (error) {
|
|
498
|
-
if (error.code == "ENOENT") {
|
|
499
|
-
response.writeHead(404, { "Content-Type": "text/html" });
|
|
500
|
-
response.end("404 Not Found", "utf-8");
|
|
501
|
-
} else {
|
|
502
|
-
response.writeHead(500);
|
|
503
|
-
response.end("Error 500: " + error.code);
|
|
504
|
-
response.end();
|
|
505
|
-
}
|
|
506
|
-
} else {
|
|
507
|
-
response.writeHead(200, { "Content-Type": contentType });
|
|
508
|
-
response.end(content, "utf-8");
|
|
509
|
-
}
|
|
510
|
-
});
|
|
511
|
-
})
|
|
512
|
-
.listen(port);
|
|
513
|
-
|
|
514
|
-
console.log(`Server running at http://127.0.0.1:${port}/`);
|
|
515
|
-
}
|