@abco20/btxml-checker 0.1.4 → 0.1.5

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/server.cjs CHANGED
@@ -34993,6 +34993,7 @@ var RuleCodes = {
34993
34993
  ConflictingModelKind: "BT120_CONFLICTING_MODEL_KIND",
34994
34994
  UnusedModelDefinition: "BT121_UNUSED_MODEL_DEFINITION",
34995
34995
  DuplicateModelDefinition: "BT122_DUPLICATE_MODEL_DEFINITION",
34996
+ MissingLocalModelDefinition: "BT123_MISSING_LOCAL_MODEL_DEFINITION",
34996
34997
  ExternalModelFileNotFound: "BT321_EXTERNAL_MODEL_FILE_NOT_FOUND",
34997
34998
  AugmentationFileNotFound: "BT324_AUGMENTATION_FILE_NOT_FOUND",
34998
34999
  MissingTreeNodesModel: "BT322_MISSING_TREENODESMODEL",
@@ -35213,8 +35214,8 @@ var RULES = {
35213
35214
  },
35214
35215
  "model/require-output-port-remap": {
35215
35216
  code: RuleCodes.OutputPortRequiresRemap,
35216
- defaultSeverity: "warn",
35217
- description: "Resolved output ports must write to a blackboard remap."
35217
+ defaultSeverity: "error",
35218
+ description: "Resolved output ports must be explicitly or default-remapped to a blackboard entry."
35218
35219
  },
35219
35220
  "model/no-childless-control-shape-mismatch": {
35220
35221
  code: RuleCodes.ChildCapableNodeSelfClosing,
@@ -35246,6 +35247,11 @@ var RULES = {
35246
35247
  defaultSeverity: "error",
35247
35248
  description: "Inline model definitions should be used in the same BT XML file."
35248
35249
  },
35250
+ "model/require-local-definition": {
35251
+ code: RuleCodes.MissingLocalModelDefinition,
35252
+ defaultSeverity: "error",
35253
+ description: "When models.convention is used-only, normal node usages should have a local TreeNodesModel definition in the same file."
35254
+ },
35249
35255
  "model/no-duplicate-definition": {
35250
35256
  code: RuleCodes.DuplicateModelDefinition,
35251
35257
  defaultSeverity: "error",
@@ -39197,6 +39203,8 @@ async function resolveIncludeGraph(input) {
39197
39203
  var RULE_CONFLICTING_KIND = "model/no-conflicting-kind-for-id";
39198
39204
  var RULE_UNUSED_DEFINITION = "model/no-unused-definition";
39199
39205
  var RULE_DUPLICATE_DEFINITION = "model/no-duplicate-definition";
39206
+ var RULE_REQUIRE_LOCAL_DEFINITION = "model/require-local-definition";
39207
+ var NORMAL_MODEL_KINDS = /* @__PURE__ */ new Set(["Action", "Condition", "Decorator", "Control"]);
39200
39208
  function createConventionDiagnostic(input) {
39201
39209
  const diagnostic = createDiagnostic(
39202
39210
  input.code,
@@ -39234,6 +39242,30 @@ function definitionInfo(definition) {
39234
39242
  range: definition.range
39235
39243
  };
39236
39244
  }
39245
+ function isNormalModelKind(kind) {
39246
+ return NORMAL_MODEL_KINDS.has(kind);
39247
+ }
39248
+ function toFixableModel(index, id) {
39249
+ const resolved = getNodeModel(index, id);
39250
+ if (!resolved) return void 0;
39251
+ if (!isNormalModelKind(resolved.kind)) return void 0;
39252
+ const hasConflict = getModelConflicts(index).some(
39253
+ (conflict) => conflict.id === id && (conflict.code === "BT012_CONFLICTING_NODE_MODEL" || conflict.code === "BT107_CONFLICTING_PORT_DEFAULT")
39254
+ );
39255
+ if (hasConflict) return void 0;
39256
+ return {
39257
+ id: resolved.id,
39258
+ kind: resolved.kind,
39259
+ ports: resolved.ports.map((port) => ({
39260
+ direction: port.direction,
39261
+ name: port.name,
39262
+ type: port.type,
39263
+ defaultValue: port.defaultValue,
39264
+ description: port.description,
39265
+ enum: port.enum
39266
+ }))
39267
+ };
39268
+ }
39237
39269
  function validateConflictingKinds(input) {
39238
39270
  const severity = resolveConventionSeverity(input.config, RULE_CONFLICTING_KIND);
39239
39271
  if (!severity) return [];
@@ -39277,17 +39309,75 @@ function validateConflictingKinds(input) {
39277
39309
  function validateUsedOnly(input) {
39278
39310
  if (input.config.models.convention !== "used-only") return [];
39279
39311
  const severity = resolveConventionSeverity(input.config, RULE_UNUSED_DEFINITION);
39280
- if (!severity) return [];
39312
+ const missingSeverity = resolveConventionSeverity(input.config, RULE_REQUIRE_LOCAL_DEFINITION);
39313
+ if (!severity && !missingSeverity) return [];
39281
39314
  const diagnostics = [];
39282
39315
  const usagesByUri = getNodeUsagesByUri(input.index);
39283
- for (const definition of input.facts) {
39284
- if (definition.isBuiltin) continue;
39316
+ const allInlineByUri = buildAllInlineDefinitionsByUri(input.facts);
39317
+ const localNormalByUri = buildLocalNormalDefinitionsByUri(input.facts);
39318
+ const relevantUris = /* @__PURE__ */ new Set([
39319
+ ...usagesByUri.keys(),
39320
+ ...localNormalByUri.keys(),
39321
+ ...allInlineByUri.keys()
39322
+ ]);
39323
+ for (const uri of relevantUris) {
39324
+ const sameFileNodeUsages = usagesByUri.get(uri) ?? [];
39325
+ const usedNodeIds = getUsedNodeIds(sameFileNodeUsages);
39326
+ const localNormalDefinitions = localNormalByUri.get(uri) ?? [];
39327
+ const localNormalIds = new Set(localNormalDefinitions.map((definition) => definition.id));
39328
+ const localAnyIds = new Set((allInlineByUri.get(uri) ?? []).map((definition) => definition.id));
39329
+ if (severity) {
39330
+ diagnostics.push(
39331
+ ...createUnusedDefinitionDiagnostics(localNormalDefinitions, usedNodeIds, severity)
39332
+ );
39333
+ }
39334
+ if (missingSeverity) {
39335
+ diagnostics.push(
39336
+ ...createMissingLocalDefinitionDiagnostics({
39337
+ index: input.index,
39338
+ uri,
39339
+ usedNodeIds,
39340
+ localNormalIds,
39341
+ localAnyIds,
39342
+ sameFileNodeUsages,
39343
+ severity: missingSeverity
39344
+ })
39345
+ );
39346
+ }
39347
+ }
39348
+ return diagnostics;
39349
+ }
39350
+ function buildAllInlineDefinitionsByUri(facts) {
39351
+ const allInlineByUri = /* @__PURE__ */ new Map();
39352
+ for (const definition of facts) {
39285
39353
  if (definition.sourceKind !== "inline-tree-nodes-model") continue;
39286
- if (definition.kind === "SubTree") continue;
39287
- const sameFileNodeUsages = usagesByUri.get(definition.uri ?? "") ?? [];
39288
- const usedNodeIds = new Set(
39289
- sameFileNodeUsages.filter((usage) => usage.kind === "node").map((usage) => usage.id)
39290
- );
39354
+ if (!definition.uri) continue;
39355
+ const allInline = allInlineByUri.get(definition.uri) ?? [];
39356
+ allInline.push(definition);
39357
+ allInlineByUri.set(definition.uri, allInline);
39358
+ }
39359
+ return allInlineByUri;
39360
+ }
39361
+ function buildLocalNormalDefinitionsByUri(facts) {
39362
+ const localNormalByUri = /* @__PURE__ */ new Map();
39363
+ for (const definition of facts) {
39364
+ if (definition.sourceKind !== "inline-tree-nodes-model") continue;
39365
+ if (!definition.uri) continue;
39366
+ if (!isNormalModelKind(definition.kind)) continue;
39367
+ const localNormal = localNormalByUri.get(definition.uri) ?? [];
39368
+ localNormal.push(definition);
39369
+ localNormalByUri.set(definition.uri, localNormal);
39370
+ }
39371
+ return localNormalByUri;
39372
+ }
39373
+ function getUsedNodeIds(sameFileNodeUsages) {
39374
+ return new Set(
39375
+ sameFileNodeUsages.filter((usage) => usage.kind === "node").map((usage) => usage.id)
39376
+ );
39377
+ }
39378
+ function createUnusedDefinitionDiagnostics(localNormalDefinitions, usedNodeIds, severity) {
39379
+ const diagnostics = [];
39380
+ for (const definition of localNormalDefinitions) {
39291
39381
  if (usedNodeIds.has(definition.id)) continue;
39292
39382
  diagnostics.push(
39293
39383
  createConventionDiagnostic({
@@ -39313,6 +39403,43 @@ function validateUsedOnly(input) {
39313
39403
  }
39314
39404
  return diagnostics;
39315
39405
  }
39406
+ function createMissingLocalDefinitionDiagnostics(input) {
39407
+ const diagnostics = [];
39408
+ for (const nodeId of input.usedNodeIds) {
39409
+ if (input.localNormalIds.has(nodeId)) continue;
39410
+ const hasNormalModel = getNodeModelDefinitions(input.index, nodeId).some(
39411
+ (definition) => isNormalModelKind(definition.kind)
39412
+ );
39413
+ if (!hasNormalModel) continue;
39414
+ const hasNonNormalLocalDefinition = input.localAnyIds.has(nodeId);
39415
+ const firstUsage = input.sameFileNodeUsages.find(
39416
+ (usage) => usage.kind === "node" && usage.id === nodeId
39417
+ );
39418
+ const fixableModel = hasNonNormalLocalDefinition ? void 0 : toFixableModel(input.index, nodeId);
39419
+ diagnostics.push(
39420
+ createConventionDiagnostic({
39421
+ code: "BT123_MISSING_LOCAL_MODEL_DEFINITION",
39422
+ message: `missing local model definition \`${nodeId}\` in this file`,
39423
+ uri: input.uri,
39424
+ range: firstUsage?.elementRange ?? firstUsage?.range,
39425
+ rule: RULE_REQUIRE_LOCAL_DEFINITION,
39426
+ severity: input.severity,
39427
+ data: {
39428
+ kind: "missing-local-model-definition",
39429
+ nodeId,
39430
+ sourceKind: "inline-tree-nodes-model",
39431
+ fix: fixableModel && input.uri ? {
39432
+ kind: "add-local-definition",
39433
+ uri: input.uri,
39434
+ nodeId,
39435
+ model: fixableModel
39436
+ } : void 0
39437
+ }
39438
+ })
39439
+ );
39440
+ }
39441
+ return diagnostics;
39442
+ }
39316
39443
  function duplicateFix(definitions) {
39317
39444
  const canonical = definitions.filter((definition) => definition.isCanonicalModelFile);
39318
39445
  if (canonical.length !== 1) return void 0;
@@ -40259,7 +40386,9 @@ var modelRules = [
40259
40386
  }),
40260
40387
  makeRuleModule({
40261
40388
  name: "model/valid-port-name",
40262
- meta: { description: "Port names must be valid XML attribute names for BT nodes." },
40389
+ meta: {
40390
+ description: "Port names must be valid XML attribute names for BT nodes."
40391
+ },
40263
40392
  create(context) {
40264
40393
  return {
40265
40394
  TreeNodeModel(node) {
@@ -40304,7 +40433,9 @@ var modelRules = [
40304
40433
  }),
40305
40434
  makeRuleModule({
40306
40435
  name: "model/valid-port-default-value",
40307
- meta: { description: "TreeNodesModel port defaults must match the declared type." },
40436
+ meta: {
40437
+ description: "TreeNodesModel port defaults must match the declared type."
40438
+ },
40308
40439
  create(context) {
40309
40440
  return {
40310
40441
  Element(element) {
@@ -40414,7 +40545,7 @@ var modelRules = [
40414
40545
  makeRuleModule({
40415
40546
  name: "model/require-output-port-remap",
40416
40547
  meta: {
40417
- description: "Resolved output ports must write to a blackboard remap."
40548
+ description: "Resolved output ports must be explicitly or default-remapped to a blackboard entry."
40418
40549
  },
40419
40550
  create(context) {
40420
40551
  return {
@@ -40422,19 +40553,34 @@ var modelRules = [
40422
40553
  if (isStructuralElement2(element)) return;
40423
40554
  const usage = context.getNodeUsage(element);
40424
40555
  if (usage.model.status !== "resolved" && usage.tagForm !== "subtree") return;
40425
- for (const attr of element.attributes) {
40426
- const portUsage = context.getPortUsage(element, attr.name);
40427
- if (portUsage?.status !== "resolved") continue;
40428
- if (portUsage.port.direction !== "output") continue;
40429
- if (getExactBlackboardReference(portUsage.port.name, attr.value) !== void 0)
40556
+ for (const port of usage.ports) {
40557
+ if (port.direction !== "output") continue;
40558
+ const binding = usage.portUsages.find(
40559
+ (candidate) => candidate.name === port.name && candidate.status === "resolved"
40560
+ );
40561
+ if (binding) {
40562
+ if (getExactBlackboardReference(port.name, binding.value) !== void 0) continue;
40563
+ context.report({
40564
+ code: RuleCodes.OutputPortRequiresRemap,
40565
+ message: `output port \`${port.name}\` must be remapped to a blackboard entry`,
40566
+ range: binding.attribute.range,
40567
+ details: {
40568
+ primaryLabel: `output port \`${port.name}\` requires a blackboard remap`,
40569
+ help: `use \`${port.name}="{${port.name}}"\` or \`${port.name}="{some_key}"\``
40570
+ }
40571
+ });
40572
+ continue;
40573
+ }
40574
+ if (port.defaultValue !== void 0 && getExactBlackboardReference(port.name, port.defaultValue) !== void 0) {
40430
40575
  continue;
40576
+ }
40431
40577
  context.report({
40432
40578
  code: RuleCodes.OutputPortRequiresRemap,
40433
- message: `output port \`${portUsage.port.name}\` must be remapped to a blackboard entry`,
40434
- range: attr.range,
40579
+ message: `output port \`${port.name}\` must be remapped to a blackboard entry`,
40580
+ range: element.range,
40435
40581
  details: {
40436
- primaryLabel: `output port \`${portUsage.port.name}\` requires a blackboard remap`,
40437
- help: `use \`${portUsage.port.name}="{${portUsage.port.name}}"\` or \`${portUsage.port.name}="{some_key}"\``
40582
+ primaryLabel: `output port \`${port.name}\` requires a blackboard remap`,
40583
+ help: `use \`${port.name}="{${port.name}}"\` or \`${port.name}="{some_key}"\``
40438
40584
  }
40439
40585
  });
40440
40586
  }
@@ -44005,12 +44151,15 @@ function removeAttributeEdit(document, attribute) {
44005
44151
  return { range, newText: "" };
44006
44152
  }
44007
44153
  function addAttributeEdit(document, element, name) {
44154
+ return addAttributeWithValueEdit(document, element, name, "");
44155
+ }
44156
+ function addAttributeWithValueEdit(document, element, name, value) {
44008
44157
  const closeOffset = Math.max(
44009
44158
  element.openTagRange.end.offset - (element.selfClosing ? 2 : 1),
44010
44159
  element.openTagRange.start.offset
44011
44160
  );
44012
44161
  const pos = document.positionAt(closeOffset);
44013
- return { range: sourceRange(pos, pos), newText: ` ${name}=""` };
44162
+ return { range: sourceRange(pos, pos), newText: ` ${name}="${value}"` };
44014
44163
  }
44015
44164
 
44016
44165
  // ../language-service/src/ranges.ts
@@ -44031,84 +44180,160 @@ function getCodeActions(context, input) {
44031
44180
  });
44032
44181
  }
44033
44182
  for (const diag of diagnostics) {
44034
- if (!diag.range) continue;
44183
+ if (!hasRange(diag)) continue;
44035
44184
  const inspect = inspectXmlCursor({
44036
44185
  document: input.document,
44037
44186
  parsed: context.parsed,
44038
44187
  position: diag.range.start
44039
44188
  });
44040
- if (diag.code === "BT101_MISSING_REQUIRED_PORT") {
44041
- const targetOffset = Math.min(diag.range.start.offset + 1, diag.range.end.offset);
44042
- const target = context.parsed?.root ? findElementAt(context.parsed.root, targetOffset) || ("element" in inspect ? inspect.element : void 0) : "element" in inspect ? inspect.element : void 0;
44043
- if (!target) continue;
44044
- const usage = resolveNodeUsage(context.semantic, {
44045
- element: target,
44046
- documentRoot: context.parsed?.root,
44047
- uri: input.document.uri,
44048
- config: context.config,
44049
- policy: context.nodeUsagePolicy
44050
- });
44051
- const missing = usage.ports.find(
44052
- (port) => port.required && !usage.portUsages.some(
44053
- (binding) => binding.status === "resolved" && binding.name === port.name
44054
- )
44055
- );
44056
- if (missing) {
44057
- actions.push({
44058
- title: `Add missing port ${missing.name}`,
44059
- kind: "quickfix",
44060
- diagnostics: [diag],
44061
- edits: [addAttributeEdit(input.document, target, missing.name)]
44062
- });
44063
- }
44064
- }
44065
- if (diag.code === "BT102_UNKNOWN_PORT" && "attribute" in inspect && "element" in inspect && inspect.attribute) {
44066
- const usage = inspect.element ? resolveNodeUsage(context.semantic, {
44067
- element: inspect.element,
44068
- documentRoot: context.parsed?.root,
44069
- uri: input.document.uri,
44070
- config: context.config,
44071
- policy: context.nodeUsagePolicy
44072
- }) : void 0;
44073
- const unknown2 = usage?.portUsages.find(
44074
- (candidate) => candidate.status === "undeclared" && candidate.attribute === inspect.attribute
44075
- );
44076
- const edit = unknown2 ? removeAttributeEdit(input.document, inspect.attribute) : void 0;
44077
- if (edit && unknown2) {
44078
- actions.push({
44079
- title: `Remove unknown port ${inspect.attribute.name}`,
44080
- kind: "quickfix",
44081
- diagnostics: [diag],
44082
- edits: [edit]
44083
- });
44084
- }
44085
- }
44086
- if (diag.code === "BT002_MISSING_BTCPP_FORMAT" && context.parsed?.root) {
44087
- const insertPos = input.document.positionAt(
44088
- context.parsed.root.nameRange?.end.offset || context.parsed.root.openTagRange.end.offset - 1
44089
- );
44189
+ const target = resolveTargetElement(context, input, diag, inspect);
44190
+ addMissingRequiredPortAction(actions, context, input, diag.code, diag, target);
44191
+ addOutputRemapAction(actions, context, input, diag.code, diag, inspect, target);
44192
+ addUnknownPortAction(actions, context, input, diag.code, diag, inspect);
44193
+ addMissingBtcppFormatAction(actions, context, input, diag.code, diag);
44194
+ addSuppressionAction(actions, input, diag);
44195
+ }
44196
+ return { actions };
44197
+ }
44198
+ function hasRange(diag) {
44199
+ return !!diag.range;
44200
+ }
44201
+ function isResolvedPortUsage(binding) {
44202
+ return binding.status === "resolved";
44203
+ }
44204
+ function resolveUsage(context, input, element) {
44205
+ return resolveNodeUsage(context.semantic, {
44206
+ element,
44207
+ documentRoot: context.parsed?.root,
44208
+ uri: input.document.uri,
44209
+ config: context.config,
44210
+ policy: context.nodeUsagePolicy
44211
+ });
44212
+ }
44213
+ function inspectElement(inspect) {
44214
+ return "element" in inspect ? inspect.element : void 0;
44215
+ }
44216
+ function resolveTargetElement(context, input, diag, inspect) {
44217
+ const fallback = inspectElement(inspect);
44218
+ const root = context.parsed?.root;
44219
+ if (!root || !diag.range) return fallback;
44220
+ const targetOffset = Math.min(diag.range.start.offset + 1, diag.range.end.offset);
44221
+ return findElementAt(root, targetOffset) ?? fallback;
44222
+ }
44223
+ function addMissingRequiredPortAction(actions, context, input, code, diag, target) {
44224
+ if (code !== "BT101_MISSING_REQUIRED_PORT") return;
44225
+ if (!target) return;
44226
+ const usage = resolveUsage(context, input, target);
44227
+ const missing = usage.ports.find(
44228
+ (port) => port.required && !usage.portUsages.some(
44229
+ (binding) => binding.status === "resolved" && binding.name === port.name
44230
+ )
44231
+ );
44232
+ if (!missing) return;
44233
+ actions.push({
44234
+ title: `Add missing port ${missing.name}`,
44235
+ kind: "quickfix",
44236
+ diagnostics: [diag],
44237
+ edits: [addAttributeEdit(input.document, target, missing.name)]
44238
+ });
44239
+ }
44240
+ function addOutputRemapAction(actions, context, input, code, diag, inspect, target) {
44241
+ if (code !== "BT115_OUTPUT_PORT_REQUIRES_REMAP") return;
44242
+ if (!target) return;
44243
+ const outputPortName = /`([^`]+)`/.exec(diag.message)?.[1];
44244
+ const usage = resolveUsage(context, input, target);
44245
+ const attribute = "attribute" in inspect ? inspect.attribute : void 0;
44246
+ if (attribute) {
44247
+ const binding = usage.portUsages.find(
44248
+ (candidate) => isResolvedPortUsage(candidate) && candidate.port.direction === "output" && candidate.attribute === attribute && (!outputPortName || candidate.port.name === outputPortName)
44249
+ );
44250
+ if (binding) {
44090
44251
  actions.push({
44091
- title: 'Add BTCPP_format="4" to <root>',
44252
+ title: `Remap output port ${binding.port.name}`,
44092
44253
  kind: "quickfix",
44093
44254
  diagnostics: [diag],
44094
- edits: [{ range: sourceRange(insertPos, insertPos), newText: ' BTCPP_format="4"' }]
44255
+ edits: [
44256
+ {
44257
+ range: attribute.valueContentRange ?? attribute.valueRange,
44258
+ newText: `{${binding.port.name}}`
44259
+ }
44260
+ ]
44095
44261
  });
44262
+ return;
44096
44263
  }
44097
- actions.push({
44098
- title: `Suppress ${diag.code} for next line`,
44099
- kind: "quickfix",
44100
- diagnostics: [diag],
44101
- edits: [
44102
- insertAtLineStart(
44103
- input.document,
44104
- diag.range.start.line,
44105
- `<!-- btxml-disable-next-line ${diag.code} reason: TODO -->
44106
- `
44107
- )
44108
- ]
44109
- });
44110
44264
  }
44111
- return { actions };
44265
+ const missingOutputPort = usage.ports.find(
44266
+ (port) => port.direction === "output" && (!outputPortName || port.name === outputPortName) && !usage.portUsages.some(
44267
+ (binding) => binding.status === "resolved" && binding.name === port.name
44268
+ )
44269
+ );
44270
+ if (!missingOutputPort) return;
44271
+ actions.push({
44272
+ title: `Remap output port ${missingOutputPort.name}`,
44273
+ kind: "quickfix",
44274
+ diagnostics: [diag],
44275
+ edits: [
44276
+ addAttributeWithValueEdit(
44277
+ input.document,
44278
+ target,
44279
+ missingOutputPort.name,
44280
+ `{${missingOutputPort.name}}`
44281
+ )
44282
+ ]
44283
+ });
44284
+ }
44285
+ function addUnknownPortAction(actions, context, input, code, diag, inspect) {
44286
+ if (code !== "BT102_UNKNOWN_PORT") return;
44287
+ if (!("attribute" in inspect && inspect.attribute)) return;
44288
+ const element = inspectElement(inspect);
44289
+ if (!element) return;
44290
+ const usage = resolveUsage(context, input, element);
44291
+ const unknown2 = usage.portUsages.find(
44292
+ (candidate) => candidate.status === "undeclared" && candidate.attribute === inspect.attribute
44293
+ );
44294
+ if (!unknown2) return;
44295
+ const edit = removeAttributeEdit(input.document, inspect.attribute);
44296
+ if (!edit) return;
44297
+ actions.push({
44298
+ title: `Remove unknown port ${inspect.attribute.name}`,
44299
+ kind: "quickfix",
44300
+ diagnostics: [diag],
44301
+ edits: [edit]
44302
+ });
44303
+ }
44304
+ function addMissingBtcppFormatAction(actions, context, input, code, diag) {
44305
+ if (code !== "BT002_MISSING_BTCPP_FORMAT") return;
44306
+ if (!context.parsed?.root) return;
44307
+ const insertPos = input.document.positionAt(
44308
+ context.parsed.root.nameRange?.end.offset || context.parsed.root.openTagRange.end.offset - 1
44309
+ );
44310
+ actions.push({
44311
+ title: 'Add BTCPP_format="4" to <root>',
44312
+ kind: "quickfix",
44313
+ diagnostics: [diag],
44314
+ edits: [
44315
+ {
44316
+ range: sourceRange(insertPos, insertPos),
44317
+ newText: ' BTCPP_format="4"'
44318
+ }
44319
+ ]
44320
+ });
44321
+ }
44322
+ function addSuppressionAction(actions, input, diag) {
44323
+ if (!diag.range) return;
44324
+ actions.push({
44325
+ title: `Suppress ${diag.code} for next line`,
44326
+ kind: "quickfix",
44327
+ diagnostics: [diag],
44328
+ edits: [
44329
+ insertAtLineStart(
44330
+ input.document,
44331
+ diag.range.start.line,
44332
+ `<!-- btxml-disable-next-line ${diag.code} reason: TODO -->
44333
+ `
44334
+ )
44335
+ ]
44336
+ });
44112
44337
  }
44113
44338
 
44114
44339
  // ../language-service/src/completions.ts
@@ -46855,7 +47080,7 @@ function handleGetChildCapability(workspace, params) {
46855
47080
  }
46856
47081
 
46857
47082
  // src/server.ts
46858
- var SERVER_VERSION = true ? "0.1.4" : "unknown";
47083
+ var SERVER_VERSION = true ? "0.1.5" : "unknown";
46859
47084
  var connection = (0, import_node4.createConnection)(import_node4.ProposedFeatures.all);
46860
47085
  var documents = new import_node4.TextDocuments(TextDocument);
46861
47086
  var openUris = /* @__PURE__ */ new Set();