@riebeckite/plugin-folder-pages 0.0.17 → 0.0.19
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/index.js +139 -92
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -13,21 +13,22 @@ function collapseFolderEntryLocations(locations) {
|
|
|
13
13
|
owners.set(location.permalink, location.slug);
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
const
|
|
17
|
-
for (const slug of locations
|
|
18
|
-
const basename =
|
|
16
|
+
const byFolderLanguage = /* @__PURE__ */ new Map();
|
|
17
|
+
for (const [slug, location] of locations) {
|
|
18
|
+
const basename = entryBaseSegment(slug, location.language);
|
|
19
19
|
if (!isEntryBasename(basename)) continue;
|
|
20
|
-
const
|
|
21
|
-
const slugs =
|
|
20
|
+
const key = languageKey(parentFolder(slug), location.language);
|
|
21
|
+
const slugs = byFolderLanguage.get(key);
|
|
22
22
|
if (slugs) slugs.push(slug);
|
|
23
|
-
else
|
|
23
|
+
else byFolderLanguage.set(key, [slug]);
|
|
24
24
|
}
|
|
25
|
-
for (const slugs of
|
|
25
|
+
for (const slugs of byFolderLanguage.values()) {
|
|
26
26
|
if (slugs.length !== 1) continue;
|
|
27
27
|
const slug = slugs[0];
|
|
28
|
+
if (slug === void 0) continue;
|
|
28
29
|
const location = locations.get(slug);
|
|
29
30
|
if (!location) continue;
|
|
30
|
-
const basename =
|
|
31
|
+
const basename = entryBaseSegment(slug, location.language);
|
|
31
32
|
if (!location.permalink.endsWith(`/${basename}`)) continue;
|
|
32
33
|
const target = location.permalink.slice(
|
|
33
34
|
0,
|
|
@@ -46,94 +47,111 @@ function collapseFolderEntryLocations(locations) {
|
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
49
|
function buildFolderPages(manifest) {
|
|
49
|
-
const pagesByFolder = /* @__PURE__ */ new Map();
|
|
50
|
-
const subfoldersOf = /* @__PURE__ */ new Map();
|
|
51
|
-
const allFolders = /* @__PURE__ */ new Set();
|
|
52
50
|
const routableBySlug = /* @__PURE__ */ new Map();
|
|
53
51
|
const routablePermalinks = /* @__PURE__ */ new Set();
|
|
54
52
|
for (const entry of manifest.publicEntries) {
|
|
55
53
|
routableBySlug.set(entry.slug, entry);
|
|
56
54
|
routablePermalinks.add(stripTrailingSlash(entry.permalink));
|
|
57
55
|
}
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
56
|
+
const allFolders = /* @__PURE__ */ new Set();
|
|
57
|
+
const folderLanguages = /* @__PURE__ */ new Map();
|
|
58
|
+
const pagesByFolderLanguage = /* @__PURE__ */ new Map();
|
|
59
|
+
const subfolders = /* @__PURE__ */ new Map();
|
|
60
|
+
const addLanguage = (folder, language) => {
|
|
61
|
+
const set = folderLanguages.get(folder);
|
|
62
|
+
if (set) set.add(language);
|
|
63
|
+
else folderLanguages.set(folder, /* @__PURE__ */ new Set([language]));
|
|
64
64
|
};
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (!isEntryBasename(basename)) {
|
|
71
|
-
const pages2 = pagesByFolder.get(parent);
|
|
72
|
-
if (pages2) pages2.push(entry);
|
|
73
|
-
else pagesByFolder.set(parent, [entry]);
|
|
65
|
+
const addPage = (folder, language, entry) => {
|
|
66
|
+
let byLanguage = pagesByFolderLanguage.get(folder);
|
|
67
|
+
if (!byLanguage) {
|
|
68
|
+
byLanguage = /* @__PURE__ */ new Map();
|
|
69
|
+
pagesByFolderLanguage.set(folder, byLanguage);
|
|
74
70
|
}
|
|
75
|
-
|
|
71
|
+
const entries = byLanguage.get(language);
|
|
72
|
+
if (entries) entries.push(entry);
|
|
73
|
+
else byLanguage.set(language, [entry]);
|
|
74
|
+
};
|
|
75
|
+
const addSubfolder = (parent, language, child) => {
|
|
76
|
+
let byLanguage = subfolders.get(parent);
|
|
77
|
+
if (!byLanguage) {
|
|
78
|
+
byLanguage = /* @__PURE__ */ new Map();
|
|
79
|
+
subfolders.set(parent, byLanguage);
|
|
80
|
+
}
|
|
81
|
+
const set = byLanguage.get(language);
|
|
82
|
+
if (set) set.add(child);
|
|
83
|
+
else byLanguage.set(language, /* @__PURE__ */ new Set([child]));
|
|
84
|
+
};
|
|
85
|
+
for (const entry of manifest.discoverableEntries) {
|
|
86
|
+
const language = entry.publicLocation.language;
|
|
87
|
+
const folder = parentFolder(entry.slug);
|
|
88
|
+
allFolders.add(folder);
|
|
89
|
+
let child = folder;
|
|
76
90
|
while (child !== "") {
|
|
91
|
+
addLanguage(child, language);
|
|
77
92
|
const grandparent = parentFolder(child);
|
|
78
|
-
addSubfolder(grandparent, child);
|
|
93
|
+
addSubfolder(grandparent, language, child);
|
|
79
94
|
child = grandparent;
|
|
80
95
|
}
|
|
96
|
+
if (isEntryBasename(entryBaseSegment(entry.slug, language))) continue;
|
|
97
|
+
if (folder !== "") addPage(folder, language, entry);
|
|
81
98
|
}
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
);
|
|
99
|
+
const owners = /* @__PURE__ */ new Map();
|
|
100
|
+
for (const entry of manifest.publicEntries) {
|
|
101
|
+
const language = entry.publicLocation.language;
|
|
102
|
+
const basename = entryBaseSegment(entry.slug, language);
|
|
103
|
+
if (!isEntryBasename(basename)) continue;
|
|
104
|
+
const folder = parentFolder(entry.slug);
|
|
105
|
+
if (folder === "") continue;
|
|
106
|
+
const key = languageKey(folder, language);
|
|
107
|
+
const existing = owners.get(key);
|
|
108
|
+
if (!existing || basename === "README") owners.set(key, entry);
|
|
109
|
+
}
|
|
110
|
+
const hasOwner = (folder, language) => owners.has(languageKey(folder, language));
|
|
111
|
+
const hasRoutablePage = (folder, language) => {
|
|
112
|
+
const entry = routableBySlug.get(folder);
|
|
113
|
+
return entry !== void 0 && entry.publicLocation.language === language;
|
|
114
|
+
};
|
|
115
|
+
const generatedPath = (folder, language) => resolveGeneratedFolderLocation(manifest, folder, language);
|
|
116
|
+
const subfoldersFor = (folder, language) => subfolders.get(folder)?.get(language) ?? /* @__PURE__ */ new Set();
|
|
117
|
+
const sortedPages = (folder, language) => {
|
|
118
|
+
const subs = subfoldersFor(folder, language);
|
|
119
|
+
const pages2 = (pagesByFolderLanguage.get(folder)?.get(language) ?? []).filter((entry) => !subs.has(entry.slug));
|
|
89
120
|
pages2.sort(compareEntries);
|
|
90
121
|
return pages2;
|
|
91
122
|
};
|
|
92
123
|
const navigableCache = /* @__PURE__ */ new Map();
|
|
93
|
-
const isNavigable = (folder) => {
|
|
94
|
-
const
|
|
124
|
+
const isNavigable = (folder, language) => {
|
|
125
|
+
const key = languageKey(folder, language);
|
|
126
|
+
const cached = navigableCache.get(key);
|
|
95
127
|
if (cached !== void 0) return cached;
|
|
96
|
-
navigableCache.set(
|
|
97
|
-
let result = sortedPages(folder).length > 0 ||
|
|
128
|
+
navigableCache.set(key, false);
|
|
129
|
+
let result = sortedPages(folder, language).length > 0 || hasOwner(folder, language) || hasRoutablePage(folder, language);
|
|
98
130
|
if (!result) {
|
|
99
|
-
for (const sub of
|
|
100
|
-
if (isListed(sub)) {
|
|
131
|
+
for (const sub of subfoldersFor(folder, language)) {
|
|
132
|
+
if (isListed(sub, language)) {
|
|
101
133
|
result = true;
|
|
102
134
|
break;
|
|
103
135
|
}
|
|
104
136
|
}
|
|
105
137
|
}
|
|
106
|
-
navigableCache.set(
|
|
138
|
+
navigableCache.set(key, result);
|
|
107
139
|
return result;
|
|
108
140
|
};
|
|
109
|
-
const isListed = (folder) =>
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (!entry.slug.startsWith(`${folder}/`)) continue;
|
|
115
|
-
const value = entry.publicLocation.language;
|
|
116
|
-
if (value === void 0) return void 0;
|
|
117
|
-
if (language === void 0) language = value;
|
|
118
|
-
else if (language !== value) return void 0;
|
|
119
|
-
}
|
|
120
|
-
return language;
|
|
121
|
-
};
|
|
122
|
-
const folderLink = (folder) => {
|
|
123
|
-
if (hasRoutableOwner(folder)) {
|
|
124
|
-
const owner = routableBySlug.get(`${folder}/README`) ?? routableBySlug.get(`${folder}/index`);
|
|
125
|
-
if (owner) return { title: owner.title, permalink: owner.permalink };
|
|
126
|
-
}
|
|
127
|
-
const page = routableBySlug.get(folder);
|
|
141
|
+
const isListed = (folder, language) => hasOwner(folder, language) || hasRoutablePage(folder, language) || isNavigable(folder, language) && generatedPath(folder, language) !== null;
|
|
142
|
+
const folderLink = (folder, language) => {
|
|
143
|
+
const owner = owners.get(languageKey(folder, language));
|
|
144
|
+
if (owner) return { title: owner.title, permalink: owner.permalink };
|
|
145
|
+
const page = hasRoutablePage(folder, language) ? routableBySlug.get(folder) : void 0;
|
|
128
146
|
if (page) return { title: page.title, permalink: page.permalink };
|
|
129
|
-
const pathname = generatedPath(folder);
|
|
147
|
+
const pathname = generatedPath(folder, language);
|
|
130
148
|
if (!pathname) return null;
|
|
131
149
|
return { title: lastSegment(folder), permalink: pathname };
|
|
132
150
|
};
|
|
133
|
-
const sortedSubfolders = (folder) => {
|
|
134
|
-
const subs = [...
|
|
135
|
-
if (!isListed(sub)) return [];
|
|
136
|
-
const link = folderLink(sub);
|
|
151
|
+
const sortedSubfolders = (folder, language) => {
|
|
152
|
+
const subs = [...subfoldersFor(folder, language)].flatMap((sub) => {
|
|
153
|
+
if (!isListed(sub, language)) return [];
|
|
154
|
+
const link = folderLink(sub, language);
|
|
137
155
|
return link ? [{ folder: sub, link }] : [];
|
|
138
156
|
});
|
|
139
157
|
subs.sort((a, b) => compareLinks(a.link, b.link));
|
|
@@ -144,37 +162,59 @@ function buildFolderPages(manifest) {
|
|
|
144
162
|
const pages = [];
|
|
145
163
|
const takenPaths = /* @__PURE__ */ new Set();
|
|
146
164
|
for (const folder of folders) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
165
|
+
for (const language of sortedLanguages(folderLanguages.get(folder))) {
|
|
166
|
+
if (!isNavigable(folder, language)) continue;
|
|
167
|
+
if (hasOwner(folder, language)) continue;
|
|
168
|
+
if (hasRoutablePage(folder, language)) continue;
|
|
169
|
+
const pathname = generatedPath(folder, language);
|
|
170
|
+
if (!pathname) continue;
|
|
171
|
+
if (pathname === "/") continue;
|
|
172
|
+
if (routablePermalinks.has(stripTrailingSlash(pathname))) continue;
|
|
173
|
+
if (takenPaths.has(pathname)) continue;
|
|
174
|
+
takenPaths.add(pathname);
|
|
175
|
+
const folderLinks = sortedSubfolders(folder, language);
|
|
176
|
+
pages.push({
|
|
177
|
+
folder,
|
|
178
|
+
pathname,
|
|
179
|
+
language,
|
|
180
|
+
title: lastSegment(folder),
|
|
181
|
+
pages: sortedPages(folder, language).map(toLink),
|
|
182
|
+
folders: folderLinks.map((sub) => sub.link),
|
|
183
|
+
dependencies: [
|
|
184
|
+
{ type: "folder", folder },
|
|
185
|
+
...folderLinks.map((sub) => ({
|
|
186
|
+
type: "folder",
|
|
187
|
+
folder: sub.folder
|
|
188
|
+
}))
|
|
189
|
+
]
|
|
190
|
+
});
|
|
191
|
+
}
|
|
172
192
|
}
|
|
173
193
|
pages.sort((a, b) => compareStrings(a.pathname, b.pathname));
|
|
174
194
|
const byPath = /* @__PURE__ */ new Map();
|
|
175
195
|
for (const page of pages) byPath.set(page.pathname, page);
|
|
176
196
|
return { paths: pages.map((page) => page.pathname), byPath };
|
|
177
197
|
}
|
|
198
|
+
function languageKey(folder, language) {
|
|
199
|
+
return `${folder}\0${language ?? ""}`;
|
|
200
|
+
}
|
|
201
|
+
function entryBaseSegment(slug, language) {
|
|
202
|
+
const segment = lastSegment(slug);
|
|
203
|
+
if (!language) return segment;
|
|
204
|
+
return segment.replace(
|
|
205
|
+
new RegExp(`[._-]${escapeRegExp(language)}$`, "i"),
|
|
206
|
+
""
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
function sortedLanguages(languages) {
|
|
210
|
+
return [...languages ?? []].sort((a, b) => {
|
|
211
|
+
const left = a ?? "";
|
|
212
|
+
const right = b ?? "";
|
|
213
|
+
if (left < right) return -1;
|
|
214
|
+
if (left > right) return 1;
|
|
215
|
+
return 0;
|
|
216
|
+
});
|
|
217
|
+
}
|
|
178
218
|
function isEntryBasename(basename) {
|
|
179
219
|
return ENTRY_BASENAMES.includes(basename);
|
|
180
220
|
}
|
|
@@ -193,6 +233,9 @@ function stripTrailingSlash(url) {
|
|
|
193
233
|
if (url.length > 1 && url.endsWith("/")) return url.slice(0, -1);
|
|
194
234
|
return url;
|
|
195
235
|
}
|
|
236
|
+
function escapeRegExp(value) {
|
|
237
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
238
|
+
}
|
|
196
239
|
function compareEntries(a, b) {
|
|
197
240
|
return compareStrings(a.permalink, b.permalink) || compareStrings(a.title, b.title) || compareStrings(a.slug, b.slug);
|
|
198
241
|
}
|
|
@@ -285,7 +328,11 @@ function folderPages(options = {}) {
|
|
|
285
328
|
},
|
|
286
329
|
onManifestCreated: ({ manifest }) => {
|
|
287
330
|
for (const page of modelFor(manifest).byPath.values()) {
|
|
288
|
-
manifest.folderLocations.set(page.
|
|
331
|
+
manifest.folderLocations.set(page.pathname, {
|
|
332
|
+
pathname: page.pathname,
|
|
333
|
+
folder: page.folder,
|
|
334
|
+
...page.language === void 0 ? {} : { language: page.language }
|
|
335
|
+
});
|
|
289
336
|
}
|
|
290
337
|
},
|
|
291
338
|
pageTypes: [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riebeckite/plugin-folder-pages",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.19",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@riebeckite/core": "0.0.
|
|
17
|
+
"@riebeckite/core": "0.0.19"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"tsx": "^4.22.4",
|
|
21
|
-
"@riebeckite/plugin-
|
|
22
|
-
"@riebeckite/plugin-
|
|
21
|
+
"@riebeckite/plugin-taxonomy": "0.0.19",
|
|
22
|
+
"@riebeckite/plugin-l10n": "0.0.19"
|
|
23
23
|
},
|
|
24
24
|
"publishConfig": {
|
|
25
25
|
"access": "public"
|