@px-lsp/server 0.1.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.
Files changed (163) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +334 -0
  3. package/THIRD-PARTY-NOTICES.md +83 -0
  4. package/data/ck3/dataTypes.json +2195 -0
  5. package/data/ck3/data_types/data_types_common.txt +2040 -0
  6. package/data/ck3/data_types/data_types_gui.txt +5264 -0
  7. package/data/ck3/data_types/data_types_internalclausewitzgui.txt +14843 -0
  8. package/data/ck3/data_types/data_types_script.txt +4251 -0
  9. package/data/ck3/data_types/data_types_uncategorized.txt +109984 -0
  10. package/data/ck3/freqs.json +1 -0
  11. package/data/ck3/guiSchema.json +6344 -0
  12. package/data/ck3/script_docs/effects.log +16059 -0
  13. package/data/ck3/script_docs/event_targets.log +2098 -0
  14. package/data/ck3/script_docs/modifiers.log +2228 -0
  15. package/data/ck3/script_docs/on_actions.log +5275 -0
  16. package/data/ck3/script_docs/triggers.log +11991 -0
  17. package/data/ck3/structures.json +9743 -0
  18. package/data/ck3/wikidocs/ATTRIBUTION.md +18 -0
  19. package/data/ck3/wikidocs/Data_types.md +2568 -0
  20. package/data/ck3/wikidocs/Effects_list.md +1176 -0
  21. package/data/ck3/wikidocs/Scopes_list.md +341 -0
  22. package/data/ck3/wikidocs/Triggers_list.md +1097 -0
  23. package/data/eu5/data_types/data_types_common.txt +2087 -0
  24. package/data/eu5/data_types/data_types_gui.txt +6732 -0
  25. package/data/eu5/data_types/data_types_internalclausewitzgui.txt +19276 -0
  26. package/data/eu5/data_types/data_types_script.txt +5688 -0
  27. package/data/eu5/data_types/data_types_uncategorized.txt +135569 -0
  28. package/data/vic3/data_types/data_types_common.txt +2021 -0
  29. package/data/vic3/data_types/data_types_gui.txt +5592 -0
  30. package/data/vic3/data_types/data_types_internalclausewitzgui.txt +17304 -0
  31. package/data/vic3/data_types/data_types_script.txt +2817 -0
  32. package/data/vic3/data_types/data_types_uncategorized.txt +84354 -0
  33. package/data/vic3/freqs.json +1 -0
  34. package/data/vic3/guiSchema.json +5578 -0
  35. package/data/vic3/script_docs/effects.log +38135 -0
  36. package/data/vic3/script_docs/event_targets.log +2028 -0
  37. package/data/vic3/script_docs/modifiers.log +18954 -0
  38. package/data/vic3/script_docs/on_actions.log +1561 -0
  39. package/data/vic3/script_docs/triggers.log +15738 -0
  40. package/data/vic3/structures.json +10189 -0
  41. package/dist/server.js +63668 -0
  42. package/media/px-lsp.svg +12 -0
  43. package/package.json +50 -0
  44. package/src/clientMode.ts +60 -0
  45. package/src/coa/coa.ts +184 -0
  46. package/src/coa/coaParse.ts +267 -0
  47. package/src/context.ts +78 -0
  48. package/src/contextKeywords.ts +224 -0
  49. package/src/data/dataBindingMacros.ts +82 -0
  50. package/src/data/dataFnDocs.ts +152 -0
  51. package/src/data/dataFnUsage.ts +431 -0
  52. package/src/data/dataTypes.ts +279 -0
  53. package/src/data/defines.ts +123 -0
  54. package/src/data/docsParser.ts +453 -0
  55. package/src/data/keywordDocs.ts +98 -0
  56. package/src/data/modifierTemplates.ts +143 -0
  57. package/src/data/textFormatting.ts +165 -0
  58. package/src/data/wikiDocs.ts +187 -0
  59. package/src/dds/decoder.ts +1007 -0
  60. package/src/dds/encode.ts +235 -0
  61. package/src/dds/index.ts +58 -0
  62. package/src/dds/png.ts +96 -0
  63. package/src/dds/tga.ts +62 -0
  64. package/src/documents.ts +35 -0
  65. package/src/features/assetPaths.ts +169 -0
  66. package/src/features/codeActions.ts +148 -0
  67. package/src/features/colors.ts +244 -0
  68. package/src/features/completion.ts +961 -0
  69. package/src/features/datafunction.ts +729 -0
  70. package/src/features/definition.ts +84 -0
  71. package/src/features/diagnostics.ts +244 -0
  72. package/src/features/folding.ts +106 -0
  73. package/src/features/formatting.ts +60 -0
  74. package/src/features/guiLanguage.ts +366 -0
  75. package/src/features/guiNavigation.ts +140 -0
  76. package/src/features/guiTree.ts +97 -0
  77. package/src/features/hover.ts +817 -0
  78. package/src/features/hoverRender.ts +222 -0
  79. package/src/features/inlayHints.ts +147 -0
  80. package/src/features/locFormatting.ts +127 -0
  81. package/src/features/references.ts +70 -0
  82. package/src/features/rename.ts +135 -0
  83. package/src/features/scopeAt.ts +65 -0
  84. package/src/features/semanticTokens.ts +188 -0
  85. package/src/features/signatureHelp.ts +72 -0
  86. package/src/features/symbols.ts +241 -0
  87. package/src/features/textureHover.ts +143 -0
  88. package/src/features/workspaceSymbols.ts +69 -0
  89. package/src/games/active.ts +19 -0
  90. package/src/games/ck3/ambientScopes.ts +273 -0
  91. package/src/games/ck3/index.ts +38 -0
  92. package/src/games/ck3/meta.ts +28 -0
  93. package/src/games/ck3/modifierPlaceholders.ts +61 -0
  94. package/src/games/ck3/saveSchema.ts +134 -0
  95. package/src/games/ck3/scaffolds.ts +197 -0
  96. package/src/games/ck3/schema.ts +422 -0
  97. package/src/games/ck3/structures.ts +887 -0
  98. package/src/games/eu5/index.ts +75 -0
  99. package/src/games/eu5/meta.ts +44 -0
  100. package/src/games/eu5/scaffolds.ts +49 -0
  101. package/src/games/eu5/schema.generated.ts +1043 -0
  102. package/src/games/jomini/variables.ts +134 -0
  103. package/src/games/profile.ts +205 -0
  104. package/src/games/registry.ts +27 -0
  105. package/src/games/vic3/index.ts +52 -0
  106. package/src/games/vic3/meta.ts +55 -0
  107. package/src/games/vic3/saveSchema.ts +77 -0
  108. package/src/games/vic3/scaffolds.ts +135 -0
  109. package/src/games/vic3/schema.ts +650 -0
  110. package/src/games/vic3/structures.ts +33 -0
  111. package/src/gui/anchorSpec.ts +66 -0
  112. package/src/gui/declMarkers.ts +30 -0
  113. package/src/gui/fillGeometry.ts +101 -0
  114. package/src/gui/guiDefs.ts +386 -0
  115. package/src/gui/guiDependencies.ts +352 -0
  116. package/src/gui/guiLinks.ts +64 -0
  117. package/src/gui/layoutEngine.ts +1998 -0
  118. package/src/gui/layoutService.ts +221 -0
  119. package/src/gui/measuredMetrics.ts +21 -0
  120. package/src/gui/previewService.ts +89 -0
  121. package/src/gui/saveSchema.ts +220 -0
  122. package/src/gui/saveValues.ts +399 -0
  123. package/src/gui/saveZip.ts +60 -0
  124. package/src/gui/sourceEdit.ts +535 -0
  125. package/src/gui/sourceEditService.ts +439 -0
  126. package/src/gui/sourceModel.ts +603 -0
  127. package/src/gui/textResolve.ts +145 -0
  128. package/src/gui/textureInfo.ts +106 -0
  129. package/src/gui/vocabulary.ts +149 -0
  130. package/src/gui/widgetEdit.ts +52 -0
  131. package/src/gui/widgetInfo.ts +245 -0
  132. package/src/index/docComments.ts +103 -0
  133. package/src/index/extract.ts +252 -0
  134. package/src/index/indexer.ts +369 -0
  135. package/src/index/intern.ts +101 -0
  136. package/src/index/lazyRefs.ts +145 -0
  137. package/src/index/modOrigin.ts +69 -0
  138. package/src/index/references.ts +534 -0
  139. package/src/overview/dependencies.ts +240 -0
  140. package/src/overview/eventBanner.ts +95 -0
  141. package/src/overview/eventDetail.ts +482 -0
  142. package/src/overview/eventGraph.ts +617 -0
  143. package/src/overview/eventVocabulary.ts +214 -0
  144. package/src/overview/locCoverage.ts +138 -0
  145. package/src/overview/modOverview.ts +29 -0
  146. package/src/overview/overrides.ts +89 -0
  147. package/src/parseCache.ts +81 -0
  148. package/src/parser/cst.ts +257 -0
  149. package/src/parser/encoding.ts +106 -0
  150. package/src/parser/index.ts +7 -0
  151. package/src/parser/lexer.ts +245 -0
  152. package/src/parser/locParser.ts +276 -0
  153. package/src/parser/parser.ts +360 -0
  154. package/src/schema/freqs.ts +70 -0
  155. package/src/schema/loader.ts +113 -0
  156. package/src/schema/types.ts +142 -0
  157. package/src/scopes/inference.ts +478 -0
  158. package/src/scopes/model.ts +148 -0
  159. package/src/scopes/varTypes.ts +290 -0
  160. package/src/server.ts +1894 -0
  161. package/src/serverData.ts +98 -0
  162. package/src/structure.ts +56 -0
  163. package/src/wordAt.ts +49 -0
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Crusader Kings III "New Content" templates. Content copied from working
3
+ * vanilla examples, so every generated file passes the game's silent-failure
4
+ * checklist: correct folder, event namespace declared, loc keys that match the
5
+ * script, and the on_action APPEND pattern rather than an override.
6
+ *
7
+ * Tabs for indentation and LF only; the writer converts EOL and adds the BOM.
8
+ */
9
+ import type { ScaffoldTemplate } from "../profile";
10
+
11
+ /** The vanilla on_actions worth hooking, all present in common/on_action/. */
12
+ const CK3_ON_ACTIONS = [
13
+ "on_birth",
14
+ "on_death",
15
+ "on_marriage",
16
+ "on_divorce",
17
+ "on_yearly_pulse",
18
+ "on_five_year_pulse",
19
+ "on_game_start",
20
+ "on_game_start_after_lobby",
21
+ "on_character_culture_change",
22
+ "on_character_faith_change",
23
+ "on_title_gain",
24
+ "on_war_won_attacker",
25
+ ];
26
+
27
+ export const CK3_SCAFFOLDS: ScaffoldTemplate[] = [
28
+ {
29
+ id: "event",
30
+ label: "$(zap) Event",
31
+ detail: "events/<prefix>_events.txt (+ loc stubs)",
32
+ nameLabel: "event id",
33
+ nameKind: "eventId",
34
+ scriptPath: "events/$PREFIX$_events.txt",
35
+ requiredHeader: "namespace = $PREFIX$",
36
+ cursorMarker: "# effects that run when the event fires",
37
+ block: `$NAME$ = {
38
+ type = character_event
39
+ title = $KEY$_t
40
+ desc = $KEY$_desc
41
+ theme = default
42
+
43
+ left_portrait = root
44
+
45
+ immediate = {
46
+ # effects that run when the event fires
47
+ }
48
+
49
+ option = {
50
+ name = $KEY$_a
51
+ # trigger = { }
52
+ # effects for this option
53
+ }
54
+ }
55
+ `,
56
+ locPath: "localization/$LANG$/$PREFIX$_events_l_$LANG$.yml",
57
+ locBody: ` $KEY$_t:0 "$NAME$ title"
58
+ $KEY$_desc:0 "$NAME$ description"
59
+ $KEY$_a:0 "Option text"
60
+ `,
61
+ },
62
+ {
63
+ id: "decision",
64
+ label: "$(checklist) Decision",
65
+ detail: "common/decisions/ (+ loc stubs)",
66
+ nameLabel: "decision",
67
+ nameKind: "identifier",
68
+ scriptPath: "common/decisions/$PREFIX$_decisions.txt",
69
+ cursorMarker: "# effects that run when the decision is taken",
70
+ block: `$NAME$ = {
71
+ picture = "gfx/interface/illustrations/decisions/decision_misc.dds"
72
+
73
+ desc = $NAME$_desc
74
+
75
+ is_shown = {
76
+ # who can see this decision
77
+ }
78
+
79
+ is_valid_showing_failures_only = {
80
+ # validity requirements shown as tooltip failures
81
+ }
82
+
83
+ cost = {
84
+ gold = 50
85
+ }
86
+
87
+ effect = {
88
+ # effects that run when the decision is taken
89
+ custom_tooltip = $NAME$_tooltip
90
+ }
91
+
92
+ ai_potential = {
93
+ always = no
94
+ }
95
+
96
+ ai_will_do = {
97
+ base = 0
98
+ }
99
+ }
100
+ `,
101
+ locPath: "localization/$LANG$/$PREFIX$_decisions_l_$LANG$.yml",
102
+ locBody: ` $NAME$:0 "Decision name"
103
+ $NAME$_desc:0 "Decision description"
104
+ $NAME$_tooltip:0 "What the effect does"
105
+ $NAME$_confirm:0 "Confirm"
106
+ `,
107
+ },
108
+ {
109
+ id: "interaction",
110
+ label: "$(person) Character interaction",
111
+ detail: "common/character_interactions/ (+ loc stubs)",
112
+ nameLabel: "interaction",
113
+ nameKind: "identifier",
114
+ scriptPath: "common/character_interactions/$PREFIX$_interactions.txt",
115
+ cursorMarker: "# effects that run when the recipient accepts",
116
+ block: `$NAME$ = {
117
+ category = interaction_category_friendly
118
+
119
+ desc = $NAME$_desc
120
+
121
+ is_shown = {
122
+ # who can use this interaction (scope = actor, recipient = target)
123
+ }
124
+
125
+ on_accept = {
126
+ # effects that run when the recipient accepts
127
+ send_interface_toast = {
128
+ title = $NAME$
129
+ left_icon = scope:recipient
130
+ }
131
+ }
132
+ }
133
+ `,
134
+ locPath: "localization/$LANG$/$PREFIX$_interactions_l_$LANG$.yml",
135
+ locBody: ` $NAME$:0 "Interaction name"
136
+ $NAME$_desc:0 "Interaction description"
137
+ `,
138
+ },
139
+ {
140
+ id: "on_action",
141
+ label: "$(git-merge) on_action hook",
142
+ detail: "common/on_action/ (append pattern, no override)",
143
+ nameLabel: "vanilla on_action",
144
+ nameKind: "identifier",
145
+ picks: CK3_ON_ACTIONS,
146
+ scriptPath: "common/on_action/$PREFIX$_on_actions.txt",
147
+ cursorMarker: "# your effects here",
148
+ // The APPEND pattern: hook into the vanilla on_action by adding a mod-owned
149
+ // on_action to its `on_actions` list, instead of redefining the vanilla
150
+ // block (which would OVERRIDE it and break every other mod + vanilla
151
+ // content). This directly targets the #1 compatibility bug.
152
+ block: `$NAME$ = {
153
+ on_actions = { $PREFIX$_$NAME$ }
154
+ }
155
+
156
+ $PREFIX$_$NAME$ = {
157
+ effect = {
158
+ # your effects here
159
+ }
160
+ }
161
+ `,
162
+ },
163
+ {
164
+ id: "scripted_effect",
165
+ label: "$(symbol-method) Scripted effect",
166
+ detail: "common/scripted_effects/ (with a PdxDoc stub)",
167
+ nameLabel: "effect",
168
+ nameKind: "identifier",
169
+ scriptPath: "common/scripted_effects/$PREFIX$_scripted_effects.txt",
170
+ cursorMarker: "# effects here",
171
+ // Prefaced with a PdxDoc stub (§E) so the documentation convention spreads
172
+ // by default: a prose line, a `@scope` tag and a `@param` placeholder.
173
+ block: `# What this does.
174
+ # @scope character (root is the character affected)
175
+ # @param EXAMPLE_PARAM describe each $PARAM$ the caller must pass
176
+ $NAME$ = {
177
+ # effects here
178
+ }
179
+ `,
180
+ },
181
+ {
182
+ id: "scripted_trigger",
183
+ label: "$(symbol-boolean) Scripted trigger",
184
+ detail: "common/scripted_triggers/ (with a PdxDoc stub)",
185
+ nameLabel: "trigger",
186
+ nameKind: "identifier",
187
+ scriptPath: "common/scripted_triggers/$PREFIX$_scripted_triggers.txt",
188
+ cursorMarker: "# conditions here",
189
+ // No `@returns`: a trigger implicitly returns yes/no.
190
+ block: `# What this checks.
191
+ # @scope character (root is the character tested)
192
+ $NAME$ = {
193
+ # conditions here
194
+ }
195
+ `,
196
+ },
197
+ ];
@@ -0,0 +1,422 @@
1
+ /**
2
+ * The bundled CK3 schema table (rework plan AD-3). One entry per game folder
3
+ * we understand; community-editable in-repo, extendable per-workspace via
4
+ * .ck3modding/schema.json.
5
+ *
6
+ * Every entry was verified against a real CK3 install (game version with
7
+ * common/ ~150 subfolders): the folder was listed, a file opened, and the
8
+ * top-level key confirmed to be the name script actually references. Where a
9
+ * folder's on-disk layout does not fit any extraction mode (see types.ts),
10
+ * it is left out rather than indexed with wrong names — see the trailing
11
+ * "Not covered" block. requiredLoc/rootScopes are only set where confirmed
12
+ * from vanilla loc + the folder's `_*.info` docs.
13
+ */
14
+ import type { SchemaEntry, RefField } from "../../schema/types";
15
+ import { JOMINI_VARIABLE_BLOCK_REFS } from "../jomini/variables";
16
+ import { STRUCTURES } from "./structures";
17
+ import { AMBIENT_SCOPES } from "./ambientScopes";
18
+
19
+ const CK3_SCHEMA_BASE: SchemaEntry[] = [
20
+ // --- Core script folders (already wired in v0.3; keep as-is) ---
21
+ { path: "common/scripted_effects", kind: "scripted_effect" },
22
+ { path: "common/scripted_triggers", kind: "scripted_trigger" },
23
+ { path: "common/on_action", kind: "on_action" },
24
+ { path: "common/script_values", kind: "script_value" },
25
+ { path: "common/scripted_modifiers", kind: "scripted_modifier" },
26
+ // rootScopes: events default to character scope (character_event); other event
27
+ // types differ, but scope inference only ranks/annotates, so best-effort is safe.
28
+ { path: "events", kind: "event", extraction: "event-id", rootScopes: ["character"] },
29
+ { path: "localization", kind: "loc_key", ext: ".yml", extraction: "loc-key" },
30
+
31
+ // --- Characters, traits, interactions ---
32
+ { path: "common/traits", kind: "trait", requiredLoc: ["trait_$"], rootScopes: ["character"] },
33
+ {
34
+ path: "common/character_interactions",
35
+ kind: "character_interaction",
36
+ rootScopes: ["character"],
37
+ },
38
+ { path: "common/character_backgrounds", kind: "character_background" },
39
+ { path: "common/character_memory_types", kind: "character_memory_type", rootScopes: ["character"] },
40
+ { path: "common/nicknames", kind: "nickname", requiredLoc: ["$"], rootScopes: ["character"] },
41
+ { path: "common/deathreasons", kind: "death_reason" },
42
+ { path: "common/secret_types", kind: "secret", rootScopes: ["secret"] },
43
+ { path: "common/hook_types", kind: "hook_type" },
44
+ {
45
+ path: "common/scripted_character_templates",
46
+ kind: "scripted_character_template",
47
+ },
48
+
49
+ // --- Decisions & interactions surfaces ---
50
+ { path: "common/decisions", kind: "decision", rootScopes: ["character"] },
51
+ { path: "common/suggestions", kind: "suggestion", rootScopes: ["character"] },
52
+ { path: "common/important_actions", kind: "important_action", rootScopes: ["character"] },
53
+
54
+ // --- Lifestyles & focuses ---
55
+ { path: "common/lifestyles", kind: "lifestyle", rootScopes: ["character"] },
56
+ {
57
+ path: "common/lifestyle_perks",
58
+ kind: "perk",
59
+ requiredLoc: ["$_name"],
60
+ rootScopes: ["character"],
61
+ },
62
+ { path: "common/focuses", kind: "focus", rootScopes: ["character"] },
63
+
64
+ // --- Casus belli & warfare ---
65
+ // casus_belli: `$` loc coverage measured ~92% in vanilla (many internal/debug
66
+ // CBs lack a name loc key) — below the 95% bar, so no requiredLoc.
67
+ { path: "common/casus_belli_types", kind: "casus_belli", rootScopes: ["character"] },
68
+ { path: "common/casus_belli_groups", kind: "casus_belli_group" },
69
+ { path: "common/men_at_arms_types", kind: "men_at_arms", requiredLoc: ["$"], rootScopes: ["character"] },
70
+ { path: "common/combat_effects", kind: "combat_effect" },
71
+
72
+ // --- Realm structure: laws, governments, titles, buildings, holdings ---
73
+ // NOTE: common/laws top-level keys are law *groups* (e.g. title_succession_laws);
74
+ // the individual laws (feudal_elective_succession_law) are second-level and are
75
+ // NOT extractable with the current modes. We index the groups only.
76
+ { path: "common/laws", kind: "law_group", rootScopes: ["character"] },
77
+ { path: "common/governments", kind: "government", rootScopes: ["character"] },
78
+ {
79
+ path: "common/landed_titles",
80
+ kind: "landed_title",
81
+ extraction: "nested-title",
82
+ rootScopes: ["character"],
83
+ },
84
+ { path: "common/buildings", kind: "building", requiredLoc: ["building_$"], rootScopes: ["province"] },
85
+ { path: "common/holdings", kind: "holding_type" },
86
+ { path: "common/great_projects/types", kind: "great_project", rootScopes: ["character", "great_project"] },
87
+ { path: "common/terrain_types", kind: "terrain_type" },
88
+ { path: "common/subject_contracts/contracts", kind: "subject_contract", rootScopes: ["character"] },
89
+ { path: "common/subject_contracts/groups", kind: "subject_contract_group" },
90
+ { path: "common/tax_slots/types", kind: "tax_slot_type", rootScopes: ["character"] },
91
+ { path: "common/vassal_stances", kind: "vassal_stance", rootScopes: ["character"] },
92
+ { path: "common/council_positions", kind: "council_position", rootScopes: ["character"] },
93
+ { path: "common/council_tasks", kind: "council_task", rootScopes: ["character"] },
94
+ { path: "common/court_positions/types", kind: "court_position", rootScopes: ["character"] },
95
+ { path: "common/court_positions/tasks", kind: "court_position_task", rootScopes: ["character"] },
96
+ { path: "common/court_amenities", kind: "court_amenity" },
97
+ { path: "common/court_types", kind: "court_type" },
98
+
99
+ // --- Culture ---
100
+ { path: "common/culture/cultures", kind: "culture", requiredLoc: ["$"] },
101
+ { path: "common/culture/pillars", kind: "culture_pillar" },
102
+ {
103
+ path: "common/culture/traditions",
104
+ kind: "culture_tradition",
105
+ // def names already carry the `tradition_` prefix; loc key is `<name>_name`.
106
+ requiredLoc: ["$_name"],
107
+ rootScopes: ["culture"],
108
+ },
109
+ { path: "common/culture/innovations", kind: "innovation", requiredLoc: ["$"], rootScopes: ["culture"] },
110
+ { path: "common/culture/eras", kind: "culture_era" },
111
+
112
+ // --- Religion ---
113
+ // religion_types top-level keys are religions (akom_religion). Faiths are
114
+ // NESTED under `faiths = { faith_x = {...} }` and cannot be extracted with the
115
+ // current modes, so faiths are NOT indexed here (limitation).
116
+ { path: "common/religion/religion_types", kind: "religion", requiredLoc: ["$"] },
117
+ // doctrine_types top-level keys ARE the doctrine names (doctrine_monogamy),
118
+ // which is exactly what `has_doctrine =` references. Doctrine *groups* live in
119
+ // doctrine_group_types (indexed separately).
120
+ { path: "common/religion/doctrine_types", kind: "doctrine", rootScopes: ["character", "faith"] },
121
+ { path: "common/religion/doctrine_group_types", kind: "doctrine_group" },
122
+ { path: "common/religion/holy_site_types", kind: "holy_site" },
123
+
124
+ // --- Dynasties ---
125
+ // dynasties top-level keys are numeric ids; huge and never typed → not completable.
126
+ { path: "common/dynasties", kind: "dynasty", completable: false },
127
+ { path: "common/dynasty_houses", kind: "dynasty_house", completable: false },
128
+ { path: "common/dynasty_legacies", kind: "dynasty_legacy" },
129
+ { path: "common/dynasty_perks", kind: "dynasty_perk" },
130
+
131
+ // --- Activities & schemes ---
132
+ { path: "common/activities/activity_types", kind: "activity_type", rootScopes: ["character"] },
133
+ {
134
+ path: "common/schemes/scheme_types",
135
+ kind: "scheme_type",
136
+ requiredLoc: ["$"],
137
+ rootScopes: ["character", "scheme"],
138
+ },
139
+ { path: "common/travel/point_of_interest_types", kind: "point_of_interest", rootScopes: ["character"] },
140
+ { path: "common/travel/travel_options", kind: "travel_option", rootScopes: ["character"] },
141
+
142
+ // --- Artifacts ---
143
+ { path: "common/artifacts/types", kind: "artifact_type" },
144
+ { path: "common/artifacts/templates", kind: "artifact_template", rootScopes: ["character"] },
145
+ { path: "common/artifacts/visuals", kind: "artifact_visual" },
146
+ { path: "common/artifacts/slots", kind: "artifact_slot" },
147
+
148
+ // --- Struggles, legends, situations ---
149
+ { path: "common/struggle/struggles", kind: "struggle" },
150
+ { path: "common/legends/legend_types", kind: "legend_type", rootScopes: ["legend", "character"] },
151
+ { path: "common/legends/chronicles", kind: "chronicle" },
152
+ { path: "common/situation/situations", kind: "situation", rootScopes: ["situation", "character"] },
153
+
154
+ // --- Accolades, diarchies ---
155
+ { path: "common/accolade_types", kind: "accolade_type", rootScopes: ["character"] },
156
+ { path: "common/accolade_names", kind: "accolade_name", rootScopes: ["accolade"] },
157
+ { path: "common/diarchies/diarchy_types", kind: "diarchy_type" },
158
+ { path: "common/diarchies/diarchy_mandates", kind: "diarchy_mandate" },
159
+
160
+ // --- Modifiers ---
161
+ // common/modifiers are static modifiers referenced by add_*_modifier = x.
162
+ { path: "common/modifiers", kind: "static_modifier" },
163
+ { path: "common/opinion_modifiers", kind: "opinion_modifier" },
164
+
165
+ // --- Events presentation ---
166
+ { path: "common/event_backgrounds", kind: "event_background", rootScopes: ["character"] },
167
+ { path: "common/event_themes", kind: "event_theme" },
168
+ { path: "common/story_cycles", kind: "story_cycle", rootScopes: ["story"] },
169
+
170
+ // --- Scripted helpers / rules ---
171
+ { path: "common/scripted_guis", kind: "scripted_gui", rootScopes: ["character"] },
172
+ { path: "common/scripted_rules", kind: "scripted_rule" },
173
+ { path: "common/scripted_lists", kind: "scripted_list" },
174
+ { path: "common/scripted_costs", kind: "scripted_cost" },
175
+ { path: "common/customizable_localization", kind: "customizable_localization" },
176
+ { path: "common/game_rules", kind: "game_rule" },
177
+ { path: "common/flavorization", kind: "flavorization" },
178
+
179
+ // --- GUI ---
180
+ { path: "gui", kind: "gui_type", ext: ".gui", extraction: "gui-type" },
181
+
182
+ // --- History (huge, never typed → not completable) ---
183
+ { path: "history/characters", kind: "character", completable: false },
184
+ { path: "history/provinces", kind: "province_history", completable: false },
185
+
186
+ // --- Coat of arms (huge → not completable) ---
187
+ { path: "common/coat_of_arms/coat_of_arms", kind: "coat_of_arms", completable: false },
188
+
189
+ // --- 2026-07 coverage audit (scripts/audit-schema-coverage.ts): every
190
+ // remaining common/ folder with a standard top-level `name = { ... }`
191
+ // layout, verified by parsing vanilla files. Ordered by definition count.
192
+ { path: "common/game_concepts", kind: "game_concept", requiredLoc: ["game_concept_$"] },
193
+ { path: "common/domiciles/buildings", kind: "domicile_building", rootScopes: ["character", "domicile"] },
194
+ { path: "common/domiciles/types", kind: "domicile_type", rootScopes: ["character"] },
195
+ { path: "common/artifacts/features", kind: "artifact_feature" },
196
+ { path: "common/artifacts/feature_groups", kind: "artifact_feature_group" },
197
+ { path: "common/schemes/pulse_actions", kind: "scheme_pulse_action" },
198
+ { path: "common/schemes/agent_types", kind: "scheme_agent_type", rootScopes: ["character"] },
199
+ { path: "common/schemes/scheme_countermeasures", kind: "scheme_countermeasure" },
200
+ { path: "common/message_filter_types", kind: "message_filter_type" },
201
+ { path: "common/message_group_types", kind: "message_group_type" },
202
+ { path: "common/messages", kind: "message" },
203
+ { path: "common/culture/creation_names", kind: "culture_creation_name", rootScopes: ["culture"] },
204
+ { path: "common/culture/name_lists", kind: "name_list" },
205
+ { path: "common/culture/name_equivalency", kind: "name_equivalency", completable: false },
206
+ { path: "common/culture/aesthetics_bundles", kind: "aesthetics_bundle" },
207
+ { path: "common/struggle/catalysts", kind: "struggle_catalyst" },
208
+ { path: "common/situation/catalysts", kind: "situation_catalyst" },
209
+ { path: "common/situation/situation_group_types", kind: "situation_group_type" },
210
+ { path: "common/trigger_localization", kind: "trigger_localization" },
211
+ { path: "common/effect_localization", kind: "effect_localization" },
212
+ { path: "common/dynasty_house_mottos", kind: "house_motto" },
213
+ { path: "common/dynasty_house_motto_inserts", kind: "house_motto_insert" },
214
+ { path: "common/task_contracts", kind: "task_contract", rootScopes: ["character"] },
215
+ { path: "common/activities/guest_invite_rules", kind: "guest_invite_rule", rootScopes: ["character"] },
216
+ { path: "common/activities/pulse_actions", kind: "activity_pulse_action" },
217
+ { path: "common/activities/intents", kind: "activity_intent", rootScopes: ["character"] },
218
+ { path: "common/activities/activity_group_types", kind: "activity_group_type" },
219
+ { path: "common/activities/activity_locales", kind: "activity_locale" },
220
+ { path: "common/bookmarks/bookmarks", kind: "bookmark" },
221
+ { path: "common/bookmarks/groups", kind: "bookmark_group" },
222
+ { path: "common/bookmarks/challenge_characters", kind: "challenge_character" },
223
+ { path: "common/achievements", kind: "achievement" },
224
+ { path: "common/legends/legend_seeds", kind: "legend_seed" },
225
+ { path: "common/scripted_relations", kind: "scripted_relation", rootScopes: ["character"] },
226
+ { path: "common/event_transitions", kind: "event_transition" },
227
+ // Formatting for code-defined modifier types (2026-07 mod audit: mods add
228
+ // formats for their dynamic modifiers). Names mirror code modifiers, so they
229
+ // are indexed for hover/structure but not offered in completion.
230
+ { path: "common/modifier_definition_formats", kind: "modifier_definition_format", completable: false },
231
+ { path: "common/event_2d_effects", kind: "event_2d_effect" },
232
+ { path: "common/house_aspirations", kind: "house_aspiration" },
233
+ { path: "common/house_relation_types", kind: "house_relation_type" },
234
+ { path: "common/house_unities", kind: "house_unity" },
235
+ { path: "common/tutorial_lessons", kind: "tutorial_lesson" },
236
+ { path: "common/tutorial_lesson_chains", kind: "tutorial_lesson_chain" },
237
+ { path: "common/decision_group_types", kind: "decision_group_type" },
238
+ { path: "common/character_interaction_categories", kind: "character_interaction_category" },
239
+ { path: "common/playable_difficulty_infos", kind: "playable_difficulty_info" },
240
+ { path: "common/combat_phase_events", kind: "combat_phase_event", rootScopes: ["character"] },
241
+ { path: "common/inspirations", kind: "inspiration", rootScopes: ["inspiration", "character"] },
242
+ { path: "common/legitimacy", kind: "legitimacy_level", rootScopes: ["character"] },
243
+ { path: "common/tax_slots/obligations", kind: "tax_obligation", rootScopes: ["character"] },
244
+ { path: "common/ai_war_stances", kind: "ai_war_stance" },
245
+ { path: "common/confederation_types", kind: "confederation_type" },
246
+ { path: "common/epidemics", kind: "epidemic", rootScopes: ["epidemic", "character"] },
247
+ { path: "common/factions", kind: "faction", rootScopes: ["faction", "character"] },
248
+ { path: "common/pool_character_selectors", kind: "pool_character_selector" },
249
+ { path: "common/religion/religion_family_types", kind: "religion_family" },
250
+ { path: "common/succession_appointment", kind: "succession_appointment", rootScopes: ["landed_title"] },
251
+ { path: "common/succession_election", kind: "succession_election", rootScopes: ["landed_title"] },
252
+ { path: "common/ruler_objective_advice_types", kind: "ruler_objective_advice" },
253
+ { path: "common/raids/intents", kind: "raid_intent" },
254
+ { path: "common/lease_contracts", kind: "lease_contract" },
255
+ { path: "common/scripted_animations", kind: "scripted_animation" },
256
+
257
+ // gfx/ surfaces with script-referenced names (layouts probed in vanilla):
258
+ { path: "gfx/portraits/portrait_modifiers", kind: "portrait_modifier_group" },
259
+ { path: "gfx/portraits/trait_portrait_modifiers", kind: "trait_portrait_modifier_group" },
260
+ { path: "gfx/portraits/portrait_animations", kind: "portrait_animation" },
261
+ { path: "gfx/court_scene/character_groups", kind: "court_scene_group" },
262
+ { path: "gfx/court_scene/character_roles", kind: "court_scene_role" },
263
+ { path: "gfx/court_scene/scene_cultures", kind: "court_scene_culture" },
264
+ { path: "gfx/interface/illustrations/scripted_illustrations", kind: "scripted_illustration" },
265
+ ];
266
+
267
+ /**
268
+ * The bundled schema with the §B2 `structure` and §B3 `ambientScopes` layers
269
+ * attached by kind (kept out of the table above so it stays readable). Static —
270
+ * no runtime harvest — so completion/hover work without gamePath set.
271
+ */
272
+ export const CK3_SCHEMA: SchemaEntry[] = CK3_SCHEMA_BASE.map((entry) => {
273
+ const structure = STRUCTURES[entry.kind];
274
+ const ambientScopes = AMBIENT_SCOPES[entry.kind];
275
+ if (!structure && !ambientScopes) return entry;
276
+ return { ...entry, ...(structure && { structure }), ...(ambientScopes && { ambientScopes }) };
277
+ });
278
+
279
+ // Not covered (layout doesn't fit any extraction mode, or wrong-data risk):
280
+ // - Faiths: nested under religion_types' `faiths = { ... }` blocks; only the
281
+ // top-level religions are indexable. Faiths would need a dedicated mode.
282
+ // - Individual laws: common/laws top-level keys are law *groups*; the actual
283
+ // laws are second-level (only law_group indexed).
284
+ // - common/defines, common/named_colors,
285
+ // common/genes, common/ethnicities, common/coat_of_arms/dynamic_definitions:
286
+ // these are engine/data config, not script-referenced named definitions in
287
+ // the usual sense.
288
+ // - common/dna_data: keys are portrait ids referenced only via dna = "..." in
289
+ // history; low modding traffic, skipped.
290
+ // - 2026-07 audit deliberate skips: common/console_groups,
291
+ // common/connection_arrows, common/modifier_icons, common/portrait_types,
292
+ // common/graphical_unit_types, common/ai_goaltypes, common/guest_system,
293
+ // common/courtier_guest_management, common/coat_of_arms/options and
294
+ // template_lists (engine/UI config); common/bookmark_portraits (332 files
295
+ // of portrait data, never referenced from script); common/accolade_icons
296
+ // (no parseable defs); common/artifacts/blueprints and
297
+ // common/province_terrain (non-standard layout, would need a mode).
298
+ // - history/cultures|situations|struggles: top-level keys are DATES
299
+ // (867.1.1 = { ... }); the identity comes from the filename, so standard
300
+ // extraction would index garbage.
301
+ // - music/ (.asset format), dlc_metadata, reader_export, and the remaining
302
+ // gfx/ art-config folders (map styles, unit states, accessory_variations,
303
+ // hud_skins, loading_screens): art/engine data, not script-referenced.
304
+ // (Full gap list: scripts/audit-schema-coverage.ts.)
305
+
306
+ /** Assignment keys whose values reference other definitions. */
307
+ export const REF_FIELDS: RefField[] = [
308
+ // Events & on_actions
309
+ { key: "trigger_event", kinds: ["event"] }, // also block form { id = x }; `id` too generic to add safely
310
+ { key: "on_action", kinds: ["on_action"] }, // trigger_event = { on_action = x }, scheme phases, travel…
311
+ { key: "on_actions", kinds: ["on_action"], form: "list" },
312
+ // Weighted block (`<weight> = <on_action>`) and fallback list, like random_events.
313
+ { key: "random_on_action", kinds: ["on_action"], form: "list", weighted: true },
314
+ { key: "first_valid_on_action", kinds: ["on_action"], form: "list" },
315
+ { key: "events", kinds: ["event"], form: "list" },
316
+ { key: "random_events", kinds: ["event"], form: "list", weighted: true },
317
+ { key: "first_valid", kinds: ["event"], form: "list" },
318
+ // `theme = X` in events: X is an event theme, never the faith/culture scope
319
+ // link of the same name — the ref kind lets hover/semantic tokens disambiguate.
320
+ { key: "theme", kinds: ["event_theme"] },
321
+
322
+ // Traits. Trait GROUPS (`group = X` inside a trait) act as virtual traits in
323
+ // these fields, so both kinds are carried.
324
+ { key: "trait", kinds: ["trait", "trait_group"] },
325
+ { key: "add_trait", kinds: ["trait"] },
326
+ { key: "remove_trait", kinds: ["trait"] },
327
+ { key: "has_trait", kinds: ["trait", "trait_group"] },
328
+
329
+ // Nicknames
330
+ { key: "give_nickname", kinds: ["nickname"] },
331
+ { key: "set_nickname", kinds: ["nickname"] },
332
+ { key: "has_nickname", kinds: ["nickname"] },
333
+
334
+ // Perks / focuses / lifestyles
335
+ { key: "add_perk", kinds: ["perk"] },
336
+ { key: "remove_perk", kinds: ["perk"] },
337
+ { key: "has_perk", kinds: ["perk"] },
338
+ { key: "set_focus", kinds: ["focus"] },
339
+ { key: "has_focus", kinds: ["focus"] },
340
+ { key: "has_lifestyle", kinds: ["lifestyle"] },
341
+
342
+ // Religion / faith / culture (scalar forms without prefix, common in history)
343
+ { key: "doctrine", kinds: ["doctrine"] },
344
+ { key: "has_doctrine", kinds: ["doctrine"] },
345
+ { key: "religion", kinds: ["religion"] },
346
+ { key: "set_religion", kinds: ["religion"] },
347
+ { key: "faith", kinds: ["faith"] },
348
+ { key: "set_faith", kinds: ["faith"] },
349
+ { key: "culture", kinds: ["culture"] },
350
+ { key: "set_culture", kinds: ["culture"] },
351
+
352
+ // Culture innovations / traditions
353
+ { key: "has_innovation", kinds: ["innovation"] },
354
+ { key: "add_innovation", kinds: ["innovation"] },
355
+ { key: "discover_innovation", kinds: ["innovation"] },
356
+ { key: "has_cultural_tradition", kinds: ["culture_tradition"] },
357
+ { key: "has_tradition", kinds: ["culture_tradition"] },
358
+ { key: "add_tradition", kinds: ["culture_tradition"] },
359
+
360
+ // Buildings / holdings
361
+ { key: "has_building", kinds: ["building"] },
362
+ { key: "has_building_or_higher", kinds: ["building"] },
363
+
364
+ // Governments / laws
365
+ { key: "government", kinds: ["government"] },
366
+ { key: "change_government", kinds: ["government"] },
367
+ { key: "has_government", kinds: ["government"] },
368
+
369
+ // Modifiers. `modifier` and add_*_modifier can reference static/opinion/scripted
370
+ // modifiers depending on context; carry all candidate kinds on the reference.
371
+ {
372
+ key: "add_character_modifier",
373
+ kinds: ["static_modifier"],
374
+ },
375
+ { key: "remove_character_modifier", kinds: ["static_modifier"] },
376
+ { key: "has_character_modifier", kinds: ["static_modifier"] },
377
+ { key: "add_county_modifier", kinds: ["static_modifier"] },
378
+ { key: "add_province_modifier", kinds: ["static_modifier"] },
379
+ { key: "add_dynasty_modifier", kinds: ["static_modifier"] },
380
+ { key: "add_house_modifier", kinds: ["static_modifier"] },
381
+ {
382
+ key: "modifier",
383
+ kinds: ["static_modifier", "opinion_modifier", "scripted_modifier"],
384
+ },
385
+ { key: "add_opinion", kinds: ["opinion_modifier"] },
386
+ { key: "reverse_add_opinion", kinds: ["opinion_modifier"] },
387
+
388
+ // Casus belli
389
+ { key: "casus_belli", kinds: ["casus_belli"] },
390
+ { key: "using_cb", kinds: ["casus_belli"] },
391
+
392
+ // Court positions
393
+ { key: "court_position", kinds: ["court_position"] },
394
+ { key: "has_court_position", kinds: ["court_position"] },
395
+ ];
396
+
397
+ /**
398
+ * Keys too generic for a global ref field, resolved by their enclosing block:
399
+ * `id` means an event only inside `trigger_event = { … }`, `reference` names an
400
+ * event background/transition/2d-effect only inside the matching override_*
401
+ * block. (override_icon/_header_background/_sound references are texture paths
402
+ * and sound events, not indexed definitions — nothing to offer.)
403
+ */
404
+ export const BLOCK_REF_FIELDS: Record<string, Record<string, string[]>> = {
405
+ trigger_event: { id: ["event"] },
406
+ override_background: { reference: ["event_background"] },
407
+ override_transition: { reference: ["event_transition"] },
408
+ override_effect_2d: { reference: ["event_2d_effect"] },
409
+ // Engine-level variable/list ops shared by every Jomini game.
410
+ ...JOMINI_VARIABLE_BLOCK_REFS,
411
+ };
412
+
413
+ /** Scalar-value prefixes that reference definitions (`culture:czech` → culture). */
414
+ export const PREFIX_REFS: Record<string, string[]> = {
415
+ culture: ["culture"],
416
+ faith: ["faith"],
417
+ religion: ["religion"],
418
+ title: ["landed_title"],
419
+ character: ["character"],
420
+ dynasty: ["dynasty"],
421
+ house: ["dynasty_house"],
422
+ };