@stati/core 1.27.2 → 1.29.0
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/README.md +6 -1
- package/dist/config/errors.d.ts +10 -0
- package/dist/config/errors.d.ts.map +1 -0
- package/dist/config/errors.js +10 -0
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +15 -2
- package/dist/constants.d.ts +26 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +23 -0
- package/dist/core/build.d.ts.map +1 -1
- package/dist/core/build.js +201 -41
- package/dist/core/collections.d.ts +139 -0
- package/dist/core/collections.d.ts.map +1 -0
- package/dist/core/collections.js +342 -0
- package/dist/core/content.d.ts.map +1 -1
- package/dist/core/content.js +2 -1
- package/dist/core/dev.d.ts.map +1 -1
- package/dist/core/dev.js +11 -62
- package/dist/core/expand.d.ts +86 -0
- package/dist/core/expand.d.ts.map +1 -0
- package/dist/core/expand.js +484 -0
- package/dist/core/isg/builder.d.ts +27 -2
- package/dist/core/isg/builder.d.ts.map +1 -1
- package/dist/core/isg/builder.js +83 -11
- package/dist/core/isg/deps.d.ts +9 -0
- package/dist/core/isg/deps.d.ts.map +1 -1
- package/dist/core/isg/deps.js +30 -1
- package/dist/core/isg/hash.d.ts +14 -2
- package/dist/core/isg/hash.d.ts.map +1 -1
- package/dist/core/isg/hash.js +30 -2
- package/dist/core/isg/index.d.ts +4 -2
- package/dist/core/isg/index.d.ts.map +1 -1
- package/dist/core/isg/index.js +4 -2
- package/dist/core/isg/manifest.js +14 -0
- package/dist/core/isg/prune.d.ts +32 -0
- package/dist/core/isg/prune.d.ts.map +1 -0
- package/dist/core/isg/prune.js +113 -0
- package/dist/core/markdown.d.ts +10 -1
- package/dist/core/markdown.d.ts.map +1 -1
- package/dist/core/markdown.js +13 -3
- package/dist/core/navigation.d.ts +4 -2
- package/dist/core/navigation.d.ts.map +1 -1
- package/dist/core/navigation.js +17 -2
- package/dist/core/templates.d.ts +15 -1
- package/dist/core/templates.d.ts.map +1 -1
- package/dist/core/templates.js +121 -126
- package/dist/core/utils/fs.utils.d.ts +29 -1
- package/dist/core/utils/fs.utils.d.ts.map +1 -1
- package/dist/core/utils/fs.utils.js +74 -1
- package/dist/core/utils/index.d.ts +3 -3
- package/dist/core/utils/index.d.ts.map +1 -1
- package/dist/core/utils/index.js +3 -3
- package/dist/core/utils/paths.utils.d.ts +15 -0
- package/dist/core/utils/paths.utils.d.ts.map +1 -1
- package/dist/core/utils/paths.utils.js +20 -0
- package/dist/core/utils/template-discovery.utils.d.ts +25 -1
- package/dist/core/utils/template-discovery.utils.d.ts.map +1 -1
- package/dist/core/utils/template-discovery.utils.js +61 -11
- package/dist/images/config.d.ts +52 -0
- package/dist/images/config.d.ts.map +1 -0
- package/dist/images/config.js +200 -0
- package/dist/images/index.d.ts +15 -0
- package/dist/images/index.d.ts.map +1 -0
- package/dist/images/index.js +11 -0
- package/dist/images/manifest.d.ts +36 -0
- package/dist/images/manifest.d.ts.map +1 -0
- package/dist/images/manifest.js +69 -0
- package/dist/images/markdown-rule.d.ts +26 -0
- package/dist/images/markdown-rule.d.ts.map +1 -0
- package/dist/images/markdown-rule.js +60 -0
- package/dist/images/markup.d.ts +39 -0
- package/dist/images/markup.d.ts.map +1 -0
- package/dist/images/markup.js +72 -0
- package/dist/images/og.d.ts +52 -0
- package/dist/images/og.d.ts.map +1 -0
- package/dist/images/og.js +165 -0
- package/dist/images/plan.d.ts +101 -0
- package/dist/images/plan.d.ts.map +1 -0
- package/dist/images/plan.js +128 -0
- package/dist/images/provider.d.ts +35 -0
- package/dist/images/provider.d.ts.map +1 -0
- package/dist/images/provider.js +70 -0
- package/dist/images/resolve.d.ts +45 -0
- package/dist/images/resolve.d.ts.map +1 -0
- package/dist/images/resolve.js +51 -0
- package/dist/images/runtime.d.ts +258 -0
- package/dist/images/runtime.d.ts.map +1 -0
- package/dist/images/runtime.js +659 -0
- package/dist/images/sources.d.ts +47 -0
- package/dist/images/sources.d.ts.map +1 -0
- package/dist/images/sources.js +97 -0
- package/dist/images/utils/image-probe.utils.d.ts +30 -0
- package/dist/images/utils/image-probe.utils.d.ts.map +1 -0
- package/dist/images/utils/image-probe.utils.js +307 -0
- package/dist/images/utils/index.d.ts +7 -0
- package/dist/images/utils/index.d.ts.map +1 -0
- package/dist/images/utils/index.js +5 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/metrics/noop.d.ts.map +1 -1
- package/dist/metrics/noop.js +3 -0
- package/dist/metrics/recorder.d.ts.map +1 -1
- package/dist/metrics/recorder.js +3 -0
- package/dist/metrics/types.d.ts +8 -0
- package/dist/metrics/types.d.ts.map +1 -1
- package/dist/rss/generator.d.ts.map +1 -1
- package/dist/rss/generator.js +5 -2
- package/dist/search/generator.d.ts +9 -0
- package/dist/search/generator.d.ts.map +1 -1
- package/dist/search/generator.js +20 -0
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/index.js +1 -1
- package/dist/seo/auto-inject.d.ts +3 -0
- package/dist/seo/auto-inject.d.ts.map +1 -1
- package/dist/seo/auto-inject.js +1 -0
- package/dist/seo/generator.d.ts +24 -0
- package/dist/seo/generator.d.ts.map +1 -1
- package/dist/seo/generator.js +65 -1
- package/dist/seo/index.d.ts +1 -1
- package/dist/seo/index.d.ts.map +1 -1
- package/dist/seo/index.js +1 -1
- package/dist/types/config.d.ts +60 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/content.d.ts +150 -3
- package/dist/types/content.d.ts.map +1 -1
- package/dist/types/images.d.ts +185 -0
- package/dist/types/images.d.ts.map +1 -0
- package/dist/types/images.js +8 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/isg.d.ts +19 -0
- package/dist/types/isg.d.ts.map +1 -1
- package/dist/types/seo.d.ts +9 -0
- package/dist/types/seo.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { FrontMatter, Logger, PageModel, PaginationData, StatiConfig } from '../types/index.js';
|
|
2
|
+
/** URL segment before the page number when `paginate.path` is not set */
|
|
3
|
+
export declare const DEFAULT_PAGINATION_PATH = "page";
|
|
4
|
+
/**
|
|
5
|
+
* Resolved pagination settings.
|
|
6
|
+
*/
|
|
7
|
+
interface PaginationSettings {
|
|
8
|
+
size: number;
|
|
9
|
+
path: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Returns the parameter name of a `[param].md` template, or undefined for other pages.
|
|
13
|
+
*
|
|
14
|
+
* @param page - A loaded page
|
|
15
|
+
* @returns The name between the brackets
|
|
16
|
+
*/
|
|
17
|
+
export declare function getTemplateParam(page: PageModel): string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Replaces `{param}` with the label in a string. `{{param}}` produces the literal `{param}`,
|
|
20
|
+
* and placeholders of other names are left as they are.
|
|
21
|
+
*
|
|
22
|
+
* @param text - The string to fill in
|
|
23
|
+
* @param param - The template's parameter name, such as `tag`
|
|
24
|
+
* @param label - The value, such as `CSS`
|
|
25
|
+
* @returns The string with its placeholders replaced
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* replacePlaceholders('Posts tagged {tag}', 'tag', 'CSS'); // 'Posts tagged CSS'
|
|
30
|
+
* replacePlaceholders('Use {{tag}} in titles', 'tag', 'CSS'); // 'Use {tag} in titles'
|
|
31
|
+
* replacePlaceholders('{author} on {tag}', 'tag', 'CSS'); // '{author} on CSS'
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare function replacePlaceholders(text: string, param: string, label: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Copies a template's front matter for one generated page, with `{param}` placeholders filled
|
|
37
|
+
* in. `generate` and `permalink` are copied as they are: they configure the template, and
|
|
38
|
+
* `permalink` takes the key through `[param]` instead.
|
|
39
|
+
*
|
|
40
|
+
* @param frontMatter - The template's front matter
|
|
41
|
+
* @param param - The template's parameter name
|
|
42
|
+
* @param label - The value for the page
|
|
43
|
+
* @returns The page's front matter
|
|
44
|
+
*/
|
|
45
|
+
export declare function substituteFrontMatter(frontMatter: FrontMatter, param: string, label: string): FrontMatter;
|
|
46
|
+
/**
|
|
47
|
+
* URL of page `pageNumber` of a listing whose first page is `baseUrl`. Later pages follow the
|
|
48
|
+
* first page's trailing-slash style: `/blog` → `/blog/page/2`, `/blog/` → `/blog/page/2/`,
|
|
49
|
+
* `/` → `/page/2`.
|
|
50
|
+
*
|
|
51
|
+
* @param baseUrl - URL of the first page
|
|
52
|
+
* @param path - URL segment before the page number
|
|
53
|
+
* @param pageNumber - Page number, starting at 1
|
|
54
|
+
* @returns The page URL
|
|
55
|
+
*/
|
|
56
|
+
export declare function getPaginationUrl(baseUrl: string, path: string, pageNumber: number): string;
|
|
57
|
+
/**
|
|
58
|
+
* Builds the pagination data of every page of a listing.
|
|
59
|
+
*
|
|
60
|
+
* @param baseUrl - URL of the first page
|
|
61
|
+
* @param items - Everything the listing shows, in order
|
|
62
|
+
* @param settings - Page size and URL segment
|
|
63
|
+
* @returns One entry per page; there is always at least one
|
|
64
|
+
*/
|
|
65
|
+
export declare function paginateItems(baseUrl: string, items: readonly PageModel[], settings: PaginationSettings): PaginationData[];
|
|
66
|
+
/**
|
|
67
|
+
* Turns the pages loaded from Markdown into the pages of a build:
|
|
68
|
+
*
|
|
69
|
+
* - Each `[param].md` template is removed and replaced by one page per key: per value of
|
|
70
|
+
* `generate.from` in its collection, and per `collections.generate` entry that names it.
|
|
71
|
+
* A template that produces no keys produces no output.
|
|
72
|
+
* - Every page with `paginate`, and every generated page whose template has
|
|
73
|
+
* `generate.paginate`, gets one more page per additional slice of its items.
|
|
74
|
+
*
|
|
75
|
+
* Generated and pagination pages are virtual: they are never collection members and are left
|
|
76
|
+
* out of navigation, search and RSS unless they opt in. A virtual page whose URL or output
|
|
77
|
+
* file is already taken is skipped with a warning.
|
|
78
|
+
*
|
|
79
|
+
* @param loaded - Pages loaded from Markdown files
|
|
80
|
+
* @param config - Stati configuration
|
|
81
|
+
* @param logger - Logger for warnings
|
|
82
|
+
* @returns The pages to build: loaded pages without templates, then virtual pages
|
|
83
|
+
*/
|
|
84
|
+
export declare function expandPages(loaded: PageModel[], config: StatiConfig, logger: Logger): Promise<PageModel[]>;
|
|
85
|
+
export {};
|
|
86
|
+
//# sourceMappingURL=expand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expand.d.ts","sourceRoot":"","sources":["../../src/core/expand.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EAGX,MAAM,EACN,SAAS,EACT,cAAc,EACd,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAmB3B,yEAAyE;AACzE,eAAO,MAAM,uBAAuB,SAAS,CAAC;AAE9C;;GAEG;AACH,UAAU,kBAAkB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAWD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAEpE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAKtF;AAwBD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,WAAW,EACxB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,WAAW,CASb;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAU1F;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,SAAS,SAAS,EAAE,EAC3B,QAAQ,EAAE,kBAAkB,GAC3B,cAAc,EAAE,CAclB;AA6FD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,SAAS,EAAE,EACnB,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,SAAS,EAAE,CAAC,CA+NtB"}
|
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
import { basename, join, relative, sep } from 'node:path';
|
|
2
|
+
import { getPageOutputFile, resolveSrcDir, slugify } from './utils/index.js';
|
|
3
|
+
import { findCollectionPath, getCollections, resolveCollectionPath } from './collections.js';
|
|
4
|
+
/**
|
|
5
|
+
* File name of a template that expands into one page per key, such as `[tag].md`.
|
|
6
|
+
*/
|
|
7
|
+
const TEMPLATE_FILE_PATTERN = /^\[([^\]]*)\]\.md$/;
|
|
8
|
+
/**
|
|
9
|
+
* Valid template parameter names: `[tag].md`, `[author].md`, `[release_year].md`.
|
|
10
|
+
*/
|
|
11
|
+
const PARAM_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_-]*$/;
|
|
12
|
+
/**
|
|
13
|
+
* Valid `paginate.path` values: one URL segment.
|
|
14
|
+
*/
|
|
15
|
+
const PAGINATION_PATH_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
16
|
+
/** URL segment before the page number when `paginate.path` is not set */
|
|
17
|
+
export const DEFAULT_PAGINATION_PATH = 'page';
|
|
18
|
+
/**
|
|
19
|
+
* Returns the parameter name of a `[param].md` template, or undefined for other pages.
|
|
20
|
+
*
|
|
21
|
+
* @param page - A loaded page
|
|
22
|
+
* @returns The name between the brackets
|
|
23
|
+
*/
|
|
24
|
+
export function getTemplateParam(page) {
|
|
25
|
+
return TEMPLATE_FILE_PATTERN.exec(basename(page.sourcePath))?.[1];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Replaces `{param}` with the label in a string. `{{param}}` produces the literal `{param}`,
|
|
29
|
+
* and placeholders of other names are left as they are.
|
|
30
|
+
*
|
|
31
|
+
* @param text - The string to fill in
|
|
32
|
+
* @param param - The template's parameter name, such as `tag`
|
|
33
|
+
* @param label - The value, such as `CSS`
|
|
34
|
+
* @returns The string with its placeholders replaced
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* replacePlaceholders('Posts tagged {tag}', 'tag', 'CSS'); // 'Posts tagged CSS'
|
|
39
|
+
* replacePlaceholders('Use {{tag}} in titles', 'tag', 'CSS'); // 'Use {tag} in titles'
|
|
40
|
+
* replacePlaceholders('{author} on {tag}', 'tag', 'CSS'); // '{author} on CSS'
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export function replacePlaceholders(text, param, label) {
|
|
44
|
+
const name = param.replace(/[.*+?^${}()|[\]\\-]/g, '\\$&');
|
|
45
|
+
return text.replace(new RegExp(`\\{\\{${name}\\}\\}|\\{${name}\\}`, 'g'), (match) => match.startsWith('{{') ? `{${param}}` : label);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Deep-copies a value from front matter (YAML data: strings, numbers, booleans, dates, lists
|
|
49
|
+
* and mappings), passing every string inside it through `mapString`.
|
|
50
|
+
*/
|
|
51
|
+
function copyValue(value, mapString = (text) => text) {
|
|
52
|
+
if (typeof value === 'string') {
|
|
53
|
+
return mapString(value);
|
|
54
|
+
}
|
|
55
|
+
if (Array.isArray(value)) {
|
|
56
|
+
return value.map((item) => copyValue(item, mapString));
|
|
57
|
+
}
|
|
58
|
+
if (value instanceof Date) {
|
|
59
|
+
return new Date(value.getTime());
|
|
60
|
+
}
|
|
61
|
+
if (value && typeof value === 'object') {
|
|
62
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, copyValue(item, mapString)]));
|
|
63
|
+
}
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Copies a template's front matter for one generated page, with `{param}` placeholders filled
|
|
68
|
+
* in. `generate` and `permalink` are copied as they are: they configure the template, and
|
|
69
|
+
* `permalink` takes the key through `[param]` instead.
|
|
70
|
+
*
|
|
71
|
+
* @param frontMatter - The template's front matter
|
|
72
|
+
* @param param - The template's parameter name
|
|
73
|
+
* @param label - The value for the page
|
|
74
|
+
* @returns The page's front matter
|
|
75
|
+
*/
|
|
76
|
+
export function substituteFrontMatter(frontMatter, param, label) {
|
|
77
|
+
const result = {};
|
|
78
|
+
for (const [key, value] of Object.entries(frontMatter)) {
|
|
79
|
+
result[key] =
|
|
80
|
+
key === 'generate' || key === 'permalink'
|
|
81
|
+
? copyValue(value)
|
|
82
|
+
: copyValue(value, (text) => replacePlaceholders(text, param, label));
|
|
83
|
+
}
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* URL of page `pageNumber` of a listing whose first page is `baseUrl`. Later pages follow the
|
|
88
|
+
* first page's trailing-slash style: `/blog` → `/blog/page/2`, `/blog/` → `/blog/page/2/`,
|
|
89
|
+
* `/` → `/page/2`.
|
|
90
|
+
*
|
|
91
|
+
* @param baseUrl - URL of the first page
|
|
92
|
+
* @param path - URL segment before the page number
|
|
93
|
+
* @param pageNumber - Page number, starting at 1
|
|
94
|
+
* @returns The page URL
|
|
95
|
+
*/
|
|
96
|
+
export function getPaginationUrl(baseUrl, path, pageNumber) {
|
|
97
|
+
if (pageNumber <= 1) {
|
|
98
|
+
return baseUrl;
|
|
99
|
+
}
|
|
100
|
+
if (baseUrl === '/') {
|
|
101
|
+
return `/${path}/${pageNumber}`;
|
|
102
|
+
}
|
|
103
|
+
return baseUrl.endsWith('/')
|
|
104
|
+
? `${baseUrl}${path}/${pageNumber}/`
|
|
105
|
+
: `${baseUrl}/${path}/${pageNumber}`;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Builds the pagination data of every page of a listing.
|
|
109
|
+
*
|
|
110
|
+
* @param baseUrl - URL of the first page
|
|
111
|
+
* @param items - Everything the listing shows, in order
|
|
112
|
+
* @param settings - Page size and URL segment
|
|
113
|
+
* @returns One entry per page; there is always at least one
|
|
114
|
+
*/
|
|
115
|
+
export function paginateItems(baseUrl, items, settings) {
|
|
116
|
+
const totalPages = Math.max(1, Math.ceil(items.length / settings.size));
|
|
117
|
+
const urls = Array.from({ length: totalPages }, (_, i) => getPaginationUrl(baseUrl, settings.path, i + 1));
|
|
118
|
+
return urls.map((_, i) => ({
|
|
119
|
+
pageNumber: i + 1,
|
|
120
|
+
totalPages,
|
|
121
|
+
items: items.slice(i * settings.size, (i + 1) * settings.size),
|
|
122
|
+
...(i > 0 && { prevUrl: urls[i - 1] }),
|
|
123
|
+
...(i < totalPages - 1 && { nextUrl: urls[i + 1] }),
|
|
124
|
+
// One array for the whole listing, not one per page; templates get their own copy
|
|
125
|
+
urls,
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Reads `paginate` settings from front matter.
|
|
130
|
+
*
|
|
131
|
+
* @param value - `paginate` or `generate.paginate`: a size, or `{ size, path }`
|
|
132
|
+
* @param warn - Reports an invalid value
|
|
133
|
+
* @returns The settings, or undefined when the value is absent or invalid
|
|
134
|
+
*/
|
|
135
|
+
function parsePaginate(value, warn) {
|
|
136
|
+
if (value === undefined || value === null || value === false) {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
const options = typeof value === 'number' ? { size: value } : value;
|
|
140
|
+
if (!options || typeof options !== 'object' || Array.isArray(options)) {
|
|
141
|
+
warn('paginate must be a page size or { size, path }; the page is not paginated');
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
const { size, path } = options;
|
|
145
|
+
if (typeof size !== 'number' || !Number.isInteger(size) || size < 1) {
|
|
146
|
+
warn('paginate.size must be a whole number of at least 1; the page is not paginated');
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
if (path === undefined) {
|
|
150
|
+
return { size, path: DEFAULT_PAGINATION_PATH };
|
|
151
|
+
}
|
|
152
|
+
if (typeof path !== 'string' || !PAGINATION_PATH_PATTERN.test(path)) {
|
|
153
|
+
warn(`paginate.path must be a single URL segment such as "page"; using "${DEFAULT_PAGINATION_PATH}"`);
|
|
154
|
+
return { size, path: DEFAULT_PAGINATION_PATH };
|
|
155
|
+
}
|
|
156
|
+
return { size, path };
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Groups the pages of a collection by the values of a front matter field. Values are slugified
|
|
160
|
+
* into keys; values that slugify to the same key share one group, under the first value seen.
|
|
161
|
+
*
|
|
162
|
+
* @param pages - Collection pages, newest first
|
|
163
|
+
* @param field - Front matter field holding a string, a number, or a list of them
|
|
164
|
+
* @param onEmptyKey - Reports a value that slugifies to nothing
|
|
165
|
+
* @param onCollision - Reports a value merged into the group of another value
|
|
166
|
+
* @returns The groups, sorted by key
|
|
167
|
+
*/
|
|
168
|
+
function groupByField(pages, field, onEmptyKey, onCollision) {
|
|
169
|
+
const groups = new Map();
|
|
170
|
+
for (const page of pages) {
|
|
171
|
+
const value = page.frontMatter[field];
|
|
172
|
+
const values = Array.isArray(value) ? value : [value];
|
|
173
|
+
const pageKeys = new Set();
|
|
174
|
+
for (const raw of values) {
|
|
175
|
+
if (typeof raw !== 'string' && !(typeof raw === 'number' && Number.isFinite(raw))) {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const label = String(raw).trim();
|
|
179
|
+
if (!label) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
const key = slugify(label);
|
|
183
|
+
if (!key) {
|
|
184
|
+
onEmptyKey(label);
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
let group = groups.get(key);
|
|
188
|
+
if (!group) {
|
|
189
|
+
group = { key, label, items: [] };
|
|
190
|
+
groups.set(key, group);
|
|
191
|
+
}
|
|
192
|
+
else if (group.label !== label) {
|
|
193
|
+
onCollision(key, group.label, label);
|
|
194
|
+
}
|
|
195
|
+
// A page that lists two values with the same key appears once
|
|
196
|
+
if (!pageKeys.has(key)) {
|
|
197
|
+
pageKeys.add(key);
|
|
198
|
+
group.items.push(page);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return [...groups.values()].sort((a, b) => a.key.localeCompare(b.key));
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Turns the pages loaded from Markdown into the pages of a build:
|
|
206
|
+
*
|
|
207
|
+
* - Each `[param].md` template is removed and replaced by one page per key: per value of
|
|
208
|
+
* `generate.from` in its collection, and per `collections.generate` entry that names it.
|
|
209
|
+
* A template that produces no keys produces no output.
|
|
210
|
+
* - Every page with `paginate`, and every generated page whose template has
|
|
211
|
+
* `generate.paginate`, gets one more page per additional slice of its items.
|
|
212
|
+
*
|
|
213
|
+
* Generated and pagination pages are virtual: they are never collection members and are left
|
|
214
|
+
* out of navigation, search and RSS unless they opt in. A virtual page whose URL or output
|
|
215
|
+
* file is already taken is skipped with a warning.
|
|
216
|
+
*
|
|
217
|
+
* @param loaded - Pages loaded from Markdown files
|
|
218
|
+
* @param config - Stati configuration
|
|
219
|
+
* @param logger - Logger for warnings
|
|
220
|
+
* @returns The pages to build: loaded pages without templates, then virtual pages
|
|
221
|
+
*/
|
|
222
|
+
export async function expandPages(loaded, config, logger) {
|
|
223
|
+
// Source-relative path of a page, such as blog/tags/[tag].md, for template paths and warnings
|
|
224
|
+
let srcDir;
|
|
225
|
+
const label = (page) => relative((srcDir ??= resolveSrcDir(config)), page.sourcePath).replace(/\\/g, '/');
|
|
226
|
+
const reported = new Set();
|
|
227
|
+
const warnOnce = (message) => {
|
|
228
|
+
if (!reported.has(message)) {
|
|
229
|
+
reported.add(message);
|
|
230
|
+
logger.warning(message);
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
const templates = [];
|
|
234
|
+
const pages = [];
|
|
235
|
+
for (const page of loaded) {
|
|
236
|
+
const param = getTemplateParam(page);
|
|
237
|
+
if (param === undefined) {
|
|
238
|
+
pages.push(page);
|
|
239
|
+
}
|
|
240
|
+
else if (!PARAM_NAME_PATTERN.test(param)) {
|
|
241
|
+
warnOnce(`${label(page)}: "${param}" is not a valid template parameter (use letters, digits, - and _, such as [tag].md); the file is skipped`);
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
templates.push({ page, param, path: label(page) });
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
const collections = getCollections(pages);
|
|
248
|
+
// Front matter that only works elsewhere, or names a collection that doesn't exist
|
|
249
|
+
for (const page of pages) {
|
|
250
|
+
const { collection, generate } = page.frontMatter;
|
|
251
|
+
if (collection !== undefined && findCollectionPath(collections, collection) === undefined) {
|
|
252
|
+
warnOnce(`${label(page)}: collection "${String(collection)}" is not the URL of a collection index page; the page reads its default collection`);
|
|
253
|
+
}
|
|
254
|
+
if (generate !== undefined) {
|
|
255
|
+
warnOnce(`${label(page)}: generate only works in a [param].md template, such as site/blog/tags/[tag].md`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// Output files taken so far, with the URL that writes each. A later page that would write
|
|
259
|
+
// one is skipped: /tags/ and /tags/index both write tags/index.html.
|
|
260
|
+
const outputFileOf = (url) => join(sep, getPageOutputFile(url)).replace(/\\/g, '/');
|
|
261
|
+
const taken = new Map();
|
|
262
|
+
for (const page of pages) {
|
|
263
|
+
const file = outputFileOf(page.url);
|
|
264
|
+
if (!taken.has(file)) {
|
|
265
|
+
taken.set(file, page.url);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const claim = (url, what) => {
|
|
269
|
+
const file = outputFileOf(url);
|
|
270
|
+
const owner = taken.get(file);
|
|
271
|
+
if (owner === url) {
|
|
272
|
+
warnOnce(`${what} would use the URL ${url}, which another page already has; it is skipped`);
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
if (owner !== undefined) {
|
|
276
|
+
warnOnce(`${what} would use the URL ${url}, which writes the same file as ${owner} (${file.slice(1)}); it is skipped`);
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
taken.set(file, url);
|
|
280
|
+
return true;
|
|
281
|
+
};
|
|
282
|
+
// Pages from collections.generate, grouped by the template they name
|
|
283
|
+
const entriesByTemplate = new Map();
|
|
284
|
+
for (const entry of await runGenerateHook(config, pages, logger)) {
|
|
285
|
+
const template = normalizeTemplatePath(entry.template);
|
|
286
|
+
const known = templates.some((candidate) => candidate.path === template);
|
|
287
|
+
if (typeof entry.url !== 'string' || !entry.url.startsWith('/')) {
|
|
288
|
+
warnOnce(`collections.generate: entry with url ${JSON.stringify(entry.url)} needs a URL starting with "/"; it is skipped`);
|
|
289
|
+
}
|
|
290
|
+
else if (!known) {
|
|
291
|
+
warnOnce(`collections.generate: ${entry.url} names the template ${JSON.stringify(entry.template)}, which is not a [param].md file in the source directory; it is skipped`);
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
const list = entriesByTemplate.get(template) ?? [];
|
|
295
|
+
list.push(entry);
|
|
296
|
+
entriesByTemplate.set(template, list);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
const generatedPages = [];
|
|
300
|
+
for (const { page: template, param, path } of templates) {
|
|
301
|
+
const fm = template.frontMatter;
|
|
302
|
+
const generate = fm.generate && typeof fm.generate === 'object' && !Array.isArray(fm.generate)
|
|
303
|
+
? fm.generate
|
|
304
|
+
: undefined;
|
|
305
|
+
const from = typeof generate?.from === 'string' ? generate.from.trim() : '';
|
|
306
|
+
const entries = entriesByTemplate.get(path) ?? [];
|
|
307
|
+
if (fm.generate !== undefined && !generate) {
|
|
308
|
+
warnOnce(`${path}: generate must be a mapping such as { from: tags }`);
|
|
309
|
+
}
|
|
310
|
+
if (fm.paginate !== undefined) {
|
|
311
|
+
warnOnce(`${path}: use generate.paginate to split generated pages; paginate is ignored here`);
|
|
312
|
+
}
|
|
313
|
+
if (!from && entries.length === 0) {
|
|
314
|
+
warnOnce(`${path}: set generate.from (such as "from: tags") or return pages for it from collections.generate; it generates no pages`);
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
// The template reads the collection its front matter names, or the one its folder is in
|
|
318
|
+
const collectionPath = resolveCollectionPath({ ...template, url: template.slug }, pages);
|
|
319
|
+
const pageUrl = createUrlBuilder(template, param, () => warnOnce(`${path}: permalink must contain [${param}] to give each page its own URL; it is ignored`));
|
|
320
|
+
const groups = [];
|
|
321
|
+
if (from) {
|
|
322
|
+
const collection = collectionPath !== undefined ? collections.byPath.get(collectionPath) : undefined;
|
|
323
|
+
if (!collection) {
|
|
324
|
+
warnOnce(`${path}: generate.from needs a collection, but the template is in none; set collection in its front matter, such as "collection: /blog"`);
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
const found = groupByField(collection.recentPages, from, (value) => warnOnce(`${path}: "${value}" has no Latin letters or digits to use in a URL; it gets no page`), (key, kept, merged) => warnOnce(`${path}: "${merged}" and "${kept}" both become the key "${key}"; their pages are listed together under "${kept}"`));
|
|
328
|
+
for (const group of found) {
|
|
329
|
+
groups.push({ ...group, url: pageUrl(group.key) });
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
for (const entry of entries) {
|
|
334
|
+
const key = typeof entry.key === 'string' && entry.key ? entry.key : lastSegment(entry.url);
|
|
335
|
+
groups.push({
|
|
336
|
+
key,
|
|
337
|
+
label: typeof entry.label === 'string' && entry.label ? entry.label : key,
|
|
338
|
+
items: Array.isArray(entry.items) ? entry.items : [],
|
|
339
|
+
url: entry.url,
|
|
340
|
+
...(entry.data !== undefined && { data: entry.data }),
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
const paginate = parsePaginate(generate?.paginate, (message) => warnOnce(`${path}: generate.${message}`));
|
|
344
|
+
for (const group of groups) {
|
|
345
|
+
if (!claim(group.url, `${path} for "${group.label}"`)) {
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
const generated = {
|
|
349
|
+
key: group.key,
|
|
350
|
+
label: group.label,
|
|
351
|
+
items: group.items,
|
|
352
|
+
template: path,
|
|
353
|
+
...(group.data !== undefined && { data: group.data }),
|
|
354
|
+
};
|
|
355
|
+
const frontMatter = substituteFrontMatter(fm, param, group.label);
|
|
356
|
+
if (collectionPath !== undefined) {
|
|
357
|
+
frontMatter.collection = collectionPath;
|
|
358
|
+
}
|
|
359
|
+
const page = {
|
|
360
|
+
// The template's slug with the key in place of [param]: /tags/[tag] → /tags/css
|
|
361
|
+
slug: `${template.slug.slice(0, template.slug.lastIndexOf('/') + 1)}${group.key}`,
|
|
362
|
+
url: group.url,
|
|
363
|
+
sourcePath: template.sourcePath,
|
|
364
|
+
frontMatter,
|
|
365
|
+
content: template.content,
|
|
366
|
+
...(template.publishedAt && { publishedAt: template.publishedAt }),
|
|
367
|
+
generated,
|
|
368
|
+
};
|
|
369
|
+
generatedPages.push(page);
|
|
370
|
+
if (paginate) {
|
|
371
|
+
generatedPages.push(...paginatePage(page, group.items, paginate, claim, path));
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
// Listings with paginate: index pages, or pages with a collection in their front matter
|
|
376
|
+
const paginationPages = [];
|
|
377
|
+
for (const page of pages) {
|
|
378
|
+
if (page.frontMatter.paginate === undefined) {
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
const where = label(page);
|
|
382
|
+
const settings = parsePaginate(page.frontMatter.paginate, (message) => warnOnce(`${where}: ${message}`));
|
|
383
|
+
if (!settings) {
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
const collectionPath = resolveCollectionPath(page, pages);
|
|
387
|
+
const collection = collectionPath !== undefined ? collections.byPath.get(collectionPath) : undefined;
|
|
388
|
+
if (!collection) {
|
|
389
|
+
warnOnce(`${where}: paginate needs a collection, but the page has none; it is not paginated`);
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
paginationPages.push(...paginatePage(page, collection.recentPages, settings, claim, where, collectionPath));
|
|
393
|
+
}
|
|
394
|
+
return [...pages, ...paginationPages, ...generatedPages];
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Sets the first page's pagination data and creates the pages after it.
|
|
398
|
+
*
|
|
399
|
+
* @param page - The first page, which keeps its URL
|
|
400
|
+
* @param items - Everything the listing shows, in order
|
|
401
|
+
* @param settings - Page size and URL segment
|
|
402
|
+
* @param claim - Reserves a URL, or reports that it is taken
|
|
403
|
+
* @param where - Source label for warnings
|
|
404
|
+
* @param collectionPath - Collection the later pages read; generated pages carry their own
|
|
405
|
+
* @returns The pages after the first
|
|
406
|
+
*/
|
|
407
|
+
function paginatePage(page, items, settings, claim, where, collectionPath) {
|
|
408
|
+
const [first, ...rest] = paginateItems(page.url, items, settings);
|
|
409
|
+
page.pagination = first;
|
|
410
|
+
const later = [];
|
|
411
|
+
for (const pagination of rest) {
|
|
412
|
+
const url = pagination.urls[pagination.pageNumber - 1];
|
|
413
|
+
if (!claim(url, `Page ${pagination.pageNumber} of ${where}`)) {
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
const frontMatter = copyValue(page.frontMatter);
|
|
417
|
+
if (collectionPath !== undefined) {
|
|
418
|
+
frontMatter.collection = collectionPath;
|
|
419
|
+
}
|
|
420
|
+
later.push({
|
|
421
|
+
...page,
|
|
422
|
+
slug: url.length > 1 && url.endsWith('/') ? url.slice(0, -1) : url,
|
|
423
|
+
url,
|
|
424
|
+
frontMatter,
|
|
425
|
+
pagination,
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
return later;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Returns a function that gives the URL of a template's page for a key: the template's URL
|
|
432
|
+
* with `[param]` replaced, or its `permalink` with `[param]` replaced.
|
|
433
|
+
*/
|
|
434
|
+
function createUrlBuilder(template, param, onBadPermalink) {
|
|
435
|
+
const token = `[${param}]`;
|
|
436
|
+
const permalink = template.frontMatter.permalink;
|
|
437
|
+
if (typeof permalink === 'string') {
|
|
438
|
+
if (permalink.includes(token)) {
|
|
439
|
+
return (key) => permalink.split(token).join(key);
|
|
440
|
+
}
|
|
441
|
+
onBadPermalink();
|
|
442
|
+
}
|
|
443
|
+
// The template's file-based URL ends with the token: /blog/tags/[tag]
|
|
444
|
+
const base = template.slug.slice(0, -token.length);
|
|
445
|
+
return (key) => `${base}${key}`;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Runs `collections.generate`.
|
|
449
|
+
*/
|
|
450
|
+
async function runGenerateHook(config, pages, logger) {
|
|
451
|
+
const generate = config.collections?.generate;
|
|
452
|
+
if (typeof generate !== 'function') {
|
|
453
|
+
return [];
|
|
454
|
+
}
|
|
455
|
+
let entries;
|
|
456
|
+
try {
|
|
457
|
+
entries = await generate({ config, pages });
|
|
458
|
+
}
|
|
459
|
+
catch (error) {
|
|
460
|
+
throw new Error(`collections.generate failed: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
461
|
+
}
|
|
462
|
+
if (!Array.isArray(entries)) {
|
|
463
|
+
logger.warning('collections.generate must return an array of pages; its result is ignored');
|
|
464
|
+
return [];
|
|
465
|
+
}
|
|
466
|
+
return entries.filter((entry) => {
|
|
467
|
+
if (entry && typeof entry === 'object' && typeof entry.template === 'string') {
|
|
468
|
+
return true;
|
|
469
|
+
}
|
|
470
|
+
logger.warning('collections.generate: every entry needs a url and a template; an entry is skipped');
|
|
471
|
+
return false;
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Normalizes a template path from `collections.generate` to the form expansion uses:
|
|
476
|
+
* relative to the source directory, with forward slashes and the `.md` extension.
|
|
477
|
+
*/
|
|
478
|
+
function normalizeTemplatePath(template) {
|
|
479
|
+
const path = template.replace(/\\/g, '/').replace(/^\.\//, '').replace(/^\/+/, '');
|
|
480
|
+
return path.endsWith('.md') ? path : `${path}.md`;
|
|
481
|
+
}
|
|
482
|
+
function lastSegment(url) {
|
|
483
|
+
return url.split('/').filter(Boolean).at(-1) ?? '';
|
|
484
|
+
}
|
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
import type { PageModel, CacheEntry, StatiConfig } from '../../types/index.js';
|
|
2
|
+
import type { PageReads } from '../collections.js';
|
|
3
|
+
/**
|
|
4
|
+
* What a render discovered: the source images a page displays (`assetDeps`), the generated
|
|
5
|
+
* images it references (`images`) and the shared data it read (`reads`).
|
|
6
|
+
*/
|
|
7
|
+
export interface RenderedAssets {
|
|
8
|
+
/** Absolute paths of files whose content affects the page, such as source images */
|
|
9
|
+
assetDeps: readonly string[];
|
|
10
|
+
/** Generated image files the page references, relative to the output directory */
|
|
11
|
+
images: readonly string[];
|
|
12
|
+
/** Whether the render read the collection and the navigation tree */
|
|
13
|
+
reads?: PageReads | undefined;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Whether a cache entry records what its page read while rendering. Entries written before
|
|
17
|
+
* Stati recorded it don't, and their page must be rebuilt once: whether it depends on its
|
|
18
|
+
* collection or the navigation tree is unknown, and assuming it doesn't could keep stale
|
|
19
|
+
* listings or prev/next links.
|
|
20
|
+
*
|
|
21
|
+
* @param entry - The cache entry
|
|
22
|
+
* @returns True when `readsCollection` and `readsNav` are both recorded
|
|
23
|
+
*/
|
|
24
|
+
export declare function hasRecordedReads(entry: CacheEntry): boolean;
|
|
2
25
|
/**
|
|
3
26
|
* Determines if a page should be rebuilt based on ISG logic.
|
|
4
27
|
* Checks content changes, dependency changes, TTL expiration, and freeze status.
|
|
@@ -29,6 +52,7 @@ export declare function shouldRebuildPage(page: PageModel, entry: CacheEntry | u
|
|
|
29
52
|
* @param allPages - All pages in the site, used to resolve the same layout as rendering
|
|
30
53
|
* @param renderedAt - When the page was rendered
|
|
31
54
|
* @param renderInputsHash - Optional hash of asset URLs and injection settings
|
|
55
|
+
* @param rendered - Files the render discovered, such as images
|
|
32
56
|
* @returns New cache entry
|
|
33
57
|
*
|
|
34
58
|
* @example
|
|
@@ -36,7 +60,7 @@ export declare function shouldRebuildPage(page: PageModel, entry: CacheEntry | u
|
|
|
36
60
|
* const entry = await createCacheEntry(page, config, pages, new Date());
|
|
37
61
|
* ```
|
|
38
62
|
*/
|
|
39
|
-
export declare function createCacheEntry(page: PageModel, config: StatiConfig, allPages: PageModel[], renderedAt: Date, renderInputsHash?: string): Promise<CacheEntry>;
|
|
63
|
+
export declare function createCacheEntry(page: PageModel, config: StatiConfig, allPages: PageModel[], renderedAt: Date, renderInputsHash?: string, rendered?: RenderedAssets): Promise<CacheEntry>;
|
|
40
64
|
/**
|
|
41
65
|
* Updates an existing cache entry with new information after rebuilding.
|
|
42
66
|
* In dev mode, this is optimized to reuse the existing deps array since
|
|
@@ -49,6 +73,7 @@ export declare function createCacheEntry(page: PageModel, config: StatiConfig, a
|
|
|
49
73
|
* @param renderedAt - When the page was rendered
|
|
50
74
|
* @param fastUpdate - If true, skip expensive dep tracking (dev mode optimization)
|
|
51
75
|
* @param renderInputsHash - Optional hash of asset URLs and injection settings
|
|
76
|
+
* @param rendered - Files the render discovered, such as images
|
|
52
77
|
* @returns Updated cache entry
|
|
53
78
|
*
|
|
54
79
|
* @example
|
|
@@ -56,5 +81,5 @@ export declare function createCacheEntry(page: PageModel, config: StatiConfig, a
|
|
|
56
81
|
* const updatedEntry = await updateCacheEntry(existingEntry, page, config, pages, new Date());
|
|
57
82
|
* ```
|
|
58
83
|
*/
|
|
59
|
-
export declare function updateCacheEntry(entry: CacheEntry, page: PageModel, config: StatiConfig, allPages: PageModel[], renderedAt: Date, fastUpdate?: boolean, renderInputsHash?: string): Promise<CacheEntry>;
|
|
84
|
+
export declare function updateCacheEntry(entry: CacheEntry, page: PageModel, config: StatiConfig, allPages: PageModel[], renderedAt: Date, fastUpdate?: boolean, renderInputsHash?: string, rendered?: RenderedAssets): Promise<CacheEntry>;
|
|
60
85
|
//# sourceMappingURL=builder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../src/core/isg/builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../src/core/isg/builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAsFnD;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,oFAAoF;IACpF,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,kFAAkF;IAClF,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,qEAAqE;IACrE,KAAK,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;CAC/B;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAE3D;AAuDD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,UAAU,GAAG,SAAS,EAC7B,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,SAAS,EAAE,EACrB,GAAG,EAAE,IAAI,EACT,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CAAC,OAAO,CAAC,CAuKlB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,SAAS,EAAE,EACrB,UAAU,EAAE,IAAI,EAChB,gBAAgB,CAAC,EAAE,MAAM,EACzB,QAAQ,CAAC,EAAE,cAAc,GACxB,OAAO,CAAC,UAAU,CAAC,CAmFrB;AAkDD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,UAAU,EACjB,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,SAAS,EAAE,EACrB,UAAU,EAAE,IAAI,EAChB,UAAU,UAAQ,EAClB,gBAAgB,CAAC,EAAE,MAAM,EACzB,QAAQ,CAAC,EAAE,cAAc,GACxB,OAAO,CAAC,UAAU,CAAC,CAiErB"}
|