@nuasite/cli 0.56.0 → 0.56.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +506 -54
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -22482,8 +22482,23 @@ function parseSource(source) {
|
|
|
22482
22482
|
return null;
|
|
22483
22483
|
}
|
|
22484
22484
|
}
|
|
22485
|
+
async function classifyEmptyContentConfig(fs) {
|
|
22486
|
+
let found = false;
|
|
22487
|
+
for (const configPath of CONTENT_CONFIG_PATHS) {
|
|
22488
|
+
try {
|
|
22489
|
+
await fs.stat(configPath);
|
|
22490
|
+
} catch {
|
|
22491
|
+
continue;
|
|
22492
|
+
}
|
|
22493
|
+
found = true;
|
|
22494
|
+
if (parseSource(await fs.readFile(configPath)) === null) {
|
|
22495
|
+
return "unparseable";
|
|
22496
|
+
}
|
|
22497
|
+
}
|
|
22498
|
+
return found ? "no-collections" : "missing";
|
|
22499
|
+
}
|
|
22485
22500
|
async function parseContentConfig(fs, cache) {
|
|
22486
|
-
for (const configPath of
|
|
22501
|
+
for (const configPath of CONTENT_CONFIG_PATHS) {
|
|
22487
22502
|
let stat;
|
|
22488
22503
|
try {
|
|
22489
22504
|
stat = await fs.stat(configPath);
|
|
@@ -23166,7 +23181,7 @@ function dropNestedDerivedFrom(collectionName, path2, fields) {
|
|
|
23166
23181
|
dropNestedDerivedFrom(collectionName, fieldPath, field.fields);
|
|
23167
23182
|
}
|
|
23168
23183
|
}
|
|
23169
|
-
var import_parser, FIELD_HELPER_TYPES, VALID_HINT_KEYS, WRAPPER_METHODS;
|
|
23184
|
+
var import_parser, FIELD_HELPER_TYPES, VALID_HINT_KEYS, WRAPPER_METHODS, CONTENT_CONFIG_PATHS;
|
|
23170
23185
|
var init_content_config_ast = __esm(() => {
|
|
23171
23186
|
init_src();
|
|
23172
23187
|
import_parser = __toESM(require_lib(), 1);
|
|
@@ -23198,6 +23213,7 @@ var init_content_config_ast = __esm(() => {
|
|
|
23198
23213
|
"accept"
|
|
23199
23214
|
]);
|
|
23200
23215
|
WRAPPER_METHODS = new Set(["optional", "nullable", "nullish", "default"]);
|
|
23216
|
+
CONTENT_CONFIG_PATHS = ["src/content/config.ts", "src/content.config.ts"];
|
|
23201
23217
|
});
|
|
23202
23218
|
|
|
23203
23219
|
// ../cms-core/src/shared.ts
|
|
@@ -23362,12 +23378,15 @@ async function checkContent(fs, options = {}) {
|
|
|
23362
23378
|
const findings = [];
|
|
23363
23379
|
const config = await parseContentConfig(fs, new Map);
|
|
23364
23380
|
if (config.size === 0) {
|
|
23365
|
-
|
|
23366
|
-
|
|
23367
|
-
|
|
23368
|
-
|
|
23369
|
-
|
|
23370
|
-
|
|
23381
|
+
const reason = await classifyEmptyContentConfig(fs);
|
|
23382
|
+
if (reason !== "no-collections") {
|
|
23383
|
+
findings.push({
|
|
23384
|
+
severity: "error",
|
|
23385
|
+
code: reason === "missing" ? "config/missing" : "config/unreadable",
|
|
23386
|
+
file: "src/content.config.ts",
|
|
23387
|
+
message: reason === "missing" ? `No content config found \u2014 expected one of ${CONTENT_CONFIG_PATHS.join(" or ")}.` : "The content config could not be parsed."
|
|
23388
|
+
});
|
|
23389
|
+
}
|
|
23371
23390
|
return { findings, collections: 0, entries: 0 };
|
|
23372
23391
|
}
|
|
23373
23392
|
const collections = await loadCollections(fs, config);
|
|
@@ -33552,7 +33571,7 @@ async function applyImageChange(content, change, absFilePath, originUrl) {
|
|
|
33552
33571
|
break;
|
|
33553
33572
|
}
|
|
33554
33573
|
}
|
|
33555
|
-
if (replacedIndex < 0 && change.sourceSnippet) {
|
|
33574
|
+
if (replacedIndex < 0 && change.sourceSnippet && isYamlValueSource(newContent, change.sourceSnippet, change.sourcePath)) {
|
|
33556
33575
|
for (const srcToFind of srcCandidates) {
|
|
33557
33576
|
const yamlResult = tryYamlValueReplacement(change.sourceSnippet, srcToFind, newSrc);
|
|
33558
33577
|
if (yamlResult !== null) {
|
|
@@ -33859,7 +33878,7 @@ function replaceLiteralInSnippet(content, snippet, oldValue, newValue) {
|
|
|
33859
33878
|
continue;
|
|
33860
33879
|
const updated = snippet.replace(pattern, `${quote}${safeNewValue}${quote}`);
|
|
33861
33880
|
if (updated !== snippet)
|
|
33862
|
-
return content.replace(snippet, updated);
|
|
33881
|
+
return content.replace(snippet, escapeReplacement(updated));
|
|
33863
33882
|
}
|
|
33864
33883
|
return;
|
|
33865
33884
|
}
|
|
@@ -33953,35 +33972,66 @@ function applyTextChange(content, change, manifest) {
|
|
|
33953
33972
|
if (!content.includes(sourceSnippet)) {
|
|
33954
33973
|
return { success: false, error: "Source snippet not found in file" };
|
|
33955
33974
|
}
|
|
33956
|
-
const
|
|
33975
|
+
const entry = manifest.entries[change.cmsId];
|
|
33976
|
+
const insideYaml = isYamlValueSource(content, sourceSnippet, change.sourcePath);
|
|
33977
|
+
const stylingAllowed = entry?.allowStyling !== false && !insideYaml;
|
|
33957
33978
|
const newText = stylingAllowed ? htmlValue ?? newValue : newValue;
|
|
33958
33979
|
const placeholderPattern = /\{\{cms:[^}]+\}\}/g;
|
|
33959
33980
|
if (placeholderPattern.test(originalValue)) {
|
|
33960
|
-
return applyTextChangeWithPlaceholders(content, sourceSnippet, originalValue, newText);
|
|
33981
|
+
return applyTextChangeWithPlaceholders(insideYaml, content, sourceSnippet, originalValue, newText);
|
|
33961
33982
|
}
|
|
33962
33983
|
const resolvedNewText = resolveCmsPlaceholders(newText, manifest);
|
|
33963
33984
|
const resolvedOriginal = resolveCmsPlaceholders(originalValue, manifest);
|
|
33964
|
-
const
|
|
33965
|
-
|
|
33966
|
-
|
|
33967
|
-
|
|
33968
|
-
|
|
33985
|
+
const write = (updatedSnippet2) => writeSnippet(content, sourceSnippet, updatedSnippet2, insideYaml, resolvedNewText);
|
|
33986
|
+
const snippetIsJavaScript = isJavaScriptSource(change.sourcePath) && (!!entry?.variableName || !looksLikeMarkup(sourceSnippet));
|
|
33987
|
+
if (snippetIsJavaScript) {
|
|
33988
|
+
const literalResult = tryJsStringLiteralChange(sourceSnippet, resolvedOriginal, resolvedNewText);
|
|
33989
|
+
if (literalResult !== null) {
|
|
33990
|
+
return write(literalResult);
|
|
33991
|
+
}
|
|
33992
|
+
}
|
|
33993
|
+
if (insideYaml) {
|
|
33994
|
+
const frontmatterResult = tryYamlValueReplacement(sourceSnippet, resolvedOriginal, resolvedNewText, true);
|
|
33995
|
+
if (frontmatterResult !== null) {
|
|
33996
|
+
return write(frontmatterResult);
|
|
33969
33997
|
}
|
|
33998
|
+
}
|
|
33999
|
+
const updatedSnippet = sourceSnippet.replace(resolvedOriginal, escapeReplacement(resolvedNewText));
|
|
34000
|
+
if (updatedSnippet === sourceSnippet) {
|
|
33970
34001
|
const brResult = tryBrNormalizedChange(sourceSnippet, resolvedOriginal, resolvedNewText);
|
|
33971
34002
|
if (brResult !== null) {
|
|
33972
|
-
return
|
|
34003
|
+
return write(brResult);
|
|
34004
|
+
}
|
|
34005
|
+
if (snippetIsJavaScript) {
|
|
34006
|
+
const literalResult = tryJsStringLiteralChange(sourceSnippet, resolvedOriginal, resolvedNewText);
|
|
34007
|
+
if (literalResult !== null) {
|
|
34008
|
+
return write(literalResult);
|
|
34009
|
+
}
|
|
33973
34010
|
}
|
|
33974
34011
|
const matchedText = findTextInSnippet(sourceSnippet, resolvedOriginal);
|
|
33975
34012
|
if (matchedText) {
|
|
33976
|
-
const
|
|
33977
|
-
|
|
34013
|
+
const spliced = /<[^>]+>/.test(resolvedNewText) ? null : spliceIntoEntitySource(matchedText, resolvedOriginal, resolvedNewText);
|
|
34014
|
+
const replacement = spliced ?? (/<[^>]+>/.test(resolvedNewText) ? encodeNbspLike(resolvedNewText, matchedText) : encodeEntitiesLike(resolvedNewText, matchedText));
|
|
34015
|
+
const updatedWithEntity = sourceSnippet.replace(matchedText, escapeReplacement(replacement));
|
|
34016
|
+
return write(updatedWithEntity);
|
|
33978
34017
|
}
|
|
33979
34018
|
const innerMatch = sourceSnippet.match(/^(\s*<(\w+)\b[^>]*>)([\s\S]*)(<\/\2>\s*)$/);
|
|
33980
34019
|
if (innerMatch) {
|
|
33981
34020
|
const [, openTag, , innerContent, closeTag] = innerMatch;
|
|
33982
34021
|
const textOnly = innerContent.replace(/<[^>]+>/g, "");
|
|
33983
34022
|
if (textOnly === resolvedOriginal) {
|
|
33984
|
-
|
|
34023
|
+
const isHtmlReplacement = /<[^>]+>/.test(resolvedNewText);
|
|
34024
|
+
if (isHtmlReplacement || !/<[^>]+>/.test(innerContent)) {
|
|
34025
|
+
return write(openTag + resolvedNewText + closeTag);
|
|
34026
|
+
}
|
|
34027
|
+
const splicedInner = spliceTextAcrossInlineMarkup(innerContent, resolvedOriginal, resolvedNewText);
|
|
34028
|
+
if (splicedInner !== null) {
|
|
34029
|
+
return write(openTag + splicedInner + closeTag);
|
|
34030
|
+
}
|
|
34031
|
+
return {
|
|
34032
|
+
success: false,
|
|
34033
|
+
error: "Cannot apply this edit without dropping the inline markup inside the element " + "\u2014 edit the styled part separately"
|
|
34034
|
+
};
|
|
33985
34035
|
}
|
|
33986
34036
|
}
|
|
33987
34037
|
return {
|
|
@@ -33989,9 +34039,9 @@ function applyTextChange(content, change, manifest) {
|
|
|
33989
34039
|
error: `Original text "${resolvedOriginal.substring(0, 50)}..." not found in source snippet`
|
|
33990
34040
|
};
|
|
33991
34041
|
}
|
|
33992
|
-
return
|
|
34042
|
+
return write(updatedSnippet);
|
|
33993
34043
|
}
|
|
33994
|
-
function applyTextChangeWithPlaceholders(content, sourceSnippet, originalValue, newText) {
|
|
34044
|
+
function applyTextChangeWithPlaceholders(insideYaml, content, sourceSnippet, originalValue, newText) {
|
|
33995
34045
|
const placeholderPattern = /\{\{cms:[^}]+\}\}/g;
|
|
33996
34046
|
const originalParts = originalValue.split(placeholderPattern);
|
|
33997
34047
|
const newParts = newText.split(placeholderPattern);
|
|
@@ -34011,7 +34061,7 @@ function applyTextChangeWithPlaceholders(content, sourceSnippet, originalValue,
|
|
|
34011
34061
|
if (matchedText !== oldPart) {
|
|
34012
34062
|
newPart = encodeEntitiesLike(newPart, matchedText);
|
|
34013
34063
|
}
|
|
34014
|
-
updatedSnippet = updatedSnippet.replace(matchedText, newPart);
|
|
34064
|
+
updatedSnippet = updatedSnippet.replace(matchedText, escapeReplacement(newPart));
|
|
34015
34065
|
anyChange = true;
|
|
34016
34066
|
} else {
|
|
34017
34067
|
return {
|
|
@@ -34023,27 +34073,192 @@ function applyTextChangeWithPlaceholders(content, sourceSnippet, originalValue,
|
|
|
34023
34073
|
if (!anyChange) {
|
|
34024
34074
|
return { success: false, error: "No text changes detected between original and new values" };
|
|
34025
34075
|
}
|
|
34026
|
-
return
|
|
34076
|
+
return writeSnippet(content, sourceSnippet, updatedSnippet, insideYaml, newText);
|
|
34077
|
+
}
|
|
34078
|
+
function isJavaScriptSource(sourcePath) {
|
|
34079
|
+
return !!sourcePath && JAVASCRIPT_SOURCE.test(sourcePath);
|
|
34080
|
+
}
|
|
34081
|
+
function isYamlValueSource(content, sourceSnippet, sourcePath) {
|
|
34082
|
+
if (!sourcePath)
|
|
34083
|
+
return false;
|
|
34084
|
+
if (YAML_DOCUMENT_SOURCE.test(sourcePath))
|
|
34085
|
+
return true;
|
|
34086
|
+
if (!YAML_FRONTMATTER_SOURCE.test(sourcePath))
|
|
34087
|
+
return false;
|
|
34088
|
+
const block = frontmatterBlock(content);
|
|
34089
|
+
if (!block)
|
|
34090
|
+
return false;
|
|
34091
|
+
const snippetStart = content.indexOf(sourceSnippet);
|
|
34092
|
+
return snippetStart >= block.start && snippetStart + sourceSnippet.length <= block.end;
|
|
34093
|
+
}
|
|
34094
|
+
function frontmatterBlock(content) {
|
|
34095
|
+
const opening = /^(?:\uFEFF)?(?:[ \t]*\r?\n)*(---|\+\+\+)[ \t]*\r?\n/.exec(content);
|
|
34096
|
+
if (!opening || opening[1] !== "---")
|
|
34097
|
+
return null;
|
|
34098
|
+
const start = opening[0].length;
|
|
34099
|
+
const closing = /\n(?:---|\+\+\+)[ \t]*(\r?\n|$)/.exec(content.slice(start));
|
|
34100
|
+
return closing ? { start, end: start + closing.index } : null;
|
|
34101
|
+
}
|
|
34102
|
+
function looksLikeMarkup(text) {
|
|
34103
|
+
return /<[a-zA-Z/!]/.test(text);
|
|
34104
|
+
}
|
|
34105
|
+
function decodeJsString(raw) {
|
|
34106
|
+
let out = "";
|
|
34107
|
+
for (let i2 = 0;i2 < raw.length; i2++) {
|
|
34108
|
+
const char = raw[i2];
|
|
34109
|
+
if (char !== "\\") {
|
|
34110
|
+
out += char;
|
|
34111
|
+
continue;
|
|
34112
|
+
}
|
|
34113
|
+
const next = raw[++i2];
|
|
34114
|
+
if (next === undefined)
|
|
34115
|
+
break;
|
|
34116
|
+
if (next === "u") {
|
|
34117
|
+
if (raw[i2 + 1] === "{") {
|
|
34118
|
+
const close = raw.indexOf("}", i2 + 2);
|
|
34119
|
+
if (close !== -1) {
|
|
34120
|
+
const code2 = parseInt(raw.slice(i2 + 2, close), 16);
|
|
34121
|
+
if (!Number.isNaN(code2)) {
|
|
34122
|
+
out += String.fromCodePoint(code2);
|
|
34123
|
+
i2 = close;
|
|
34124
|
+
continue;
|
|
34125
|
+
}
|
|
34126
|
+
}
|
|
34127
|
+
}
|
|
34128
|
+
const code = parseInt(raw.slice(i2 + 1, i2 + 5), 16);
|
|
34129
|
+
if (!Number.isNaN(code)) {
|
|
34130
|
+
out += String.fromCharCode(code);
|
|
34131
|
+
i2 += 4;
|
|
34132
|
+
continue;
|
|
34133
|
+
}
|
|
34134
|
+
}
|
|
34135
|
+
if (next === "x") {
|
|
34136
|
+
const code = parseInt(raw.slice(i2 + 1, i2 + 3), 16);
|
|
34137
|
+
if (!Number.isNaN(code)) {
|
|
34138
|
+
out += String.fromCharCode(code);
|
|
34139
|
+
i2 += 2;
|
|
34140
|
+
continue;
|
|
34141
|
+
}
|
|
34142
|
+
}
|
|
34143
|
+
if (next === `
|
|
34144
|
+
`)
|
|
34145
|
+
continue;
|
|
34146
|
+
out += JS_ESCAPES[next] ?? next;
|
|
34147
|
+
}
|
|
34148
|
+
return out;
|
|
34149
|
+
}
|
|
34150
|
+
function encodeJsString(value, quote, escapeNbsp) {
|
|
34151
|
+
let out = value.replace(/\\/g, "\\\\").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t").replaceAll(quote, `\\${quote}`);
|
|
34152
|
+
if (escapeNbsp)
|
|
34153
|
+
out = out.replace(/\u00A0/g, "\\u00A0");
|
|
34154
|
+
if (quote === "`")
|
|
34155
|
+
out = out.replace(/\$\{/g, "\\${");
|
|
34156
|
+
return quote + out + quote;
|
|
34157
|
+
}
|
|
34158
|
+
function findStringLiterals(snippet) {
|
|
34159
|
+
const literals = [];
|
|
34160
|
+
for (let i2 = 0;i2 < snippet.length; i2++) {
|
|
34161
|
+
const quote = snippet[i2];
|
|
34162
|
+
if (quote !== "'" && quote !== '"' && quote !== "`")
|
|
34163
|
+
continue;
|
|
34164
|
+
let j = i2 + 1;
|
|
34165
|
+
while (j < snippet.length) {
|
|
34166
|
+
if (snippet[j] === "\\")
|
|
34167
|
+
j += 2;
|
|
34168
|
+
else if (snippet[j] === quote)
|
|
34169
|
+
break;
|
|
34170
|
+
else
|
|
34171
|
+
j++;
|
|
34172
|
+
}
|
|
34173
|
+
if (j >= snippet.length)
|
|
34174
|
+
break;
|
|
34175
|
+
const raw = snippet.slice(i2 + 1, j);
|
|
34176
|
+
literals.push({ start: i2, end: j + 1, quote, value: decodeJsString(raw) });
|
|
34177
|
+
i2 = j;
|
|
34178
|
+
}
|
|
34179
|
+
return literals;
|
|
34180
|
+
}
|
|
34181
|
+
function tryJsStringLiteralChange(sourceSnippet, resolvedOriginal, resolvedNewText) {
|
|
34182
|
+
const literals = findStringLiterals(sourceSnippet);
|
|
34183
|
+
if (literals.length === 0)
|
|
34184
|
+
return null;
|
|
34185
|
+
const splice = (start, end, replacement) => sourceSnippet.slice(0, start) + replacement + sourceSnippet.slice(end);
|
|
34186
|
+
for (const literal of literals) {
|
|
34187
|
+
if (literal.value !== resolvedOriginal)
|
|
34188
|
+
continue;
|
|
34189
|
+
const escapeNbsp = /\\u00[aA]0/.test(sourceSnippet.slice(literal.start, literal.end));
|
|
34190
|
+
return splice(literal.start, literal.end, encodeJsString(resolvedNewText, literal.quote, escapeNbsp));
|
|
34191
|
+
}
|
|
34192
|
+
for (let first = 0;first < literals.length; first++) {
|
|
34193
|
+
let combined = "";
|
|
34194
|
+
for (let last = first;last < literals.length; last++) {
|
|
34195
|
+
if (last > first) {
|
|
34196
|
+
const between = sourceSnippet.slice(literals[last - 1].end, literals[last].start);
|
|
34197
|
+
if (!/^\s*\+\s*$/.test(between))
|
|
34198
|
+
break;
|
|
34199
|
+
}
|
|
34200
|
+
combined += literals[last].value;
|
|
34201
|
+
if (last === first || combined !== resolvedOriginal)
|
|
34202
|
+
continue;
|
|
34203
|
+
const start = literals[first].start;
|
|
34204
|
+
const end = literals[last].end;
|
|
34205
|
+
const escapeNbsp = /\\u00[aA]0/.test(sourceSnippet.slice(start, end));
|
|
34206
|
+
return splice(start, end, encodeJsString(resolvedNewText, literals[first].quote, escapeNbsp));
|
|
34207
|
+
}
|
|
34208
|
+
}
|
|
34209
|
+
return null;
|
|
34210
|
+
}
|
|
34211
|
+
function pickRunAtSeam(tokens, earlier, later) {
|
|
34212
|
+
const seam = tokens.slice(earlier.index + 1, later.index).find((token) => token.startsWith("<"));
|
|
34213
|
+
return seam?.startsWith("</") ? later : earlier;
|
|
34214
|
+
}
|
|
34215
|
+
function spliceTextAcrossInlineMarkup(innerContent, originalText, newText) {
|
|
34216
|
+
const tokens = innerContent.split(/(<[^>]+>)/);
|
|
34217
|
+
const isTag = (token2) => token2.startsWith("<");
|
|
34218
|
+
const runs = [];
|
|
34219
|
+
let plain = "";
|
|
34220
|
+
for (let i2 = 0;i2 < tokens.length; i2++) {
|
|
34221
|
+
const token2 = tokens[i2];
|
|
34222
|
+
if (isTag(token2) || !token2)
|
|
34223
|
+
continue;
|
|
34224
|
+
runs.push({ index: i2, start: plain.length, end: plain.length + token2.length });
|
|
34225
|
+
plain += token2;
|
|
34226
|
+
}
|
|
34227
|
+
if (plain !== originalText)
|
|
34228
|
+
return null;
|
|
34229
|
+
let start = 0;
|
|
34230
|
+
while (start < originalText.length && start < newText.length && originalText[start] === newText[start])
|
|
34231
|
+
start++;
|
|
34232
|
+
let tail = 0;
|
|
34233
|
+
while (tail < originalText.length - start && tail < newText.length - start && originalText[originalText.length - 1 - tail] === newText[newText.length - 1 - tail])
|
|
34234
|
+
tail++;
|
|
34235
|
+
const originalEnd = originalText.length - tail;
|
|
34236
|
+
const newEnd = newText.length - tail;
|
|
34237
|
+
if (start === originalEnd && start === newEnd)
|
|
34238
|
+
return innerContent;
|
|
34239
|
+
if (start === originalEnd) {
|
|
34240
|
+
const inserted = newText.slice(start, newEnd);
|
|
34241
|
+
if (start === 0)
|
|
34242
|
+
return inserted + innerContent;
|
|
34243
|
+
if (start === originalText.length)
|
|
34244
|
+
return innerContent + inserted;
|
|
34245
|
+
}
|
|
34246
|
+
const fitting = runs.filter((r) => start >= r.start && originalEnd <= r.end);
|
|
34247
|
+
const run = start === originalEnd && fitting.length > 1 ? pickRunAtSeam(tokens, fitting[0], fitting[fitting.length - 1]) : fitting[0];
|
|
34248
|
+
if (!run)
|
|
34249
|
+
return null;
|
|
34250
|
+
const token = tokens[run.index];
|
|
34251
|
+
tokens[run.index] = token.slice(0, start - run.start) + newText.slice(start, newEnd) + token.slice(originalEnd - run.start);
|
|
34252
|
+
return tokens.join("");
|
|
34027
34253
|
}
|
|
34028
34254
|
function findTextInSnippet(snippet, decodedText) {
|
|
34029
34255
|
if (snippet.includes(decodedText)) {
|
|
34030
34256
|
return decodedText;
|
|
34031
34257
|
}
|
|
34032
|
-
|
|
34033
|
-
|
|
34034
|
-
|
|
34035
|
-
[
|
|
34036
|
-
["<", "<"],
|
|
34037
|
-
[">", ">"],
|
|
34038
|
-
['"', """],
|
|
34039
|
-
["'", "'"],
|
|
34040
|
-
["'", "'"]
|
|
34041
|
-
];
|
|
34042
|
-
let pattern = escapeRegex(decodedText);
|
|
34043
|
-
for (const [char, entity] of entityMap) {
|
|
34044
|
-
const escapedChar = escapeRegex(char);
|
|
34045
|
-
const escapedEntity = escapeRegex(entity);
|
|
34046
|
-
pattern = pattern.replace(new RegExp(escapedChar, "g"), `(?:${escapedChar}|${escapedEntity})`);
|
|
34258
|
+
let pattern = "";
|
|
34259
|
+
for (const char of decodedText) {
|
|
34260
|
+
const alternatives = ENTITY_ALTERNATIVES.get(char);
|
|
34261
|
+
pattern += alternatives ? `(?:${[char, ...alternatives].map(escapeRegex).join("|")})` : escapeRegex(char);
|
|
34047
34262
|
}
|
|
34048
34263
|
const regex = new RegExp(pattern);
|
|
34049
34264
|
const match = snippet.match(regex);
|
|
@@ -34055,11 +34270,70 @@ function findTextInSnippet(snippet, decodedText) {
|
|
|
34055
34270
|
const brMatch = snippet.match(brRegex);
|
|
34056
34271
|
return brMatch && brMatch[0] !== decodedText ? brMatch[0] : null;
|
|
34057
34272
|
}
|
|
34273
|
+
function sameCharacter(a, b2) {
|
|
34274
|
+
if (a === b2)
|
|
34275
|
+
return true;
|
|
34276
|
+
const spaceLike = (c) => c === " " || c === "\xA0";
|
|
34277
|
+
return spaceLike(a) && spaceLike(b2);
|
|
34278
|
+
}
|
|
34279
|
+
function decodeEntitiesWithOffsets(source) {
|
|
34280
|
+
const entityPattern = /&(?:#x([0-9a-f]+)|#(\d+)|([a-z]+));/iy;
|
|
34281
|
+
let text = "";
|
|
34282
|
+
const offsets = [];
|
|
34283
|
+
let i2 = 0;
|
|
34284
|
+
while (i2 < source.length) {
|
|
34285
|
+
entityPattern.lastIndex = i2;
|
|
34286
|
+
const match = entityPattern.exec(source);
|
|
34287
|
+
const decoded = match ? decodeEntityMatch(match) : undefined;
|
|
34288
|
+
offsets.push(i2);
|
|
34289
|
+
if (decoded !== undefined) {
|
|
34290
|
+
text += decoded;
|
|
34291
|
+
i2 += match[0].length;
|
|
34292
|
+
} else {
|
|
34293
|
+
text += source[i2];
|
|
34294
|
+
i2++;
|
|
34295
|
+
}
|
|
34296
|
+
}
|
|
34297
|
+
offsets.push(source.length);
|
|
34298
|
+
return { text, offsets };
|
|
34299
|
+
}
|
|
34300
|
+
function decodeEntityMatch(match) {
|
|
34301
|
+
const [, hex, dec, name] = match;
|
|
34302
|
+
if (hex)
|
|
34303
|
+
return String.fromCodePoint(parseInt(hex, 16));
|
|
34304
|
+
if (dec)
|
|
34305
|
+
return String.fromCodePoint(parseInt(dec, 10));
|
|
34306
|
+
return name ? NAMED_ENTITIES[name.toLowerCase()] : undefined;
|
|
34307
|
+
}
|
|
34308
|
+
function spliceIntoEntitySource(source, original, replacement) {
|
|
34309
|
+
const { text: decoded, offsets } = decodeEntitiesWithOffsets(source);
|
|
34310
|
+
if (decoded.length !== original.length)
|
|
34311
|
+
return null;
|
|
34312
|
+
for (let i2 = 0;i2 < decoded.length; i2++) {
|
|
34313
|
+
if (!sameCharacter(decoded[i2], original[i2]))
|
|
34314
|
+
return null;
|
|
34315
|
+
}
|
|
34316
|
+
let start = 0;
|
|
34317
|
+
while (start < original.length && start < replacement.length && sameCharacter(original[start], replacement[start])) {
|
|
34318
|
+
start++;
|
|
34319
|
+
}
|
|
34320
|
+
let tail = 0;
|
|
34321
|
+
while (tail < original.length - start && tail < replacement.length - start && sameCharacter(original[original.length - 1 - tail], replacement[replacement.length - 1 - tail]))
|
|
34322
|
+
tail++;
|
|
34323
|
+
const originalEnd = original.length - tail;
|
|
34324
|
+
const newEnd = replacement.length - tail;
|
|
34325
|
+
if (start === originalEnd && start === newEnd)
|
|
34326
|
+
return source;
|
|
34327
|
+
const head = source.slice(0, offsets[start]);
|
|
34328
|
+
const rest = source.slice(offsets[originalEnd]);
|
|
34329
|
+
return head + encodeEntitiesLike(replacement.slice(start, newEnd), source) + rest;
|
|
34330
|
+
}
|
|
34058
34331
|
function encodeEntitiesLike(text, reference) {
|
|
34059
34332
|
let result = text;
|
|
34060
34333
|
if (reference.includes("&")) {
|
|
34061
34334
|
result = result.replace(/&/g, "&");
|
|
34062
34335
|
}
|
|
34336
|
+
result = encodeNbspLike(result, reference);
|
|
34063
34337
|
if (reference.includes("<")) {
|
|
34064
34338
|
result = result.replace(/</g, "<");
|
|
34065
34339
|
}
|
|
@@ -34074,6 +34348,13 @@ function encodeEntitiesLike(text, reference) {
|
|
|
34074
34348
|
}
|
|
34075
34349
|
return result;
|
|
34076
34350
|
}
|
|
34351
|
+
function encodeNbspLike(text, reference) {
|
|
34352
|
+
if (reference.includes(" "))
|
|
34353
|
+
return text.replace(/\u00A0/g, " ");
|
|
34354
|
+
if (reference.includes(" "))
|
|
34355
|
+
return text.replace(/\u00A0/g, " ");
|
|
34356
|
+
return text;
|
|
34357
|
+
}
|
|
34077
34358
|
function resolveCmsPlaceholders(text, manifest) {
|
|
34078
34359
|
const placeholderPattern = /\{\{cms:([^}]+)\}\}/g;
|
|
34079
34360
|
return text.replace(placeholderPattern, (match, cmsId) => {
|
|
@@ -34135,24 +34416,164 @@ function getVisibleText(html) {
|
|
|
34135
34416
|
`);
|
|
34136
34417
|
return text.trim();
|
|
34137
34418
|
}
|
|
34138
|
-
function
|
|
34139
|
-
|
|
34140
|
-
|
|
34419
|
+
function findYamlTargets(sourceSnippet, allowQuotedKey) {
|
|
34420
|
+
let doc;
|
|
34421
|
+
try {
|
|
34422
|
+
doc = import_yaml6.parseDocument(sourceSnippet);
|
|
34423
|
+
if (doc.errors.length > 0)
|
|
34424
|
+
return [];
|
|
34425
|
+
} catch {
|
|
34426
|
+
return [];
|
|
34427
|
+
}
|
|
34428
|
+
const targets = [];
|
|
34429
|
+
import_yaml6.visit(doc, {
|
|
34430
|
+
Scalar(key, node, path13) {
|
|
34431
|
+
if (key === "key" || !node.range)
|
|
34432
|
+
return;
|
|
34433
|
+
if (typeof node.value !== "string" && typeof node.value !== "number")
|
|
34434
|
+
return;
|
|
34435
|
+
const parent = path13[path13.length - 1];
|
|
34436
|
+
const pair = key === "value" && parent && "key" in parent ? parent : null;
|
|
34437
|
+
if (!allowQuotedKey && (pair ? pair.key?.type !== "PLAIN" : node.type !== "PLAIN"))
|
|
34438
|
+
return;
|
|
34439
|
+
const ownerStart = pair ? pair.key.range[0] : dashBefore(sourceSnippet, node.range[0]);
|
|
34440
|
+
const [start, end] = node.range;
|
|
34441
|
+
const value = node.value;
|
|
34442
|
+
const trailingCr = typeof value === "string" && value.endsWith("\r") && sourceSnippet[end - 1] === "\r";
|
|
34443
|
+
targets.push({
|
|
34444
|
+
start,
|
|
34445
|
+
end: trailingCr ? end - 1 : end,
|
|
34446
|
+
value: trailingCr ? value.slice(0, -1) : value,
|
|
34447
|
+
key: pair ? String(pair.key.value) : null,
|
|
34448
|
+
ownerColumn: columnOf(sourceSnippet, ownerStart)
|
|
34449
|
+
});
|
|
34450
|
+
}
|
|
34451
|
+
});
|
|
34452
|
+
return targets;
|
|
34453
|
+
}
|
|
34454
|
+
function dashBefore(sourceSnippet, valueStart) {
|
|
34455
|
+
const dash = sourceSnippet.lastIndexOf("-", valueStart);
|
|
34456
|
+
return dash < 0 ? valueStart : dash;
|
|
34457
|
+
}
|
|
34458
|
+
function columnOf(sourceSnippet, offset) {
|
|
34459
|
+
return offset - (sourceSnippet.lastIndexOf(`
|
|
34460
|
+
`, offset - 1) + 1);
|
|
34461
|
+
}
|
|
34462
|
+
function tryYamlValueReplacement(sourceSnippet, resolvedOriginal, resolvedNewText, allowQuotedKey = false) {
|
|
34463
|
+
const matches = findYamlTargets(sourceSnippet, allowQuotedKey).filter((candidate) => String(candidate.value) === resolvedOriginal);
|
|
34464
|
+
if (matches.length !== 1)
|
|
34141
34465
|
return null;
|
|
34466
|
+
const target = matches[0];
|
|
34467
|
+
const fieldIsTyped = resolvesAsNonString(sourceSnippet.slice(target.start, target.end));
|
|
34468
|
+
const replacement = typeof target.value === "number" && YAML_PLAIN_NUMBER.test(resolvedNewText) ? resolvedNewText : serializeYamlValue(resolvedNewText, target.key, target.ownerColumn, fieldIsTyped);
|
|
34469
|
+
if (replacement === null)
|
|
34470
|
+
return null;
|
|
34471
|
+
const updated = sourceSnippet.slice(0, target.start) + replacement + sourceSnippet.slice(target.end);
|
|
34472
|
+
return yamlValueRoundTrips(updated, resolvedNewText) ? updated : null;
|
|
34473
|
+
}
|
|
34474
|
+
function yamlValueRoundTrips(updatedSnippet, expected) {
|
|
34475
|
+
return findYamlTargets(normalizeCr(updatedSnippet), true).some((target) => scalarSays(target.value, expected));
|
|
34476
|
+
}
|
|
34477
|
+
function scalarSays(actual, expected) {
|
|
34478
|
+
if (String(actual) === expected)
|
|
34479
|
+
return true;
|
|
34480
|
+
if (typeof actual !== "number")
|
|
34481
|
+
return false;
|
|
34482
|
+
const parsed = tryParseYaml(expected);
|
|
34483
|
+
return typeof parsed === "number" && parsed === actual;
|
|
34484
|
+
}
|
|
34485
|
+
function writeSnippet(content, sourceSnippet, updatedSnippet, insideYaml, expected) {
|
|
34486
|
+
if (insideYaml && !yamlSnippetSurvives(sourceSnippet, updatedSnippet, expected)) {
|
|
34487
|
+
return {
|
|
34488
|
+
success: false,
|
|
34489
|
+
error: `"${expected.substring(0, 50)}" cannot be written into this frontmatter field without breaking it`
|
|
34490
|
+
};
|
|
34491
|
+
}
|
|
34492
|
+
return { success: true, content: content.replace(sourceSnippet, escapeReplacement(updatedSnippet)) };
|
|
34493
|
+
}
|
|
34494
|
+
function yamlSnippetSurvives(sourceSnippet, updatedSnippet, expected) {
|
|
34495
|
+
const before = yamlScalars(sourceSnippet);
|
|
34496
|
+
const after = yamlScalars(updatedSnippet);
|
|
34497
|
+
if (!before || !after || before.length !== after.length)
|
|
34498
|
+
return false;
|
|
34499
|
+
let changed = 0;
|
|
34500
|
+
for (let i2 = 0;i2 < before.length; i2++) {
|
|
34501
|
+
if (before[i2].owner !== after[i2].owner)
|
|
34502
|
+
return false;
|
|
34503
|
+
const wrote = after[i2].value;
|
|
34504
|
+
if (String(before[i2].value) === String(wrote))
|
|
34505
|
+
continue;
|
|
34506
|
+
changed++;
|
|
34507
|
+
const saysIt = expected === "" ? wrote === "" : scalarSays(wrote, expected) || String(wrote).includes(expected);
|
|
34508
|
+
if (!saysIt)
|
|
34509
|
+
return false;
|
|
34510
|
+
}
|
|
34511
|
+
return changed > 0;
|
|
34512
|
+
}
|
|
34513
|
+
function yamlScalars(snippet) {
|
|
34142
34514
|
try {
|
|
34143
|
-
const
|
|
34144
|
-
if (
|
|
34515
|
+
const doc = import_yaml6.parseDocument(normalizeCr(snippet));
|
|
34516
|
+
if (doc.errors.length > 0)
|
|
34145
34517
|
return null;
|
|
34146
|
-
const
|
|
34147
|
-
|
|
34148
|
-
|
|
34149
|
-
|
|
34518
|
+
const scalars = [];
|
|
34519
|
+
import_yaml6.visit(doc, {
|
|
34520
|
+
Scalar(key, node) {
|
|
34521
|
+
scalars.push({ owner: String(key), value: node.value });
|
|
34522
|
+
}
|
|
34523
|
+
});
|
|
34524
|
+
return scalars;
|
|
34525
|
+
} catch {
|
|
34526
|
+
return null;
|
|
34527
|
+
}
|
|
34528
|
+
}
|
|
34529
|
+
function normalizeCr(snippet) {
|
|
34530
|
+
return snippet.replace(/\r(?=\n|$)/g, "");
|
|
34531
|
+
}
|
|
34532
|
+
function serializeYamlValue(value, key, ownerColumn, fieldIsTyped = false) {
|
|
34533
|
+
let body = renderYamlValue(value, key, undefined);
|
|
34534
|
+
if (!fieldIsTyped && body !== null && !body.includes(`
|
|
34535
|
+
`) && resolvesAsNonString(body)) {
|
|
34536
|
+
body = renderYamlValue(value, key, "QUOTE_DOUBLE");
|
|
34537
|
+
}
|
|
34538
|
+
if (body === null || !body.includes(`
|
|
34539
|
+
`))
|
|
34540
|
+
return body;
|
|
34541
|
+
const pad = " ".repeat(ownerColumn);
|
|
34542
|
+
const [header, ...rest] = body.split(`
|
|
34543
|
+
`);
|
|
34544
|
+
return [header, ...rest.map((line) => line === "" ? line : pad + line)].join(`
|
|
34545
|
+
`);
|
|
34546
|
+
}
|
|
34547
|
+
function renderYamlValue(value, key, defaultStringType) {
|
|
34548
|
+
const options = { lineWidth: 0, ...defaultStringType ? { defaultStringType, defaultKeyType: "PLAIN" } : {} };
|
|
34549
|
+
const rendered = key === null ? import_yaml6.stringify([value], options) : import_yaml6.stringify({ [key]: value }, options);
|
|
34550
|
+
let valueStart;
|
|
34551
|
+
try {
|
|
34552
|
+
const doc = import_yaml6.parseDocument(rendered);
|
|
34553
|
+
const first = doc.contents?.items?.[0];
|
|
34554
|
+
const node = key === null ? first : first?.value;
|
|
34555
|
+
if (!node?.range)
|
|
34150
34556
|
return null;
|
|
34557
|
+
valueStart = node.range[0];
|
|
34151
34558
|
} catch {
|
|
34152
34559
|
return null;
|
|
34153
34560
|
}
|
|
34154
|
-
const
|
|
34155
|
-
return
|
|
34561
|
+
const text = rendered.slice(valueStart);
|
|
34562
|
+
return /^[|>]\d*\+/.test(text) ? text : text.replace(/\n$/, "");
|
|
34563
|
+
}
|
|
34564
|
+
function resolvesAsNonString(scalar) {
|
|
34565
|
+
try {
|
|
34566
|
+
return typeof import_yaml6.parse(scalar, { version: "1.1" }) !== "string";
|
|
34567
|
+
} catch {
|
|
34568
|
+
return false;
|
|
34569
|
+
}
|
|
34570
|
+
}
|
|
34571
|
+
function tryParseYaml(text) {
|
|
34572
|
+
try {
|
|
34573
|
+
return import_yaml6.parse(text);
|
|
34574
|
+
} catch {
|
|
34575
|
+
return;
|
|
34576
|
+
}
|
|
34156
34577
|
}
|
|
34157
34578
|
function tryDataFileValueReplacement(content, sourceSnippet, originalValue, newValue, sourceLine) {
|
|
34158
34579
|
const doubleQuoted = `"${originalValue}"`;
|
|
@@ -34168,7 +34589,7 @@ function tryDataFileValueReplacement(content, sourceSnippet, originalValue, newV
|
|
|
34168
34589
|
} else {
|
|
34169
34590
|
return null;
|
|
34170
34591
|
}
|
|
34171
|
-
const updatedSnippet = sourceSnippet.replace(quotedOriginal, quotedNew);
|
|
34592
|
+
const updatedSnippet = sourceSnippet.replace(quotedOriginal, escapeReplacement(quotedNew));
|
|
34172
34593
|
if (updatedSnippet === sourceSnippet)
|
|
34173
34594
|
return null;
|
|
34174
34595
|
let searchStart = 0;
|
|
@@ -34232,14 +34653,14 @@ function tryBrNormalizedChange(sourceSnippet, resolvedOriginal, resolvedNewText)
|
|
|
34232
34653
|
const leadingWs = raw.slice(0, raw.indexOf(trimmed));
|
|
34233
34654
|
const trailingWs = raw.slice(raw.indexOf(trimmed) + trimmed.length);
|
|
34234
34655
|
const newRaw = leadingWs + newSegment + trailingWs;
|
|
34235
|
-
result = result.replace(raw, newRaw);
|
|
34656
|
+
result = result.replace(raw, escapeReplacement(newRaw));
|
|
34236
34657
|
break;
|
|
34237
34658
|
}
|
|
34238
34659
|
}
|
|
34239
34660
|
}
|
|
34240
34661
|
return result !== sourceSnippet ? result : null;
|
|
34241
34662
|
}
|
|
34242
|
-
var import_node_html_parser, import_yaml6, ASSET_IMPORT_EXT_RE, REMOTE_FETCH_TIMEOUT_MS = 15000, REMOTE_FETCH_MAX_BYTES, QUOTED_LITERAL_DELIMITERS;
|
|
34663
|
+
var import_node_html_parser, import_yaml6, ASSET_IMPORT_EXT_RE, REMOTE_FETCH_TIMEOUT_MS = 15000, REMOTE_FETCH_MAX_BYTES, QUOTED_LITERAL_DELIMITERS, JAVASCRIPT_SOURCE, YAML_DOCUMENT_SOURCE, YAML_FRONTMATTER_SOURCE, JS_ESCAPES, ENTITY_ALTERNATIVES, NAMED_ENTITIES, YAML_PLAIN_NUMBER;
|
|
34243
34664
|
var init_source_writer = __esm(() => {
|
|
34244
34665
|
init_astro_image_paths();
|
|
34245
34666
|
init_config();
|
|
@@ -34250,6 +34671,37 @@ var init_source_writer = __esm(() => {
|
|
|
34250
34671
|
ASSET_IMPORT_EXT_RE = /\.(jpe?g|png|gif|webp|avif|svg|ico|bmp|tiff?)$/i;
|
|
34251
34672
|
REMOTE_FETCH_MAX_BYTES = 50 * 1024 * 1024;
|
|
34252
34673
|
QUOTED_LITERAL_DELIMITERS = [`'`, `"`, "`"];
|
|
34674
|
+
JAVASCRIPT_SOURCE = /\.(astro|[cm]?[jt]sx?)$/i;
|
|
34675
|
+
YAML_DOCUMENT_SOURCE = /\.ya?ml$/i;
|
|
34676
|
+
YAML_FRONTMATTER_SOURCE = /\.(md|mdx|markdown)$/i;
|
|
34677
|
+
JS_ESCAPES = {
|
|
34678
|
+
n: `
|
|
34679
|
+
`,
|
|
34680
|
+
r: "\r",
|
|
34681
|
+
t: "\t",
|
|
34682
|
+
b: "\b",
|
|
34683
|
+
f: "\f",
|
|
34684
|
+
v: "\v",
|
|
34685
|
+
0: "\x00"
|
|
34686
|
+
};
|
|
34687
|
+
ENTITY_ALTERNATIVES = new Map([
|
|
34688
|
+
["&", ["&"]],
|
|
34689
|
+
["\xA0", [" ", " ", " "]],
|
|
34690
|
+
[" ", [" ", " "]],
|
|
34691
|
+
["<", ["<"]],
|
|
34692
|
+
[">", [">"]],
|
|
34693
|
+
['"', ["""]],
|
|
34694
|
+
["'", ["'", "'"]]
|
|
34695
|
+
]);
|
|
34696
|
+
NAMED_ENTITIES = {
|
|
34697
|
+
amp: "&",
|
|
34698
|
+
lt: "<",
|
|
34699
|
+
gt: ">",
|
|
34700
|
+
quot: '"',
|
|
34701
|
+
apos: "'",
|
|
34702
|
+
nbsp: "\xA0"
|
|
34703
|
+
};
|
|
34704
|
+
YAML_PLAIN_NUMBER = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/;
|
|
34253
34705
|
});
|
|
34254
34706
|
|
|
34255
34707
|
// ../cms/src/handlers/api-routes.ts
|