mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-04-02 20:09:00 +08:00
feat(game): 添加游戏内容配置系统和VS Code插件支持
- 实现YAML配置文件管理和JSON Schema验证功能 - 提供运行时只读查询和Source Generator代码生成功能 - 开发VS Code插件实现配置浏览、校验和轻量表单编辑 - 支持开发期热重载和配置变更自动刷新机制 - 集成诊断功能提供配置文件错误提示和修复建议
This commit is contained in:
parent
e8d0ea2daf
commit
0c662ced2a
@ -144,7 +144,7 @@ var hotReload = loader.EnableHotReload(
|
|||||||
- 打开 raw YAML 文件
|
- 打开 raw YAML 文件
|
||||||
- 打开匹配的 schema 文件
|
- 打开匹配的 schema 文件
|
||||||
- 对必填字段、未知顶层字段、基础标量类型和标量数组元素做轻量校验
|
- 对必填字段、未知顶层字段、基础标量类型和标量数组元素做轻量校验
|
||||||
- 对顶层标量字段提供轻量表单入口
|
- 对顶层标量字段和顶层标量数组提供轻量表单入口
|
||||||
|
|
||||||
当前仍建议把复杂数组、嵌套对象和批量修改放在 raw YAML 中完成。
|
当前仍建议把复杂数组、嵌套对象和批量修改放在 raw YAML 中完成。
|
||||||
|
|
||||||
@ -154,6 +154,6 @@ var hotReload = loader.EnableHotReload(
|
|||||||
|
|
||||||
- 跨表引用校验
|
- 跨表引用校验
|
||||||
- 更完整的 JSON Schema 支持
|
- 更完整的 JSON Schema 支持
|
||||||
- 更强的 VS Code 表单编辑器
|
- 更强的 VS Code 嵌套对象与复杂数组编辑器
|
||||||
|
|
||||||
因此,现阶段更适合作为你游戏项目的“受控试点配表系统”,而不是完全无约束的大规模内容生产平台。
|
因此,现阶段更适合作为你游戏项目的“受控试点配表系统”,而不是完全无约束的大规模内容生产平台。
|
||||||
|
|||||||
@ -8,7 +8,7 @@ Minimal VS Code extension scaffold for the GFramework AI-First config workflow.
|
|||||||
- Open raw YAML files
|
- Open raw YAML files
|
||||||
- Open matching schema files from `schemas/`
|
- Open matching schema files from `schemas/`
|
||||||
- Run lightweight schema validation for required fields, unknown top-level fields, scalar types, and scalar array items
|
- Run lightweight schema validation for required fields, unknown top-level fields, scalar types, and scalar array items
|
||||||
- Open a lightweight form preview for top-level scalar fields
|
- Open a lightweight form preview for top-level scalar fields and top-level scalar arrays
|
||||||
|
|
||||||
## Validation Coverage
|
## Validation Coverage
|
||||||
|
|
||||||
@ -32,8 +32,8 @@ node --test ./test/*.test.js
|
|||||||
|
|
||||||
- Multi-root workspaces use the first workspace folder
|
- Multi-root workspaces use the first workspace folder
|
||||||
- Validation only covers a minimal subset of JSON Schema
|
- Validation only covers a minimal subset of JSON Schema
|
||||||
- Form editing currently supports top-level scalar fields only
|
- Form editing currently supports top-level scalar fields and top-level scalar arrays
|
||||||
- Arrays and nested objects should still be edited in raw YAML
|
- Nested objects and complex arrays should still be edited in raw YAML
|
||||||
|
|
||||||
## Workspace Settings
|
## Workspace Settings
|
||||||
|
|
||||||
|
|||||||
@ -227,44 +227,85 @@ function isScalarCompatible(expectedType, scalarValue) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply scalar field updates back into the original YAML text.
|
* Apply form field updates back into the original YAML text.
|
||||||
|
* The current form editor supports top-level scalar fields and top-level scalar
|
||||||
|
* arrays, while nested objects and complex arrays remain raw-YAML-only.
|
||||||
|
*
|
||||||
|
* @param {string} originalYaml Original YAML content.
|
||||||
|
* @param {{scalars?: Record<string, string>, arrays?: Record<string, string[]>}} updates Updated form values.
|
||||||
|
* @returns {string} Updated YAML content.
|
||||||
|
*/
|
||||||
|
function applyFormUpdates(originalYaml, updates) {
|
||||||
|
const lines = originalYaml.split(/\r?\n/u);
|
||||||
|
const scalarUpdates = updates.scalars || {};
|
||||||
|
const arrayUpdates = updates.arrays || {};
|
||||||
|
const touchedScalarKeys = new Set();
|
||||||
|
const touchedArrayKeys = new Set();
|
||||||
|
const blocks = findTopLevelBlocks(lines);
|
||||||
|
const updatedLines = [];
|
||||||
|
let cursor = 0;
|
||||||
|
|
||||||
|
for (const block of blocks) {
|
||||||
|
while (cursor < block.start) {
|
||||||
|
updatedLines.push(lines[cursor]);
|
||||||
|
cursor += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.prototype.hasOwnProperty.call(scalarUpdates, block.key)) {
|
||||||
|
touchedScalarKeys.add(block.key);
|
||||||
|
updatedLines.push(renderScalarLine(block.key, scalarUpdates[block.key]));
|
||||||
|
cursor = block.end + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.prototype.hasOwnProperty.call(arrayUpdates, block.key)) {
|
||||||
|
touchedArrayKeys.add(block.key);
|
||||||
|
updatedLines.push(...renderArrayBlock(block.key, arrayUpdates[block.key]));
|
||||||
|
cursor = block.end + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (cursor <= block.end) {
|
||||||
|
updatedLines.push(lines[cursor]);
|
||||||
|
cursor += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (cursor < lines.length) {
|
||||||
|
updatedLines.push(lines[cursor]);
|
||||||
|
cursor += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(scalarUpdates)) {
|
||||||
|
if (touchedScalarKeys.has(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedLines.push(renderScalarLine(key, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(arrayUpdates)) {
|
||||||
|
if (touchedArrayKeys.has(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedLines.push(...renderArrayBlock(key, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return updatedLines.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply only scalar updates back into the original YAML text.
|
||||||
|
* This helper is preserved for compatibility with existing tests and callers
|
||||||
|
* that only edit top-level scalar fields.
|
||||||
*
|
*
|
||||||
* @param {string} originalYaml Original YAML content.
|
* @param {string} originalYaml Original YAML content.
|
||||||
* @param {Record<string, string>} updates Updated scalar values.
|
* @param {Record<string, string>} updates Updated scalar values.
|
||||||
* @returns {string} Updated YAML content.
|
* @returns {string} Updated YAML content.
|
||||||
*/
|
*/
|
||||||
function applyScalarUpdates(originalYaml, updates) {
|
function applyScalarUpdates(originalYaml, updates) {
|
||||||
const lines = originalYaml.split(/\r?\n/u);
|
return applyFormUpdates(originalYaml, {scalars: updates});
|
||||||
const touched = new Set();
|
|
||||||
|
|
||||||
const updatedLines = lines.map((line) => {
|
|
||||||
if (/^\s/u.test(line)) {
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
const match = /^([A-Za-z0-9_]+):(?:\s*(.*))?$/u.exec(line);
|
|
||||||
if (!match) {
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
const key = match[1];
|
|
||||||
if (!Object.prototype.hasOwnProperty.call(updates, key)) {
|
|
||||||
return line;
|
|
||||||
}
|
|
||||||
|
|
||||||
touched.add(key);
|
|
||||||
return `${key}: ${formatYamlScalar(updates[key])}`;
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(updates)) {
|
|
||||||
if (touched.has(key)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
updatedLines.push(`${key}: ${formatYamlScalar(value)}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return updatedLines.join("\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -329,8 +370,90 @@ function parseTopLevelArray(childLines) {
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find top-level YAML blocks so form updates can replace whole entries without
|
||||||
|
* touching unrelated domains in the file.
|
||||||
|
*
|
||||||
|
* @param {string[]} lines YAML lines.
|
||||||
|
* @returns {Array<{key: string, start: number, end: number}>} Top-level blocks.
|
||||||
|
*/
|
||||||
|
function findTopLevelBlocks(lines) {
|
||||||
|
const blocks = [];
|
||||||
|
|
||||||
|
for (let index = 0; index < lines.length; index += 1) {
|
||||||
|
const line = lines[index];
|
||||||
|
if (!line || line.trim().length === 0 || line.trim().startsWith("#") || /^\s/u.test(line)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const match = /^([A-Za-z0-9_]+):(?:\s*(.*))?$/u.exec(line);
|
||||||
|
if (!match) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cursor = index + 1;
|
||||||
|
while (cursor < lines.length) {
|
||||||
|
const nextLine = lines[cursor];
|
||||||
|
if (nextLine.trim().length === 0 || nextLine.trim().startsWith("#")) {
|
||||||
|
cursor += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!/^\s/u.test(nextLine)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
blocks.push({
|
||||||
|
key: match[1],
|
||||||
|
start: index,
|
||||||
|
end: cursor - 1
|
||||||
|
});
|
||||||
|
index = cursor - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render a top-level scalar line.
|
||||||
|
*
|
||||||
|
* @param {string} key Property name.
|
||||||
|
* @param {string} value Scalar value.
|
||||||
|
* @returns {string} Rendered YAML line.
|
||||||
|
*/
|
||||||
|
function renderScalarLine(key, value) {
|
||||||
|
return `${key}: ${formatYamlScalar(value)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render a top-level scalar array block.
|
||||||
|
*
|
||||||
|
* @param {string} key Property name.
|
||||||
|
* @param {string[]} items Array items.
|
||||||
|
* @returns {string[]} Rendered YAML lines.
|
||||||
|
*/
|
||||||
|
function renderArrayBlock(key, items) {
|
||||||
|
const normalizedItems = Array.isArray(items)
|
||||||
|
? items
|
||||||
|
.map((item) => String(item).trim())
|
||||||
|
.filter((item) => item.length > 0)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const lines = [`${key}:`];
|
||||||
|
for (const item of normalizedItems) {
|
||||||
|
lines.push(` - ${formatYamlScalar(item)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
applyFormUpdates,
|
||||||
applyScalarUpdates,
|
applyScalarUpdates,
|
||||||
|
findTopLevelBlocks,
|
||||||
formatYamlScalar,
|
formatYamlScalar,
|
||||||
isScalarCompatible,
|
isScalarCompatible,
|
||||||
parseSchemaContent,
|
parseSchemaContent,
|
||||||
|
|||||||
@ -2,7 +2,7 @@ const fs = require("fs");
|
|||||||
const path = require("path");
|
const path = require("path");
|
||||||
const vscode = require("vscode");
|
const vscode = require("vscode");
|
||||||
const {
|
const {
|
||||||
applyScalarUpdates,
|
applyFormUpdates,
|
||||||
parseSchemaContent,
|
parseSchemaContent,
|
||||||
parseTopLevelYaml,
|
parseTopLevelYaml,
|
||||||
unquoteScalar,
|
unquoteScalar,
|
||||||
@ -247,9 +247,9 @@ async function openSchemaFile(item) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a lightweight form preview for top-level scalar fields.
|
* Open a lightweight form preview for top-level scalar fields and scalar
|
||||||
* The editor intentionally edits only simple scalar keys and keeps raw YAML as
|
* arrays. Nested objects and more complex array shapes still use raw YAML as
|
||||||
* the escape hatch for arrays, nested objects, and advanced changes.
|
* the escape hatch.
|
||||||
*
|
*
|
||||||
* @param {ConfigTreeItem | { resourceUri?: vscode.Uri }} item Tree item.
|
* @param {ConfigTreeItem | { resourceUri?: vscode.Uri }} item Tree item.
|
||||||
* @param {vscode.DiagnosticCollection} diagnostics Diagnostic collection.
|
* @param {vscode.DiagnosticCollection} diagnostics Diagnostic collection.
|
||||||
@ -279,7 +279,10 @@ async function openFormPreview(item, diagnostics) {
|
|||||||
|
|
||||||
panel.webview.onDidReceiveMessage(async (message) => {
|
panel.webview.onDidReceiveMessage(async (message) => {
|
||||||
if (message.type === "save") {
|
if (message.type === "save") {
|
||||||
const updatedYaml = applyScalarUpdates(yamlText, message.values || {});
|
const updatedYaml = applyFormUpdates(yamlText, {
|
||||||
|
scalars: message.scalars || {},
|
||||||
|
arrays: parseArrayFieldPayload(message.arrays || {})
|
||||||
|
});
|
||||||
await fs.promises.writeFile(configUri.fsPath, updatedYaml, "utf8");
|
await fs.promises.writeFile(configUri.fsPath, updatedYaml, "utf8");
|
||||||
const document = await vscode.workspace.openTextDocument(configUri);
|
const document = await vscode.workspace.openTextDocument(configUri);
|
||||||
await document.save();
|
await document.save();
|
||||||
@ -409,7 +412,7 @@ async function loadSchemaInfoForConfig(configUri, workspaceRoot) {
|
|||||||
* @returns {string} HTML string.
|
* @returns {string} HTML string.
|
||||||
*/
|
*/
|
||||||
function renderFormHtml(fileName, schemaInfo, parsedYaml) {
|
function renderFormHtml(fileName, schemaInfo, parsedYaml) {
|
||||||
const fields = Array.from(parsedYaml.entries.entries())
|
const scalarFields = Array.from(parsedYaml.entries.entries())
|
||||||
.filter(([, entry]) => entry.kind === "scalar")
|
.filter(([, entry]) => entry.kind === "scalar")
|
||||||
.map(([key, entry]) => {
|
.map(([key, entry]) => {
|
||||||
const escapedKey = escapeHtml(key);
|
const escapedKey = escapeHtml(key);
|
||||||
@ -424,13 +427,48 @@ function renderFormHtml(fileName, schemaInfo, parsedYaml) {
|
|||||||
})
|
})
|
||||||
.join("\n");
|
.join("\n");
|
||||||
|
|
||||||
|
const arrayFields = Array.from(parsedYaml.entries.entries())
|
||||||
|
.filter(([, entry]) => entry.kind === "array")
|
||||||
|
.map(([key, entry]) => {
|
||||||
|
const escapedKey = escapeHtml(key);
|
||||||
|
const escapedValue = escapeHtml((entry.items || [])
|
||||||
|
.map((item) => unquoteScalar(item.raw))
|
||||||
|
.join("\n"));
|
||||||
|
const required = schemaInfo.required.includes(key) ? "<span class=\"badge\">required</span>" : "";
|
||||||
|
const itemType = schemaInfo.properties[key] && schemaInfo.properties[key].itemType
|
||||||
|
? `array<${escapeHtml(schemaInfo.properties[key].itemType)}>`
|
||||||
|
: "array";
|
||||||
|
|
||||||
|
return `
|
||||||
|
<label class="field">
|
||||||
|
<span class="label">${escapedKey} ${required}</span>
|
||||||
|
<span class="hint">One item per line. Expected type: ${itemType}</span>
|
||||||
|
<textarea data-array-key="${escapedKey}" rows="5">${escapedValue}</textarea>
|
||||||
|
</label>
|
||||||
|
`;
|
||||||
|
})
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
const unsupportedFields = Array.from(parsedYaml.entries.entries())
|
||||||
|
.filter(([, entry]) => entry.kind !== "scalar" && entry.kind !== "array")
|
||||||
|
.map(([key, entry]) => `
|
||||||
|
<div class="unsupported">
|
||||||
|
<strong>${escapeHtml(key)}</strong>: ${escapeHtml(entry.kind)} fields are currently raw-YAML-only.
|
||||||
|
</div>
|
||||||
|
`)
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
const schemaStatus = schemaInfo.exists
|
const schemaStatus = schemaInfo.exists
|
||||||
? `Schema: ${escapeHtml(schemaInfo.schemaPath)}`
|
? `Schema: ${escapeHtml(schemaInfo.schemaPath)}`
|
||||||
: `Schema missing: ${escapeHtml(schemaInfo.schemaPath)}`;
|
: `Schema missing: ${escapeHtml(schemaInfo.schemaPath)}`;
|
||||||
|
|
||||||
const emptyState = fields.length > 0
|
const editableContent = [scalarFields, arrayFields].filter((content) => content.length > 0).join("\n");
|
||||||
? fields
|
const unsupportedSection = unsupportedFields.length > 0
|
||||||
: "<p>No editable top-level scalar fields were detected. Use raw YAML for nested objects or arrays.</p>";
|
? `<div class="unsupported-list">${unsupportedFields}</div>`
|
||||||
|
: "";
|
||||||
|
const emptyState = editableContent.length > 0
|
||||||
|
? `${editableContent}${unsupportedSection}`
|
||||||
|
: "<p>No editable top-level scalar or scalar-array fields were detected. Use raw YAML for nested objects or complex arrays.</p>";
|
||||||
|
|
||||||
return `<!DOCTYPE html>
|
return `<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
@ -477,6 +515,22 @@ function renderFormHtml(fileName, schemaInfo, parsedYaml) {
|
|||||||
background: var(--vscode-input-background);
|
background: var(--vscode-input-background);
|
||||||
color: var(--vscode-input-foreground);
|
color: var(--vscode-input-foreground);
|
||||||
}
|
}
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid var(--vscode-input-border, transparent);
|
||||||
|
background: var(--vscode-input-background);
|
||||||
|
color: var(--vscode-input-foreground);
|
||||||
|
font-family: var(--vscode-editor-font-family, var(--vscode-font-family));
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
.hint {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
color: var(--vscode-descriptionForeground);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
.badge {
|
.badge {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
@ -486,11 +540,20 @@ function renderFormHtml(fileName, schemaInfo, parsedYaml) {
|
|||||||
color: var(--vscode-badge-foreground);
|
color: var(--vscode-badge-foreground);
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
}
|
}
|
||||||
|
.unsupported-list {
|
||||||
|
margin-top: 20px;
|
||||||
|
border-top: 1px solid var(--vscode-panel-border, transparent);
|
||||||
|
padding-top: 16px;
|
||||||
|
}
|
||||||
|
.unsupported {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
color: var(--vscode-descriptionForeground);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<button id="save">Save Scalars</button>
|
<button id="save">Save Form</button>
|
||||||
<button id="openRaw">Open Raw YAML</button>
|
<button id="openRaw">Open Raw YAML</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
@ -501,11 +564,15 @@ function renderFormHtml(fileName, schemaInfo, parsedYaml) {
|
|||||||
<script>
|
<script>
|
||||||
const vscode = acquireVsCodeApi();
|
const vscode = acquireVsCodeApi();
|
||||||
document.getElementById("save").addEventListener("click", () => {
|
document.getElementById("save").addEventListener("click", () => {
|
||||||
const values = {};
|
const scalars = {};
|
||||||
|
const arrays = {};
|
||||||
for (const input of document.querySelectorAll("input[data-key]")) {
|
for (const input of document.querySelectorAll("input[data-key]")) {
|
||||||
values[input.dataset.key] = input.value;
|
scalars[input.dataset.key] = input.value;
|
||||||
}
|
}
|
||||||
vscode.postMessage({ type: "save", values });
|
for (const textarea of document.querySelectorAll("textarea[data-array-key]")) {
|
||||||
|
arrays[textarea.dataset.arrayKey] = textarea.value;
|
||||||
|
}
|
||||||
|
vscode.postMessage({ type: "save", scalars, arrays });
|
||||||
});
|
});
|
||||||
document.getElementById("openRaw").addEventListener("click", () => {
|
document.getElementById("openRaw").addEventListener("click", () => {
|
||||||
vscode.postMessage({ type: "openRaw" });
|
vscode.postMessage({ type: "openRaw" });
|
||||||
@ -638,6 +705,25 @@ function escapeHtml(value) {
|
|||||||
.replace(/'/gu, "'");
|
.replace(/'/gu, "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert raw textarea payloads into scalar-array items.
|
||||||
|
*
|
||||||
|
* @param {Record<string, string>} arrays Raw array editor payload.
|
||||||
|
* @returns {Record<string, string[]>} Parsed array updates.
|
||||||
|
*/
|
||||||
|
function parseArrayFieldPayload(arrays) {
|
||||||
|
const parsed = {};
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(arrays)) {
|
||||||
|
parsed[key] = String(value)
|
||||||
|
.split(/\r?\n/u)
|
||||||
|
.map((item) => item.trim())
|
||||||
|
.filter((item) => item.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
activate,
|
activate,
|
||||||
deactivate
|
deactivate
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
const test = require("node:test");
|
const test = require("node:test");
|
||||||
const assert = require("node:assert/strict");
|
const assert = require("node:assert/strict");
|
||||||
const {
|
const {
|
||||||
|
applyFormUpdates,
|
||||||
applyScalarUpdates,
|
applyScalarUpdates,
|
||||||
parseSchemaContent,
|
parseSchemaContent,
|
||||||
parseTopLevelYaml,
|
parseTopLevelYaml,
|
||||||
@ -109,3 +110,31 @@ test("applyScalarUpdates should update top-level scalars and append new keys", (
|
|||||||
assert.match(updated, /^hp: 25$/mu);
|
assert.match(updated, /^hp: 25$/mu);
|
||||||
assert.match(updated, /^ - 1$/mu);
|
assert.match(updated, /^ - 1$/mu);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("applyFormUpdates should replace top-level scalar arrays and preserve unrelated content", () => {
|
||||||
|
const updated = applyFormUpdates(
|
||||||
|
[
|
||||||
|
"id: 1",
|
||||||
|
"name: Slime",
|
||||||
|
"dropItems:",
|
||||||
|
" - potion",
|
||||||
|
" - slime_gel",
|
||||||
|
"reward:",
|
||||||
|
" gold: 10"
|
||||||
|
].join("\n"),
|
||||||
|
{
|
||||||
|
scalars: {
|
||||||
|
name: "Goblin"
|
||||||
|
},
|
||||||
|
arrays: {
|
||||||
|
dropItems: ["bomb", "hi potion"]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.match(updated, /^name: Goblin$/mu);
|
||||||
|
assert.match(updated, /^dropItems:$/mu);
|
||||||
|
assert.match(updated, /^ - bomb$/mu);
|
||||||
|
assert.match(updated, /^ - hi potion$/mu);
|
||||||
|
assert.match(updated, /^reward:$/mu);
|
||||||
|
assert.match(updated, /^ gold: 10$/mu);
|
||||||
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user