@johnhenry/sitefile 0.0.0-stage → 0.0.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/CHANGELOG.md +48 -0
- package/LICENSE +21 -0
- package/README.md +475 -2
- package/lib/src/archive-writers.d.ts +31 -0
- package/lib/src/archive-writers.js +197 -0
- package/lib/src/attest.d.ts +126 -0
- package/lib/src/attest.js +220 -0
- package/lib/src/bake.d.ts +74 -0
- package/lib/src/bake.js +372 -0
- package/lib/src/base-image.d.ts +76 -0
- package/lib/src/base-image.js +138 -0
- package/lib/src/build-args.d.ts +26 -0
- package/lib/src/build-args.js +164 -0
- package/lib/src/cache-limit.d.ts +54 -0
- package/lib/src/cache-limit.js +239 -0
- package/lib/src/casefold-data.d.ts +2 -0
- package/lib/src/casefold-data.js +217 -0
- package/lib/src/cbor.d.ts +39 -0
- package/lib/src/cbor.js +174 -0
- package/lib/src/checklinks.d.ts +42 -0
- package/lib/src/checklinks.js +118 -0
- package/lib/src/cli/bake.d.ts +2 -0
- package/lib/src/cli/bake.js +179 -0
- package/lib/src/cli/build-image.d.ts +21 -0
- package/lib/src/cli/build-image.js +42 -0
- package/lib/src/cli/cache.d.ts +8 -0
- package/lib/src/cli/cache.js +109 -0
- package/lib/src/cli/common.d.ts +29 -0
- package/lib/src/cli/common.js +100 -0
- package/lib/src/cli/git-context.d.ts +18 -0
- package/lib/src/cli/git-context.js +48 -0
- package/lib/src/cli/images.d.ts +6 -0
- package/lib/src/cli/images.js +285 -0
- package/lib/src/cli/index.d.ts +10 -0
- package/lib/src/cli/index.js +95 -0
- package/lib/src/cli/outdated.d.ts +5 -0
- package/lib/src/cli/outdated.js +94 -0
- package/lib/src/cli/registry.d.ts +2 -0
- package/lib/src/cli/registry.js +122 -0
- package/lib/src/cli/serve-worker.d.ts +2 -0
- package/lib/src/cli/serve-worker.js +42 -0
- package/lib/src/cli/servers.d.ts +15 -0
- package/lib/src/cli/servers.js +451 -0
- package/lib/src/cli/vendor.d.ts +2 -0
- package/lib/src/cli/vendor.js +92 -0
- package/lib/src/cli/watch.d.ts +26 -0
- package/lib/src/cli/watch.js +81 -0
- package/lib/src/cli.d.ts +12 -0
- package/lib/src/cli.js +486 -0
- package/lib/src/csv.d.ts +27 -0
- package/lib/src/csv.js +117 -0
- package/lib/src/deflate.d.ts +76 -0
- package/lib/src/deflate.js +604 -0
- package/lib/src/digest.d.ts +3 -0
- package/lib/src/digest.js +7 -0
- package/lib/src/errors.d.ts +34 -0
- package/lib/src/errors.js +20 -0
- package/lib/src/executor.d.ts +386 -0
- package/lib/src/executor.js +2193 -0
- package/lib/src/explain.d.ts +64 -0
- package/lib/src/explain.js +445 -0
- package/lib/src/export-formats.d.ts +16 -0
- package/lib/src/export-formats.js +52 -0
- package/lib/src/exporter.d.ts +103 -0
- package/lib/src/exporter.js +676 -0
- package/lib/src/fingerprint.d.ts +40 -0
- package/lib/src/fingerprint.js +168 -0
- package/lib/src/frontmatter.d.ts +22 -0
- package/lib/src/frontmatter.js +45 -0
- package/lib/src/index.d.ts +12 -0
- package/lib/src/index.js +12 -0
- package/lib/src/language/ast.d.ts +353 -0
- package/lib/src/language/ast.js +57 -0
- package/lib/src/language/parser.d.ts +3 -0
- package/lib/src/language/parser.js +612 -0
- package/lib/src/language/scanner.d.ts +110 -0
- package/lib/src/language/scanner.js +449 -0
- package/lib/src/language/validate.d.ts +13 -0
- package/lib/src/language/validate.js +367 -0
- package/lib/src/links.d.ts +79 -0
- package/lib/src/links.js +583 -0
- package/lib/src/lint.d.ts +10 -0
- package/lib/src/lint.js +223 -0
- package/lib/src/markdown.d.ts +29 -0
- package/lib/src/markdown.js +612 -0
- package/lib/src/media.d.ts +82 -0
- package/lib/src/media.js +650 -0
- package/lib/src/memo.d.ts +57 -0
- package/lib/src/memo.js +93 -0
- package/lib/src/oci.d.ts +178 -0
- package/lib/src/oci.js +380 -0
- package/lib/src/outdated.d.ts +46 -0
- package/lib/src/outdated.js +195 -0
- package/lib/src/pages.d.ts +10 -0
- package/lib/src/pages.js +54 -0
- package/lib/src/paths.d.ts +39 -0
- package/lib/src/paths.js +101 -0
- package/lib/src/planner.d.ts +297 -0
- package/lib/src/planner.js +410 -0
- package/lib/src/plugins/cache.d.ts +70 -0
- package/lib/src/plugins/cache.js +226 -0
- package/lib/src/plugins/exec.d.ts +51 -0
- package/lib/src/plugins/exec.js +144 -0
- package/lib/src/plugins/host.d.ts +75 -0
- package/lib/src/plugins/host.js +277 -0
- package/lib/src/plugins/wasm.d.ts +23 -0
- package/lib/src/plugins/wasm.js +249 -0
- package/lib/src/profile.d.ts +42 -0
- package/lib/src/profile.js +68 -0
- package/lib/src/ref.d.ts +40 -0
- package/lib/src/ref.js +79 -0
- package/lib/src/registry-auth.d.ts +32 -0
- package/lib/src/registry-auth.js +151 -0
- package/lib/src/registry-cache.d.ts +71 -0
- package/lib/src/registry-cache.js +333 -0
- package/lib/src/registry-ops.d.ts +51 -0
- package/lib/src/registry-ops.js +248 -0
- package/lib/src/registry.d.ts +109 -0
- package/lib/src/registry.js +505 -0
- package/lib/src/render.d.ts +134 -0
- package/lib/src/render.js +576 -0
- package/lib/src/resources/archive.d.ts +11 -0
- package/lib/src/resources/archive.js +306 -0
- package/lib/src/resources/bundle-data.d.ts +16 -0
- package/lib/src/resources/bundle-data.js +50 -0
- package/lib/src/resources/convert.d.ts +12 -0
- package/lib/src/resources/convert.js +63 -0
- package/lib/src/resources/documents.d.ts +35 -0
- package/lib/src/resources/documents.js +122 -0
- package/lib/src/resources/git.d.ts +103 -0
- package/lib/src/resources/git.js +720 -0
- package/lib/src/resources/https.d.ts +40 -0
- package/lib/src/resources/https.js +256 -0
- package/lib/src/resources/ignore.d.ts +33 -0
- package/lib/src/resources/ignore.js +119 -0
- package/lib/src/resources/local.d.ts +64 -0
- package/lib/src/resources/local.js +248 -0
- package/lib/src/resources/lockfile.d.ts +52 -0
- package/lib/src/resources/lockfile.js +172 -0
- package/lib/src/resources/netpolicy.d.ts +6 -0
- package/lib/src/resources/netpolicy.js +82 -0
- package/lib/src/resources/types.d.ts +63 -0
- package/lib/src/resources/types.js +13 -0
- package/lib/src/resources/vendor.d.ts +94 -0
- package/lib/src/resources/vendor.js +296 -0
- package/lib/src/resources/wbn-reader.d.ts +44 -0
- package/lib/src/resources/wbn-reader.js +302 -0
- package/lib/src/schema.d.ts +25 -0
- package/lib/src/schema.js +169 -0
- package/lib/src/secrets.d.ts +21 -0
- package/lib/src/secrets.js +103 -0
- package/lib/src/serve-rules.d.ts +29 -0
- package/lib/src/serve-rules.js +122 -0
- package/lib/src/server.d.ts +45 -0
- package/lib/src/server.js +246 -0
- package/lib/src/servers.d.ts +71 -0
- package/lib/src/servers.js +139 -0
- package/lib/src/site.d.ts +60 -0
- package/lib/src/site.js +169 -0
- package/lib/src/store.d.ts +151 -0
- package/lib/src/store.js +596 -0
- package/lib/src/tree.d.ts +50 -0
- package/lib/src/tree.js +134 -0
- package/lib/src/values.d.ts +7 -0
- package/lib/src/values.js +37 -0
- package/lib/src/vendor.d.ts +19 -0
- package/lib/src/vendor.js +145 -0
- package/lib/src/watch.d.ts +44 -0
- package/lib/src/watch.js +137 -0
- package/lib/src/wbn.d.ts +5 -0
- package/lib/src/wbn.js +147 -0
- package/lib/src/yaml.d.ts +34 -0
- package/lib/src/yaml.js +562 -0
- package/package.json +58 -4
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { SitefileError } from './errors.js';
|
|
4
|
+
import { parseYaml } from './yaml.js';
|
|
5
|
+
const KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
6
|
+
/**
|
|
7
|
+
* Read build-arg values from a file, by extension:
|
|
8
|
+
*
|
|
9
|
+
* - `.json`: a flat object, `{"TITLE": "Docs", "PORT": 8080}`
|
|
10
|
+
* - `.yaml` / `.yml`: a flat mapping, `TITLE: Docs`
|
|
11
|
+
* - `.env` (or a file named `.env`, `.env.*`, `*.env`): `KEY=value` lines
|
|
12
|
+
*
|
|
13
|
+
* Values must be strings, numbers or booleans; they become strings and are
|
|
14
|
+
* checked against each ARG's declared type later, like `--build-arg`.
|
|
15
|
+
* `.env` files are parsed, never executed: no `$VAR` or `$(…)` expansion.
|
|
16
|
+
*/
|
|
17
|
+
export async function loadBuildArgFile(file) {
|
|
18
|
+
const kind = buildArgFileKind(file); // an unknown extension is a usage error, before any IO
|
|
19
|
+
let text;
|
|
20
|
+
try {
|
|
21
|
+
text = await readFile(file, 'utf8');
|
|
22
|
+
}
|
|
23
|
+
catch (e) {
|
|
24
|
+
throw new SitefileError('E_NOT_FOUND', `cannot read build-arg file '${file}'`, undefined, { cause: e });
|
|
25
|
+
}
|
|
26
|
+
const label = path.relative(process.cwd(), path.resolve(file)) || file;
|
|
27
|
+
if (kind === 'env')
|
|
28
|
+
return parseEnvFile(text, label);
|
|
29
|
+
let value;
|
|
30
|
+
if (kind === 'json') {
|
|
31
|
+
try {
|
|
32
|
+
value = JSON.parse(text.replace(/^/, ''));
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
throw new SitefileError('E_DATA', `${label} is not valid JSON: ${e.message}`, undefined, { cause: e });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
value = parseYaml(text, label);
|
|
40
|
+
}
|
|
41
|
+
return flatScalars(value, label);
|
|
42
|
+
}
|
|
43
|
+
export function buildArgFileKind(file) {
|
|
44
|
+
const base = path.basename(file).toLowerCase();
|
|
45
|
+
if (base.endsWith('.json'))
|
|
46
|
+
return 'json';
|
|
47
|
+
if (base.endsWith('.yaml') || base.endsWith('.yml'))
|
|
48
|
+
return 'yaml';
|
|
49
|
+
if (base === '.env' || base.startsWith('.env.') || base.endsWith('.env'))
|
|
50
|
+
return 'env';
|
|
51
|
+
throw new SitefileError('E_USAGE', `--build-arg-file '${file}': unknown format (use a .json, .yaml, .yml or .env file)`);
|
|
52
|
+
}
|
|
53
|
+
function flatScalars(value, label) {
|
|
54
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
55
|
+
throw new SitefileError('E_DATA', `${label}: build-arg files must contain a mapping of NAME: value`);
|
|
56
|
+
}
|
|
57
|
+
const out = Object.create(null);
|
|
58
|
+
for (const [key, v] of Object.entries(value)) {
|
|
59
|
+
if (!KEY_RE.test(key))
|
|
60
|
+
throw new SitefileError('E_DATA', `${label}: '${key}' is not a valid ARG name`);
|
|
61
|
+
if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean')
|
|
62
|
+
out[key] = String(v);
|
|
63
|
+
else {
|
|
64
|
+
throw new SitefileError('E_DATA', `${label}: ${key} must be a string, number or boolean (ARGs can't hold ${v === null ? 'null' : Array.isArray(v) ? 'lists' : 'objects'})`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* `.env` syntax: one `KEY=value` per line, optional `export ` prefix, `#`
|
|
71
|
+
* comment lines and blank lines. Unquoted values are trimmed and a ` #` starts
|
|
72
|
+
* a comment; `'single'` quotes are literal; `"double"` quotes understand
|
|
73
|
+
* `\n \t \r \" \\` and may span lines. Nothing is expanded or executed.
|
|
74
|
+
*/
|
|
75
|
+
export function parseEnvFile(text, label) {
|
|
76
|
+
const out = Object.create(null);
|
|
77
|
+
const src = text.replace(/^/, '').replace(/\r\n?/g, '\n');
|
|
78
|
+
const err = (line, msg) => new SitefileError('E_DATA', msg, { file: label, line, column: 1 });
|
|
79
|
+
let i = 0;
|
|
80
|
+
let line = 1;
|
|
81
|
+
while (i < src.length) {
|
|
82
|
+
const nl = src.indexOf('\n', i);
|
|
83
|
+
const end = nl === -1 ? src.length : nl;
|
|
84
|
+
const raw = src.slice(i, end);
|
|
85
|
+
const trimmed = raw.trim();
|
|
86
|
+
const startLine = line;
|
|
87
|
+
if (trimmed === '' || trimmed.startsWith('#')) {
|
|
88
|
+
i = end + 1;
|
|
89
|
+
line++;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const m = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*/.exec(raw);
|
|
93
|
+
if (!m)
|
|
94
|
+
throw err(line, `expected KEY=value, got '${trimmed}'`);
|
|
95
|
+
let j = i + m[0].length;
|
|
96
|
+
let value;
|
|
97
|
+
const q = src[j];
|
|
98
|
+
if (q === "'" || q === '"') {
|
|
99
|
+
j++;
|
|
100
|
+
value = '';
|
|
101
|
+
let closed = false;
|
|
102
|
+
while (j < src.length) {
|
|
103
|
+
const c = src[j];
|
|
104
|
+
if (c === q) {
|
|
105
|
+
closed = true;
|
|
106
|
+
j++;
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
if (c === '\n')
|
|
110
|
+
line++;
|
|
111
|
+
if (q === '"' && c === '\\' && j + 1 < src.length) {
|
|
112
|
+
const n = src[j + 1];
|
|
113
|
+
value += n === 'n' ? '\n' : n === 't' ? '\t' : n === 'r' ? '\r' : n;
|
|
114
|
+
j += 2;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
value += c;
|
|
118
|
+
j++;
|
|
119
|
+
}
|
|
120
|
+
if (!closed)
|
|
121
|
+
throw err(startLine, `unterminated ${q} quote for ${m[1]}`);
|
|
122
|
+
const restEnd = src.indexOf('\n', j) === -1 ? src.length : src.indexOf('\n', j);
|
|
123
|
+
const rest = src.slice(j, restEnd).trim();
|
|
124
|
+
if (rest !== '' && !rest.startsWith('#'))
|
|
125
|
+
throw err(line, `unexpected text after the quoted value of ${m[1]}`);
|
|
126
|
+
i = restEnd + 1;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
value = src.slice(j, end).replace(/\s+#.*$/, '').trim();
|
|
130
|
+
i = end + 1;
|
|
131
|
+
}
|
|
132
|
+
line++;
|
|
133
|
+
out[m[1]] = value;
|
|
134
|
+
}
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* The CLI's build args: `--build-arg-file` files in order (later files win), then
|
|
139
|
+
* `--build-arg NAME=value` (or `NAME`, read from the environment), which win over files.
|
|
140
|
+
* Malformed flags are E_USAGE errors.
|
|
141
|
+
*/
|
|
142
|
+
export async function collectBuildArgs(files, flags, env = process.env) {
|
|
143
|
+
const out = {};
|
|
144
|
+
for (const file of files)
|
|
145
|
+
Object.assign(out, await loadBuildArgFile(file));
|
|
146
|
+
for (const kv of flags) {
|
|
147
|
+
const eq = kv.indexOf('=');
|
|
148
|
+
if (eq === -1) {
|
|
149
|
+
// --build-arg NAME: take the value from the environment, as Docker does.
|
|
150
|
+
if (!KEY_RE.test(kv))
|
|
151
|
+
throw new SitefileError('E_USAGE', `--build-arg expects NAME=value or NAME, got '${kv}'`);
|
|
152
|
+
const v = env[kv];
|
|
153
|
+
if (v === undefined)
|
|
154
|
+
throw new SitefileError('E_USAGE', `--build-arg ${kv}: environment variable ${kv} is not set`);
|
|
155
|
+
out[kv] = v;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (eq === 0)
|
|
159
|
+
throw new SitefileError('E_USAGE', `--build-arg expects NAME=value, got '${kv}'`);
|
|
160
|
+
out[kv.slice(0, eq)] = kv.slice(eq + 1);
|
|
161
|
+
}
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=build-args.js.map
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Size limit for what Sitefile keeps under $SITEFILE_HOME (docs/CLI.md, "Cache size limit").
|
|
3
|
+
*
|
|
4
|
+
* EVICTABLE data is the TRANSFORM result cache (cache/transform), the compiled wasm module cache
|
|
5
|
+
* (cache/wasm, written by the Rust build only) and, in the image store, untagged images and blobs
|
|
6
|
+
* no tagged image uses. Tagged images and every blob they reference are never evicted.
|
|
7
|
+
*
|
|
8
|
+
* After a build, when the evictable bytes exceed the limit ($SITEFILE_CACHE_MAX, default 1 GiB,
|
|
9
|
+
* 0 = no limit), the least recently used items are deleted until it fits. Recency is the file's
|
|
10
|
+
* mtime, refreshed on every cache hit (atime is often disabled): a TRANSFORM entry, a .cwasm file,
|
|
11
|
+
* an untagged image's manifest blob. Nothing touched within the grace period is deleted (10 minutes
|
|
12
|
+
* for the pure caches, 1 hour for the image store and for temp files), so a concurrent build never
|
|
13
|
+
* loses what it is writing or has just written; writes are temp file + rename, and the store part
|
|
14
|
+
* runs under the store lock. The check is one directory listing per cache when under the limit.
|
|
15
|
+
*
|
|
16
|
+
* Kept byte-for-byte in step with rust/src/cache_limit.rs.
|
|
17
|
+
*/
|
|
18
|
+
export declare const CACHE_MAX_ENV = "SITEFILE_CACHE_MAX";
|
|
19
|
+
export declare const DEFAULT_CACHE_MAX: number;
|
|
20
|
+
/** Files touched more recently than this are never evicted from the pure caches. */
|
|
21
|
+
export declare const CACHE_GRACE_MS: number;
|
|
22
|
+
/** Temp files and image-store data get a longer grace (pulls and builds can take a while). */
|
|
23
|
+
export declare const LONG_GRACE_MS: number;
|
|
24
|
+
/** `1048576`, `512K`, `512M`, `1.5G`, `2GiB`, `1T` (binary units, case-insensitive); `0` = no limit. */
|
|
25
|
+
export declare function parseSize(raw: string): number | undefined;
|
|
26
|
+
/** A limit as it is shown: `unlimited`, `1GiB`, `512MiB`, `100KiB`, else bytes (`1000B`). */
|
|
27
|
+
export declare function formatLimit(bytes: number): string;
|
|
28
|
+
/** The limit from $SITEFILE_CACHE_MAX (unset or empty: the default). A bad value warns and uses the default. */
|
|
29
|
+
export declare function cacheLimitFromEnv(env?: NodeJS.ProcessEnv, warn?: (m: string) => void): number;
|
|
30
|
+
export interface CacheUsage {
|
|
31
|
+
readonly name: 'transform' | 'wasm' | 'store' | 'servers';
|
|
32
|
+
readonly path: string;
|
|
33
|
+
/** TRANSFORM entries, .cwasm modules, store blobs, server files. */
|
|
34
|
+
readonly items: number;
|
|
35
|
+
readonly bytes: number;
|
|
36
|
+
/** Bytes the size limit may delete (everything but tagged images' blobs and server state). */
|
|
37
|
+
readonly evictable: number;
|
|
38
|
+
}
|
|
39
|
+
export declare function cachePaths(home: string): Record<CacheUsage['name'], string>;
|
|
40
|
+
/** Sizes per cache under `home` (for `cache du`). */
|
|
41
|
+
export declare function cacheUsage(home: string): Promise<CacheUsage[]>;
|
|
42
|
+
export interface EvictResult {
|
|
43
|
+
/** TRANSFORM entries, modules, images and stray blobs deleted. */
|
|
44
|
+
readonly items: number;
|
|
45
|
+
readonly bytes: number;
|
|
46
|
+
/** Evictable bytes before and after. */
|
|
47
|
+
readonly before: number;
|
|
48
|
+
readonly after: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Delete least recently used evictable data until it fits in `limit` bytes (0: no limit).
|
|
52
|
+
* Cheap when under the limit: one listing per cache directory, no file is read.
|
|
53
|
+
*/
|
|
54
|
+
export declare function enforceCacheLimit(home: string, limit: number, now?: number): Promise<EvictResult>;
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { lstat, readdir, readFile, rm } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { Store } from './store.js';
|
|
4
|
+
/**
|
|
5
|
+
* Size limit for what Sitefile keeps under $SITEFILE_HOME (docs/CLI.md, "Cache size limit").
|
|
6
|
+
*
|
|
7
|
+
* EVICTABLE data is the TRANSFORM result cache (cache/transform), the compiled wasm module cache
|
|
8
|
+
* (cache/wasm, written by the Rust build only) and, in the image store, untagged images and blobs
|
|
9
|
+
* no tagged image uses. Tagged images and every blob they reference are never evicted.
|
|
10
|
+
*
|
|
11
|
+
* After a build, when the evictable bytes exceed the limit ($SITEFILE_CACHE_MAX, default 1 GiB,
|
|
12
|
+
* 0 = no limit), the least recently used items are deleted until it fits. Recency is the file's
|
|
13
|
+
* mtime, refreshed on every cache hit (atime is often disabled): a TRANSFORM entry, a .cwasm file,
|
|
14
|
+
* an untagged image's manifest blob. Nothing touched within the grace period is deleted (10 minutes
|
|
15
|
+
* for the pure caches, 1 hour for the image store and for temp files), so a concurrent build never
|
|
16
|
+
* loses what it is writing or has just written; writes are temp file + rename, and the store part
|
|
17
|
+
* runs under the store lock. The check is one directory listing per cache when under the limit.
|
|
18
|
+
*
|
|
19
|
+
* Kept byte-for-byte in step with rust/src/cache_limit.rs.
|
|
20
|
+
*/
|
|
21
|
+
export const CACHE_MAX_ENV = 'SITEFILE_CACHE_MAX';
|
|
22
|
+
export const DEFAULT_CACHE_MAX = 1024 ** 3;
|
|
23
|
+
/** Files touched more recently than this are never evicted from the pure caches. */
|
|
24
|
+
export const CACHE_GRACE_MS = 10 * 60_000;
|
|
25
|
+
/** Temp files and image-store data get a longer grace (pulls and builds can take a while). */
|
|
26
|
+
export const LONG_GRACE_MS = 60 * 60_000;
|
|
27
|
+
const HEX64 = /^[0-9a-f]{64}$/;
|
|
28
|
+
const UNITS = { '': 1, k: 1024, m: 1024 ** 2, g: 1024 ** 3, t: 1024 ** 4 };
|
|
29
|
+
/** `1048576`, `512K`, `512M`, `1.5G`, `2GiB`, `1T` (binary units, case-insensitive); `0` = no limit. */
|
|
30
|
+
export function parseSize(raw) {
|
|
31
|
+
const m = /^(\d+(?:\.\d+)?)\s*(?:([kmgt])(?:i?b)?|b)?$/i.exec(raw.trim());
|
|
32
|
+
if (!m)
|
|
33
|
+
return undefined;
|
|
34
|
+
const n = Math.floor(Number(m[1]) * (UNITS[(m[2] ?? '').toLowerCase()] ?? 1));
|
|
35
|
+
return Number.isSafeInteger(n) ? n : undefined;
|
|
36
|
+
}
|
|
37
|
+
/** A limit as it is shown: `unlimited`, `1GiB`, `512MiB`, `100KiB`, else bytes (`1000B`). */
|
|
38
|
+
export function formatLimit(bytes) {
|
|
39
|
+
if (bytes === 0)
|
|
40
|
+
return 'unlimited';
|
|
41
|
+
for (const [u, n] of [['TiB', 1024 ** 4], ['GiB', 1024 ** 3], ['MiB', 1024 ** 2], ['KiB', 1024]]) {
|
|
42
|
+
if (bytes % n === 0)
|
|
43
|
+
return `${bytes / n}${u}`;
|
|
44
|
+
}
|
|
45
|
+
return `${bytes}B`;
|
|
46
|
+
}
|
|
47
|
+
/** The limit from $SITEFILE_CACHE_MAX (unset or empty: the default). A bad value warns and uses the default. */
|
|
48
|
+
export function cacheLimitFromEnv(env = process.env, warn = () => { }) {
|
|
49
|
+
const raw = env[CACHE_MAX_ENV];
|
|
50
|
+
if (raw === undefined || raw.trim() === '')
|
|
51
|
+
return DEFAULT_CACHE_MAX;
|
|
52
|
+
const n = parseSize(raw);
|
|
53
|
+
if (n !== undefined)
|
|
54
|
+
return n;
|
|
55
|
+
warn(`${CACHE_MAX_ENV}='${raw}' is not a size (bytes, or a number with K, M, G or T; 0 for no limit); using ${formatLimit(DEFAULT_CACHE_MAX)}`);
|
|
56
|
+
return DEFAULT_CACHE_MAX;
|
|
57
|
+
}
|
|
58
|
+
async function files(dir) {
|
|
59
|
+
const names = await readdir(dir).catch(() => []);
|
|
60
|
+
const out = [];
|
|
61
|
+
for (const name of names.sort()) {
|
|
62
|
+
const file = path.join(dir, name);
|
|
63
|
+
const st = await lstat(file).catch(() => undefined);
|
|
64
|
+
if (st?.isFile())
|
|
65
|
+
out.push({ name, file, size: st.size, mtime: st.mtimeMs });
|
|
66
|
+
}
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
export function cachePaths(home) {
|
|
70
|
+
return {
|
|
71
|
+
transform: path.join(home, 'cache', 'transform'),
|
|
72
|
+
wasm: path.join(home, 'cache', 'wasm'),
|
|
73
|
+
store: path.join(home, 'blobs', 'sha256'),
|
|
74
|
+
servers: path.join(home, 'servers'),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
class Model {
|
|
78
|
+
blobs = new Map();
|
|
79
|
+
roots = [];
|
|
80
|
+
/** Bytes in the model (all evictable). */
|
|
81
|
+
total = 0;
|
|
82
|
+
blob(key, f, grace) {
|
|
83
|
+
this.blobs.set(key, { file: f.file, size: f.size, mtime: f.mtime, grace, refs: 0, gone: false });
|
|
84
|
+
this.total += f.size;
|
|
85
|
+
}
|
|
86
|
+
root(r) {
|
|
87
|
+
this.roots.push(r);
|
|
88
|
+
this.total += r.size;
|
|
89
|
+
for (const k of r.refs) {
|
|
90
|
+
const b = this.blobs.get(k);
|
|
91
|
+
if (b)
|
|
92
|
+
b.refs++;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async function addTransform(m, dir) {
|
|
97
|
+
for (const f of await files(path.join(dir, 'blobs')))
|
|
98
|
+
m.blob(`t:${f.name}`, f, HEX64.test(f.name) ? CACHE_GRACE_MS : LONG_GRACE_MS);
|
|
99
|
+
let entries = 0;
|
|
100
|
+
for (const f of await files(path.join(dir, 'entries'))) {
|
|
101
|
+
if (!f.name.endsWith('.json') || f.name.startsWith('.')) {
|
|
102
|
+
m.blob(`t:entries/${f.name}`, f, LONG_GRACE_MS);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
entries++;
|
|
106
|
+
let refs = [];
|
|
107
|
+
try {
|
|
108
|
+
const j = JSON.parse(await readFile(f.file, 'utf8'));
|
|
109
|
+
if (Array.isArray(j.files))
|
|
110
|
+
refs = j.files.flatMap((x) => (Array.isArray(x) && typeof x[1] === 'string' && HEX64.test(x[1]) ? [`t:${x[1]}`] : []));
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
/* damaged: an entry with no blobs */
|
|
114
|
+
}
|
|
115
|
+
m.root({ key: `t:entries/${f.name}`, file: f.file, size: f.size, mtime: f.mtime, grace: CACHE_GRACE_MS, refs: [...new Set(refs)] });
|
|
116
|
+
}
|
|
117
|
+
return entries;
|
|
118
|
+
}
|
|
119
|
+
async function addWasm(m, dir) {
|
|
120
|
+
let modules = 0;
|
|
121
|
+
for (const f of await files(dir)) {
|
|
122
|
+
const ok = f.name.endsWith('.cwasm') && HEX64.test(f.name.slice(0, -'.cwasm'.length));
|
|
123
|
+
if (ok)
|
|
124
|
+
modules++;
|
|
125
|
+
m.blob(`w:${f.name}`, f, ok ? CACHE_GRACE_MS : LONG_GRACE_MS);
|
|
126
|
+
}
|
|
127
|
+
return modules;
|
|
128
|
+
}
|
|
129
|
+
/** Adds the store's evictable part; returns [blob count, total bytes]. */
|
|
130
|
+
async function addStore(m, store, dir) {
|
|
131
|
+
const all = await files(dir);
|
|
132
|
+
const view = await store.gcView();
|
|
133
|
+
for (const f of all)
|
|
134
|
+
if (!view.live.has(f.name))
|
|
135
|
+
m.blob(`s:${f.name}`, f, LONG_GRACE_MS);
|
|
136
|
+
for (const im of view.untagged) {
|
|
137
|
+
const manifest = m.blobs.get(`s:${im.id.slice(7)}`);
|
|
138
|
+
m.root({
|
|
139
|
+
key: `s:image/${im.id}`,
|
|
140
|
+
file: undefined,
|
|
141
|
+
size: 0,
|
|
142
|
+
mtime: manifest?.mtime ?? 0,
|
|
143
|
+
grace: LONG_GRACE_MS,
|
|
144
|
+
refs: [...new Set(im.blobs.filter((h) => !view.live.has(h)).map((h) => `s:${h}`))],
|
|
145
|
+
image: im.id,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return [all.length, all.reduce((a, f) => a + f.size, 0)];
|
|
149
|
+
}
|
|
150
|
+
async function sizeOf(dir) {
|
|
151
|
+
const f = await files(dir);
|
|
152
|
+
return [f.length, f.reduce((a, x) => a + x.size, 0)];
|
|
153
|
+
}
|
|
154
|
+
/** Sizes per cache under `home` (for `cache du`). */
|
|
155
|
+
export async function cacheUsage(home) {
|
|
156
|
+
const p = cachePaths(home);
|
|
157
|
+
const t = new Model();
|
|
158
|
+
const entries = await addTransform(t, p.transform);
|
|
159
|
+
const w = new Model();
|
|
160
|
+
const modules = await addWasm(w, p.wasm);
|
|
161
|
+
const s = new Model();
|
|
162
|
+
const store = await Store.openExisting(home);
|
|
163
|
+
let storeItems = 0;
|
|
164
|
+
let storeBytes = 0;
|
|
165
|
+
if (store)
|
|
166
|
+
[storeItems, storeBytes] = await addStore(s, store, p.store);
|
|
167
|
+
const [serverItems, serverBytes] = await sizeOf(p.servers);
|
|
168
|
+
return [
|
|
169
|
+
{ name: 'transform', path: p.transform, items: entries, bytes: t.total, evictable: t.total },
|
|
170
|
+
{ name: 'wasm', path: p.wasm, items: modules, bytes: w.total, evictable: w.total },
|
|
171
|
+
{ name: 'store', path: p.store, items: storeItems, bytes: storeBytes, evictable: s.total },
|
|
172
|
+
{ name: 'servers', path: p.servers, items: serverItems, bytes: serverBytes, evictable: 0 },
|
|
173
|
+
];
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Delete least recently used evictable data until it fits in `limit` bytes (0: no limit).
|
|
177
|
+
* Cheap when under the limit: one listing per cache directory, no file is read.
|
|
178
|
+
*/
|
|
179
|
+
export async function enforceCacheLimit(home, limit, now = Date.now()) {
|
|
180
|
+
if (limit === 0)
|
|
181
|
+
return { items: 0, bytes: 0, before: 0, after: 0 };
|
|
182
|
+
const p = cachePaths(home);
|
|
183
|
+
// Upper bound first (it counts tagged images too): under the limit, nothing more to do.
|
|
184
|
+
let bound = 0;
|
|
185
|
+
for (const d of [path.join(p.transform, 'blobs'), path.join(p.transform, 'entries'), p.wasm, p.store])
|
|
186
|
+
bound += (await sizeOf(d))[1];
|
|
187
|
+
if (bound <= limit)
|
|
188
|
+
return { items: 0, bytes: 0, before: bound, after: bound };
|
|
189
|
+
const store = await Store.openExisting(home);
|
|
190
|
+
const run = async () => {
|
|
191
|
+
const m = new Model();
|
|
192
|
+
await addTransform(m, p.transform);
|
|
193
|
+
await addWasm(m, p.wasm);
|
|
194
|
+
if (store)
|
|
195
|
+
await addStore(m, store, p.store);
|
|
196
|
+
const before = m.total;
|
|
197
|
+
let items = 0;
|
|
198
|
+
const cands = [
|
|
199
|
+
...m.roots.map((r) => ({ mtime: r.mtime, key: r.key, root: r })),
|
|
200
|
+
...[...m.blobs].filter(([, b]) => b.refs === 0).map(([key, b]) => ({ mtime: b.mtime, key, blob: b })),
|
|
201
|
+
];
|
|
202
|
+
cands.sort((a, b) => a.mtime - b.mtime || (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
|
|
203
|
+
const drop = async (b) => {
|
|
204
|
+
await rm(b.file, { force: true });
|
|
205
|
+
b.gone = true;
|
|
206
|
+
m.total -= b.size;
|
|
207
|
+
};
|
|
208
|
+
for (const c of cands) {
|
|
209
|
+
if (m.total <= limit)
|
|
210
|
+
break;
|
|
211
|
+
if (c.root) {
|
|
212
|
+
const r = c.root;
|
|
213
|
+
if (now - r.mtime < r.grace)
|
|
214
|
+
continue;
|
|
215
|
+
if (r.image && store)
|
|
216
|
+
await store.dropUntaggedLocked(r.image);
|
|
217
|
+
if (r.file)
|
|
218
|
+
await rm(r.file, { force: true });
|
|
219
|
+
m.total -= r.size;
|
|
220
|
+
items++;
|
|
221
|
+
for (const k of r.refs) {
|
|
222
|
+
const b = m.blobs.get(k);
|
|
223
|
+
if (!b || b.gone)
|
|
224
|
+
continue;
|
|
225
|
+
b.refs--;
|
|
226
|
+
if (b.refs === 0 && now - b.mtime >= b.grace)
|
|
227
|
+
await drop(b);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
else if (c.blob && !c.blob.gone && c.blob.refs === 0 && now - c.blob.mtime >= c.blob.grace) {
|
|
231
|
+
await drop(c.blob);
|
|
232
|
+
items++;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return { items, bytes: before - m.total, before, after: m.total };
|
|
236
|
+
};
|
|
237
|
+
return store ? store.withLock(run) : run();
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=cache-limit.js.map
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
// GENERATED by tools/gen-casefold.mjs from CaseFolding-17.0.0.txt; do not edit.
|
|
2
|
+
// Unicode simple case folding (status C and S): 1512 mappings in 209 runs
|
|
3
|
+
// [start, end, delta, step]: c in start..=end with (c - start) % step == 0 folds to c + delta.
|
|
4
|
+
export const CASEFOLD_UNICODE_VERSION = '17.0.0';
|
|
5
|
+
// prettier-ignore
|
|
6
|
+
export const CASEFOLD_RUNS = [
|
|
7
|
+
[65, 90, 32, 1],
|
|
8
|
+
[181, 181, 775, 1],
|
|
9
|
+
[192, 214, 32, 1],
|
|
10
|
+
[216, 222, 32, 1],
|
|
11
|
+
[256, 302, 1, 2],
|
|
12
|
+
[306, 310, 1, 2],
|
|
13
|
+
[313, 327, 1, 2],
|
|
14
|
+
[330, 374, 1, 2],
|
|
15
|
+
[376, 376, -121, 1],
|
|
16
|
+
[377, 381, 1, 2],
|
|
17
|
+
[383, 383, -268, 1],
|
|
18
|
+
[385, 385, 210, 1],
|
|
19
|
+
[386, 388, 1, 2],
|
|
20
|
+
[390, 390, 206, 1],
|
|
21
|
+
[391, 391, 1, 1],
|
|
22
|
+
[393, 394, 205, 1],
|
|
23
|
+
[395, 395, 1, 1],
|
|
24
|
+
[398, 398, 79, 1],
|
|
25
|
+
[399, 399, 202, 1],
|
|
26
|
+
[400, 400, 203, 1],
|
|
27
|
+
[401, 401, 1, 1],
|
|
28
|
+
[403, 403, 205, 1],
|
|
29
|
+
[404, 404, 207, 1],
|
|
30
|
+
[406, 406, 211, 1],
|
|
31
|
+
[407, 407, 209, 1],
|
|
32
|
+
[408, 408, 1, 1],
|
|
33
|
+
[412, 412, 211, 1],
|
|
34
|
+
[413, 413, 213, 1],
|
|
35
|
+
[415, 415, 214, 1],
|
|
36
|
+
[416, 420, 1, 2],
|
|
37
|
+
[422, 422, 218, 1],
|
|
38
|
+
[423, 423, 1, 1],
|
|
39
|
+
[425, 425, 218, 1],
|
|
40
|
+
[428, 428, 1, 1],
|
|
41
|
+
[430, 430, 218, 1],
|
|
42
|
+
[431, 431, 1, 1],
|
|
43
|
+
[433, 434, 217, 1],
|
|
44
|
+
[435, 437, 1, 2],
|
|
45
|
+
[439, 439, 219, 1],
|
|
46
|
+
[440, 440, 1, 1],
|
|
47
|
+
[444, 444, 1, 1],
|
|
48
|
+
[452, 452, 2, 1],
|
|
49
|
+
[453, 453, 1, 1],
|
|
50
|
+
[455, 455, 2, 1],
|
|
51
|
+
[456, 456, 1, 1],
|
|
52
|
+
[458, 458, 2, 1],
|
|
53
|
+
[459, 475, 1, 2],
|
|
54
|
+
[478, 494, 1, 2],
|
|
55
|
+
[497, 497, 2, 1],
|
|
56
|
+
[498, 500, 1, 2],
|
|
57
|
+
[502, 502, -97, 1],
|
|
58
|
+
[503, 503, -56, 1],
|
|
59
|
+
[504, 542, 1, 2],
|
|
60
|
+
[544, 544, -130, 1],
|
|
61
|
+
[546, 562, 1, 2],
|
|
62
|
+
[570, 570, 10795, 1],
|
|
63
|
+
[571, 571, 1, 1],
|
|
64
|
+
[573, 573, -163, 1],
|
|
65
|
+
[574, 574, 10792, 1],
|
|
66
|
+
[577, 577, 1, 1],
|
|
67
|
+
[579, 579, -195, 1],
|
|
68
|
+
[580, 580, 69, 1],
|
|
69
|
+
[581, 581, 71, 1],
|
|
70
|
+
[582, 590, 1, 2],
|
|
71
|
+
[837, 837, 116, 1],
|
|
72
|
+
[880, 882, 1, 2],
|
|
73
|
+
[886, 886, 1, 1],
|
|
74
|
+
[895, 895, 116, 1],
|
|
75
|
+
[902, 902, 38, 1],
|
|
76
|
+
[904, 906, 37, 1],
|
|
77
|
+
[908, 908, 64, 1],
|
|
78
|
+
[910, 911, 63, 1],
|
|
79
|
+
[913, 929, 32, 1],
|
|
80
|
+
[931, 939, 32, 1],
|
|
81
|
+
[962, 962, 1, 1],
|
|
82
|
+
[975, 975, 8, 1],
|
|
83
|
+
[976, 976, -30, 1],
|
|
84
|
+
[977, 977, -25, 1],
|
|
85
|
+
[981, 981, -15, 1],
|
|
86
|
+
[982, 982, -22, 1],
|
|
87
|
+
[984, 1006, 1, 2],
|
|
88
|
+
[1008, 1008, -54, 1],
|
|
89
|
+
[1009, 1009, -48, 1],
|
|
90
|
+
[1012, 1012, -60, 1],
|
|
91
|
+
[1013, 1013, -64, 1],
|
|
92
|
+
[1015, 1015, 1, 1],
|
|
93
|
+
[1017, 1017, -7, 1],
|
|
94
|
+
[1018, 1018, 1, 1],
|
|
95
|
+
[1021, 1023, -130, 1],
|
|
96
|
+
[1024, 1039, 80, 1],
|
|
97
|
+
[1040, 1071, 32, 1],
|
|
98
|
+
[1120, 1152, 1, 2],
|
|
99
|
+
[1162, 1214, 1, 2],
|
|
100
|
+
[1216, 1216, 15, 1],
|
|
101
|
+
[1217, 1229, 1, 2],
|
|
102
|
+
[1232, 1326, 1, 2],
|
|
103
|
+
[1329, 1366, 48, 1],
|
|
104
|
+
[4256, 4293, 7264, 1],
|
|
105
|
+
[4295, 4295, 7264, 1],
|
|
106
|
+
[4301, 4301, 7264, 1],
|
|
107
|
+
[5112, 5117, -8, 1],
|
|
108
|
+
[7296, 7296, -6222, 1],
|
|
109
|
+
[7297, 7297, -6221, 1],
|
|
110
|
+
[7298, 7298, -6212, 1],
|
|
111
|
+
[7299, 7300, -6210, 1],
|
|
112
|
+
[7301, 7301, -6211, 1],
|
|
113
|
+
[7302, 7302, -6204, 1],
|
|
114
|
+
[7303, 7303, -6180, 1],
|
|
115
|
+
[7304, 7304, 35267, 1],
|
|
116
|
+
[7305, 7305, 1, 1],
|
|
117
|
+
[7312, 7354, -3008, 1],
|
|
118
|
+
[7357, 7359, -3008, 1],
|
|
119
|
+
[7680, 7828, 1, 2],
|
|
120
|
+
[7835, 7835, -58, 1],
|
|
121
|
+
[7838, 7838, -7615, 1],
|
|
122
|
+
[7840, 7934, 1, 2],
|
|
123
|
+
[7944, 7951, -8, 1],
|
|
124
|
+
[7960, 7965, -8, 1],
|
|
125
|
+
[7976, 7983, -8, 1],
|
|
126
|
+
[7992, 7999, -8, 1],
|
|
127
|
+
[8008, 8013, -8, 1],
|
|
128
|
+
[8025, 8031, -8, 2],
|
|
129
|
+
[8040, 8047, -8, 1],
|
|
130
|
+
[8072, 8079, -8, 1],
|
|
131
|
+
[8088, 8095, -8, 1],
|
|
132
|
+
[8104, 8111, -8, 1],
|
|
133
|
+
[8120, 8121, -8, 1],
|
|
134
|
+
[8122, 8123, -74, 1],
|
|
135
|
+
[8124, 8124, -9, 1],
|
|
136
|
+
[8126, 8126, -7173, 1],
|
|
137
|
+
[8136, 8139, -86, 1],
|
|
138
|
+
[8140, 8140, -9, 1],
|
|
139
|
+
[8147, 8147, -7235, 1],
|
|
140
|
+
[8152, 8153, -8, 1],
|
|
141
|
+
[8154, 8155, -100, 1],
|
|
142
|
+
[8163, 8163, -7219, 1],
|
|
143
|
+
[8168, 8169, -8, 1],
|
|
144
|
+
[8170, 8171, -112, 1],
|
|
145
|
+
[8172, 8172, -7, 1],
|
|
146
|
+
[8184, 8185, -128, 1],
|
|
147
|
+
[8186, 8187, -126, 1],
|
|
148
|
+
[8188, 8188, -9, 1],
|
|
149
|
+
[8486, 8486, -7517, 1],
|
|
150
|
+
[8490, 8490, -8383, 1],
|
|
151
|
+
[8491, 8491, -8262, 1],
|
|
152
|
+
[8498, 8498, 28, 1],
|
|
153
|
+
[8544, 8559, 16, 1],
|
|
154
|
+
[8579, 8579, 1, 1],
|
|
155
|
+
[9398, 9423, 26, 1],
|
|
156
|
+
[11264, 11311, 48, 1],
|
|
157
|
+
[11360, 11360, 1, 1],
|
|
158
|
+
[11362, 11362, -10743, 1],
|
|
159
|
+
[11363, 11363, -3814, 1],
|
|
160
|
+
[11364, 11364, -10727, 1],
|
|
161
|
+
[11367, 11371, 1, 2],
|
|
162
|
+
[11373, 11373, -10780, 1],
|
|
163
|
+
[11374, 11374, -10749, 1],
|
|
164
|
+
[11375, 11375, -10783, 1],
|
|
165
|
+
[11376, 11376, -10782, 1],
|
|
166
|
+
[11378, 11378, 1, 1],
|
|
167
|
+
[11381, 11381, 1, 1],
|
|
168
|
+
[11390, 11391, -10815, 1],
|
|
169
|
+
[11392, 11490, 1, 2],
|
|
170
|
+
[11499, 11501, 1, 2],
|
|
171
|
+
[11506, 11506, 1, 1],
|
|
172
|
+
[42560, 42604, 1, 2],
|
|
173
|
+
[42624, 42650, 1, 2],
|
|
174
|
+
[42786, 42798, 1, 2],
|
|
175
|
+
[42802, 42862, 1, 2],
|
|
176
|
+
[42873, 42875, 1, 2],
|
|
177
|
+
[42877, 42877, -35332, 1],
|
|
178
|
+
[42878, 42886, 1, 2],
|
|
179
|
+
[42891, 42891, 1, 1],
|
|
180
|
+
[42893, 42893, -42280, 1],
|
|
181
|
+
[42896, 42898, 1, 2],
|
|
182
|
+
[42902, 42920, 1, 2],
|
|
183
|
+
[42922, 42922, -42308, 1],
|
|
184
|
+
[42923, 42923, -42319, 1],
|
|
185
|
+
[42924, 42924, -42315, 1],
|
|
186
|
+
[42925, 42925, -42305, 1],
|
|
187
|
+
[42926, 42926, -42308, 1],
|
|
188
|
+
[42928, 42928, -42258, 1],
|
|
189
|
+
[42929, 42929, -42282, 1],
|
|
190
|
+
[42930, 42930, -42261, 1],
|
|
191
|
+
[42931, 42931, 928, 1],
|
|
192
|
+
[42932, 42946, 1, 2],
|
|
193
|
+
[42948, 42948, -48, 1],
|
|
194
|
+
[42949, 42949, -42307, 1],
|
|
195
|
+
[42950, 42950, -35384, 1],
|
|
196
|
+
[42951, 42953, 1, 2],
|
|
197
|
+
[42955, 42955, -42343, 1],
|
|
198
|
+
[42956, 42970, 1, 2],
|
|
199
|
+
[42972, 42972, -42561, 1],
|
|
200
|
+
[42997, 42997, 1, 1],
|
|
201
|
+
[43888, 43967, -38864, 1],
|
|
202
|
+
[64261, 64261, 1, 1],
|
|
203
|
+
[65313, 65338, 32, 1],
|
|
204
|
+
[66560, 66599, 40, 1],
|
|
205
|
+
[66736, 66771, 40, 1],
|
|
206
|
+
[66928, 66938, 39, 1],
|
|
207
|
+
[66940, 66954, 39, 1],
|
|
208
|
+
[66956, 66962, 39, 1],
|
|
209
|
+
[66964, 66965, 39, 1],
|
|
210
|
+
[68736, 68786, 64, 1],
|
|
211
|
+
[68944, 68965, 32, 1],
|
|
212
|
+
[71840, 71871, 32, 1],
|
|
213
|
+
[93760, 93791, 32, 1],
|
|
214
|
+
[93856, 93880, 27, 1],
|
|
215
|
+
[125184, 125217, 34, 1],
|
|
216
|
+
];
|
|
217
|
+
//# sourceMappingURL=casefold-data.js.map
|