@tileflow/dev 0.1.0-alpha.3 → 0.1.0-alpha.31
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/LICENSE +201 -0
- package/README.md +201 -5
- package/THIRD_PARTY_NOTICES.md +87 -0
- package/dist/artifacts.d.ts +265 -0
- package/dist/artifacts.js +81 -0
- package/dist/chunk-2QXKVQ6O.js +3062 -0
- package/dist/chunk-7C4F6GAX.js +170 -0
- package/dist/chunk-AQUGMUZW.js +324 -0
- package/dist/chunk-D4OE4ITL.js +13 -0
- package/dist/chunk-IR22ZTQW.js +2392 -0
- package/dist/chunk-KDFTE4Q5.js +156 -0
- package/dist/chunk-ONYQNLNA.js +1108 -0
- package/dist/chunk-UTRO4IBQ.js +671 -0
- package/dist/chunk-XHJBCVBB.js +241 -0
- package/dist/config.d.ts +33 -0
- package/dist/config.js +27 -0
- package/dist/fonts.d.ts +47 -0
- package/dist/fonts.js +16 -0
- package/dist/icons.d.ts +339 -0
- package/dist/icons.js +39 -0
- package/dist/inspect.d.ts +149 -0
- package/dist/inspect.js +805 -0
- package/dist/preview-assets-MVUJJ5XR.js +148 -0
- package/dist/preview.d.ts +71 -0
- package/dist/preview.js +2574 -0
- package/dist/server.d.ts +82 -0
- package/dist/server.js +2094 -0
- package/dist/tilesets.d.ts +89 -0
- package/dist/tilesets.js +6 -0
- package/dist/validation.d.ts +65 -0
- package/dist/validation.js +24 -0
- package/docs/artifact-lifecycle.md +152 -0
- package/docs/bounded-pmtiles-resource-inspection.md +21 -0
- package/docs/bounded-vector-feature-inspection.md +100 -0
- package/docs/local-comparison-workbench-and-compiler-inspection.md +227 -0
- package/docs/native-artifacts.md +285 -0
- package/docs/native-icons.md +129 -0
- package/docs/structured-config-inspection-and-diagnostics.md +39 -0
- package/package.json +77 -13
- package/dist/index.d.ts +0 -54
- package/dist/index.js +0 -314
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// src/diagnostic-sanitization.ts
|
|
2
|
+
function sanitizeDiagnosticSecrets(value) {
|
|
3
|
+
return value.replace(/([a-z][a-z0-9+.-]*:\/\/)[^\s/@:]+:[^\s/@]+@/gi, "$1[redacted]@").replace(/\bBearer\s+[^\s,;]+/gi, "Bearer [redacted]").replace(/\btf_(?:live|cli|test)_[A-Za-z0-9_-]{8,}\b/gi, "tf_[redacted]").replace(/\b(?:sk_(?:live|test)|rk_(?:live|test)|whsec)_[A-Za-z0-9_-]+\b/g, "[redacted]").replace(
|
|
4
|
+
/([?&](?:access_token|api_key|key|password|secret|signature|token)=)[^&#\s]+/gi,
|
|
5
|
+
"$1[redacted]"
|
|
6
|
+
);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// src/style-validation.ts
|
|
10
|
+
import { validateStyleMin } from "@maplibre/maplibre-gl-style-spec";
|
|
11
|
+
var TileflowStyleValidationError = class extends Error {
|
|
12
|
+
code = "STYLE_INVALID";
|
|
13
|
+
issues;
|
|
14
|
+
phase = "style-validation";
|
|
15
|
+
constructor(issues) {
|
|
16
|
+
super("Compiled Tileflow styles are not valid MapLibre styles.");
|
|
17
|
+
this.name = "TileflowStyleValidationError";
|
|
18
|
+
this.issues = normalizeIssues(issues);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
var maxIssues = 32;
|
|
22
|
+
var maxMessageLength = 300;
|
|
23
|
+
var maxPathLength = 300;
|
|
24
|
+
function assertValidTileflowStyle(style, map) {
|
|
25
|
+
const issues = validateTileflowStyle(style, map);
|
|
26
|
+
if (issues.length > 0) throw new TileflowStyleValidationError(issues);
|
|
27
|
+
}
|
|
28
|
+
function validateTileflowStyle(style, map) {
|
|
29
|
+
const jsonIssues = [];
|
|
30
|
+
collectJsonIssues(
|
|
31
|
+
style,
|
|
32
|
+
`maps.${sanitizePathSegment(map)}.style`,
|
|
33
|
+
map,
|
|
34
|
+
jsonIssues,
|
|
35
|
+
/* @__PURE__ */ new Set()
|
|
36
|
+
);
|
|
37
|
+
if (jsonIssues.length > 0) return normalizeIssues(jsonIssues);
|
|
38
|
+
const semanticIssues = validateStyleMin(style).map(
|
|
39
|
+
(issue) => createSemanticIssue(style, map, issue.message)
|
|
40
|
+
);
|
|
41
|
+
return normalizeIssues(semanticIssues);
|
|
42
|
+
}
|
|
43
|
+
function normalizeTileflowStyleValidationIssues(issues) {
|
|
44
|
+
return normalizeIssues(issues);
|
|
45
|
+
}
|
|
46
|
+
function createSemanticIssue(style, map, rawMessage) {
|
|
47
|
+
const normalized = rawMessage.replace(/[\r\n]+/g, " ").trim();
|
|
48
|
+
const separator = normalized.indexOf(":");
|
|
49
|
+
const rawPath = separator >= 0 ? normalized.slice(0, separator).trim() : "";
|
|
50
|
+
const detail = separator >= 0 ? normalized.slice(separator + 1).trim() : normalized;
|
|
51
|
+
return {
|
|
52
|
+
map,
|
|
53
|
+
message: boundText(sanitizeDiagnosticSecrets(sanitizeUrls(detail)), maxMessageLength),
|
|
54
|
+
path: boundText(stableStylePath(style, map, rawPath), maxPathLength)
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function stableStylePath(style, map, rawPath) {
|
|
58
|
+
const fallback = `maps.${sanitizePathSegment(map)}.style`;
|
|
59
|
+
if (!rawPath) return fallback;
|
|
60
|
+
const path = rawPath.replace(/layers\[(\d+)]/g, (_match, index) => {
|
|
61
|
+
const layer = style.layers[Number(index)];
|
|
62
|
+
const id = typeof layer?.id === "string" && layer.id ? layer.id : index;
|
|
63
|
+
return `layers.${sanitizePathSegment(id)}`;
|
|
64
|
+
});
|
|
65
|
+
return `${fallback}.${path}`;
|
|
66
|
+
}
|
|
67
|
+
function sanitizePathSegment(value) {
|
|
68
|
+
let sanitized = "";
|
|
69
|
+
let replacing = false;
|
|
70
|
+
for (const character of value) {
|
|
71
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
72
|
+
const isAsciiLetter = codePoint >= 65 && codePoint <= 90 || codePoint >= 97 && codePoint <= 122;
|
|
73
|
+
const isDigit = codePoint >= 48 && codePoint <= 57;
|
|
74
|
+
const shouldReplace = !isAsciiLetter && !isDigit && character !== "-" && character !== "_";
|
|
75
|
+
if (shouldReplace) {
|
|
76
|
+
if (!replacing) sanitized += "-";
|
|
77
|
+
replacing = true;
|
|
78
|
+
} else {
|
|
79
|
+
sanitized += character;
|
|
80
|
+
replacing = false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return sanitized.slice(0, 128) || "(unknown)";
|
|
84
|
+
}
|
|
85
|
+
function collectJsonIssues(value, path, map, issues, ancestors) {
|
|
86
|
+
if (issues.length >= maxIssues) return;
|
|
87
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") return;
|
|
88
|
+
if (typeof value === "number") {
|
|
89
|
+
if (!Number.isFinite(value)) addJsonIssue(map, path, "non-finite number", issues);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (typeof value !== "object") {
|
|
93
|
+
addJsonIssue(map, path, typeof value, issues);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (ancestors.has(value)) {
|
|
97
|
+
addJsonIssue(map, path, "cyclic object", issues);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
ancestors.add(value);
|
|
101
|
+
if (Array.isArray(value)) {
|
|
102
|
+
value.forEach((item, index) => {
|
|
103
|
+
const layerId = path.endsWith(".layers") && item && typeof item === "object" && !Array.isArray(item) ? item.id : void 0;
|
|
104
|
+
const childPath = typeof layerId === "string" && layerId ? `${path}.${sanitizePathSegment(layerId)}` : `${path}[${index}]`;
|
|
105
|
+
collectJsonIssues(item, childPath, map, issues, ancestors);
|
|
106
|
+
});
|
|
107
|
+
} else {
|
|
108
|
+
for (const [key, item] of Object.entries(value)) {
|
|
109
|
+
collectJsonIssues(item, `${path}.${sanitizePathSegment(key)}`, map, issues, ancestors);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
ancestors.delete(value);
|
|
113
|
+
}
|
|
114
|
+
function addJsonIssue(map, path, type, issues) {
|
|
115
|
+
issues.push({
|
|
116
|
+
map,
|
|
117
|
+
message: `Expected a recursive JSON value; found ${type}.`,
|
|
118
|
+
path: boundText(path, maxPathLength)
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function normalizeIssues(issues) {
|
|
122
|
+
const normalized = issues.map((issue) => ({
|
|
123
|
+
map: boundText(sanitizePathSegment(issue.map), 128),
|
|
124
|
+
message: boundText(
|
|
125
|
+
sanitizeDiagnosticSecrets(issue.message.replace(/[\r\n]+/g, " ").trim()),
|
|
126
|
+
maxMessageLength
|
|
127
|
+
),
|
|
128
|
+
path: boundText(issue.path.replaceAll("\\", "/"), maxPathLength)
|
|
129
|
+
}));
|
|
130
|
+
normalized.sort(
|
|
131
|
+
(left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : left.message < right.message ? -1 : left.message > right.message ? 1 : 0
|
|
132
|
+
);
|
|
133
|
+
return normalized.filter(
|
|
134
|
+
(issue, index) => index === 0 || issue.path !== normalized[index - 1]?.path || issue.message !== normalized[index - 1]?.message
|
|
135
|
+
).slice(0, maxIssues);
|
|
136
|
+
}
|
|
137
|
+
function sanitizeUrls(message) {
|
|
138
|
+
return message.replace(/https?:\/\/[^\s'"<>]+/gi, (value) => {
|
|
139
|
+
try {
|
|
140
|
+
return new URL(value.replace(/[),.;]+$/, "")).origin;
|
|
141
|
+
} catch {
|
|
142
|
+
return "(resource URL)";
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
function boundText(value, limit) {
|
|
147
|
+
return value.length <= limit ? value : `${value.slice(0, limit - 1)}\u2026`;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export {
|
|
151
|
+
sanitizeDiagnosticSecrets,
|
|
152
|
+
TileflowStyleValidationError,
|
|
153
|
+
assertValidTileflowStyle,
|
|
154
|
+
validateTileflowStyle,
|
|
155
|
+
normalizeTileflowStyleValidationIssues
|
|
156
|
+
};
|