intelligent-system-design-language 0.3.13

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 (209) hide show
  1. package/.claude/agents/langium-language-designer.md +38 -0
  2. package/.claude/agents/typescript-vscode-expert.md +29 -0
  3. package/.claude/agents/ui-ux-designer.md +36 -0
  4. package/.claude/settings.local.json +33 -0
  5. package/.idea/inspectionProfiles/Project_Default.xml +7 -0
  6. package/.idea/isdl.iml +14 -0
  7. package/.idea/modules.xml +9 -0
  8. package/.idea/vcs.xml +7 -0
  9. package/.idea/watcherTasks.xml +4 -0
  10. package/.vscodeignore +18 -0
  11. package/LICENSE +674 -0
  12. package/README.md +86 -0
  13. package/bin/cli.js +4 -0
  14. package/bin/lsp.js +8 -0
  15. package/isdl.png +0 -0
  16. package/out/_backgrounds.scss +91 -0
  17. package/out/_handlebars.scss +505 -0
  18. package/out/_isdlStyles.scss +1357 -0
  19. package/out/_vuetifyOverrides.scss +425 -0
  20. package/out/_vuetifyStyles.scss +31957 -0
  21. package/out/cli/cli-util.js +39 -0
  22. package/out/cli/cli-util.js.map +1 -0
  23. package/out/cli/components/_backgrounds.scss +91 -0
  24. package/out/cli/components/_handlebars.scss +505 -0
  25. package/out/cli/components/_isdlStyles.scss +1357 -0
  26. package/out/cli/components/_vuetifyOverrides.scss +425 -0
  27. package/out/cli/components/_vuetifyStyles.scss +31957 -0
  28. package/out/cli/components/active-effect-sheet-generator.js +643 -0
  29. package/out/cli/components/active-effect-sheet-generator.js.map +1 -0
  30. package/out/cli/components/base-actor-sheet-generator.js +125 -0
  31. package/out/cli/components/base-actor-sheet-generator.js.map +1 -0
  32. package/out/cli/components/base-sheet-generator.js +525 -0
  33. package/out/cli/components/base-sheet-generator.js.map +1 -0
  34. package/out/cli/components/chat-card-generator.js +683 -0
  35. package/out/cli/components/chat-card-generator.js.map +1 -0
  36. package/out/cli/components/css-generator.js +58 -0
  37. package/out/cli/components/css-generator.js.map +1 -0
  38. package/out/cli/components/damage-roll-generator.js +173 -0
  39. package/out/cli/components/damage-roll-generator.js.map +1 -0
  40. package/out/cli/components/datamodel-generator.js +672 -0
  41. package/out/cli/components/datamodel-generator.js.map +1 -0
  42. package/out/cli/components/derived-data-generator.js +1340 -0
  43. package/out/cli/components/derived-data-generator.js.map +1 -0
  44. package/out/cli/components/hotbar-drop-hook-generator.js +95 -0
  45. package/out/cli/components/hotbar-drop-hook-generator.js.map +1 -0
  46. package/out/cli/components/init-hook-generator.js +597 -0
  47. package/out/cli/components/init-hook-generator.js.map +1 -0
  48. package/out/cli/components/keywords-generator.js +220 -0
  49. package/out/cli/components/keywords-generator.js.map +1 -0
  50. package/out/cli/components/language-generator.js +110 -0
  51. package/out/cli/components/language-generator.js.map +1 -0
  52. package/out/cli/components/measured-template-preview.js +234 -0
  53. package/out/cli/components/measured-template-preview.js.map +1 -0
  54. package/out/cli/components/method-generator.js +1812 -0
  55. package/out/cli/components/method-generator.js.map +1 -0
  56. package/out/cli/components/ready-hook-generator.js +448 -0
  57. package/out/cli/components/ready-hook-generator.js.map +1 -0
  58. package/out/cli/components/token-generator.js +138 -0
  59. package/out/cli/components/token-generator.js.map +1 -0
  60. package/out/cli/components/utils.js +176 -0
  61. package/out/cli/components/utils.js.map +1 -0
  62. package/out/cli/components/vue/base-components/vue-attribute.js +148 -0
  63. package/out/cli/components/vue/base-components/vue-attribute.js.map +1 -0
  64. package/out/cli/components/vue/base-components/vue-boolean.js +77 -0
  65. package/out/cli/components/vue/base-components/vue-boolean.js.map +1 -0
  66. package/out/cli/components/vue/base-components/vue-calculator.js +106 -0
  67. package/out/cli/components/vue/base-components/vue-calculator.js.map +1 -0
  68. package/out/cli/components/vue/base-components/vue-damage-application.js +369 -0
  69. package/out/cli/components/vue/base-components/vue-damage-application.js.map +1 -0
  70. package/out/cli/components/vue/base-components/vue-damage-bonuses.js +225 -0
  71. package/out/cli/components/vue/base-components/vue-damage-bonuses.js.map +1 -0
  72. package/out/cli/components/vue/base-components/vue-damage-resistances.js +256 -0
  73. package/out/cli/components/vue/base-components/vue-damage-resistances.js.map +1 -0
  74. package/out/cli/components/vue/base-components/vue-damage-track.js +134 -0
  75. package/out/cli/components/vue/base-components/vue-damage-track.js.map +1 -0
  76. package/out/cli/components/vue/base-components/vue-date-time.js +55 -0
  77. package/out/cli/components/vue/base-components/vue-date-time.js.map +1 -0
  78. package/out/cli/components/vue/base-components/vue-dice.js +111 -0
  79. package/out/cli/components/vue/base-components/vue-dice.js.map +1 -0
  80. package/out/cli/components/vue/base-components/vue-die.js +86 -0
  81. package/out/cli/components/vue/base-components/vue-die.js.map +1 -0
  82. package/out/cli/components/vue/base-components/vue-document-choice.js +172 -0
  83. package/out/cli/components/vue/base-components/vue-document-choice.js.map +1 -0
  84. package/out/cli/components/vue/base-components/vue-document-choices.js +203 -0
  85. package/out/cli/components/vue/base-components/vue-document-choices.js.map +1 -0
  86. package/out/cli/components/vue/base-components/vue-document-link.js +73 -0
  87. package/out/cli/components/vue/base-components/vue-document-link.js.map +1 -0
  88. package/out/cli/components/vue/base-components/vue-extended-choice.js +101 -0
  89. package/out/cli/components/vue/base-components/vue-extended-choice.js.map +1 -0
  90. package/out/cli/components/vue/base-components/vue-inventory.js +532 -0
  91. package/out/cli/components/vue/base-components/vue-inventory.js.map +1 -0
  92. package/out/cli/components/vue/base-components/vue-macro-choice.js +150 -0
  93. package/out/cli/components/vue/base-components/vue-macro-choice.js.map +1 -0
  94. package/out/cli/components/vue/base-components/vue-measured-template.js +543 -0
  95. package/out/cli/components/vue/base-components/vue-measured-template.js.map +1 -0
  96. package/out/cli/components/vue/base-components/vue-money.js +496 -0
  97. package/out/cli/components/vue/base-components/vue-money.js.map +1 -0
  98. package/out/cli/components/vue/base-components/vue-number.js +184 -0
  99. package/out/cli/components/vue/base-components/vue-number.js.map +1 -0
  100. package/out/cli/components/vue/base-components/vue-paperdoll.js +56 -0
  101. package/out/cli/components/vue/base-components/vue-paperdoll.js.map +1 -0
  102. package/out/cli/components/vue/base-components/vue-parent-property-reference.js +89 -0
  103. package/out/cli/components/vue/base-components/vue-parent-property-reference.js.map +1 -0
  104. package/out/cli/components/vue/base-components/vue-prosemirror.js +31 -0
  105. package/out/cli/components/vue/base-components/vue-prosemirror.js.map +1 -0
  106. package/out/cli/components/vue/base-components/vue-resource.js +149 -0
  107. package/out/cli/components/vue/base-components/vue-resource.js.map +1 -0
  108. package/out/cli/components/vue/base-components/vue-roll-visualizer.js +121 -0
  109. package/out/cli/components/vue/base-components/vue-roll-visualizer.js.map +1 -0
  110. package/out/cli/components/vue/base-components/vue-self-property-reference.js +75 -0
  111. package/out/cli/components/vue/base-components/vue-self-property-reference.js.map +1 -0
  112. package/out/cli/components/vue/base-components/vue-string-choice.js +111 -0
  113. package/out/cli/components/vue/base-components/vue-string-choice.js.map +1 -0
  114. package/out/cli/components/vue/base-components/vue-string-choices.js +216 -0
  115. package/out/cli/components/vue/base-components/vue-string-choices.js.map +1 -0
  116. package/out/cli/components/vue/base-components/vue-string.js +73 -0
  117. package/out/cli/components/vue/base-components/vue-string.js.map +1 -0
  118. package/out/cli/components/vue/base-components/vue-text-field.js +66 -0
  119. package/out/cli/components/vue/base-components/vue-text-field.js.map +1 -0
  120. package/out/cli/components/vue/base-components/vue-tracker.js +444 -0
  121. package/out/cli/components/vue/base-components/vue-tracker.js.map +1 -0
  122. package/out/cli/components/vue/vue-action-component-generator.js +88 -0
  123. package/out/cli/components/vue/vue-action-component-generator.js.map +1 -0
  124. package/out/cli/components/vue/vue-active-effect-sheet-generator.js +1016 -0
  125. package/out/cli/components/vue/vue-active-effect-sheet-generator.js.map +1 -0
  126. package/out/cli/components/vue/vue-base-components-generator.js +59 -0
  127. package/out/cli/components/vue/vue-base-components-generator.js.map +1 -0
  128. package/out/cli/components/vue/vue-datatable-component-generator.js +307 -0
  129. package/out/cli/components/vue/vue-datatable-component-generator.js.map +1 -0
  130. package/out/cli/components/vue/vue-datatable-sheet-class-generator.js +342 -0
  131. package/out/cli/components/vue/vue-datatable-sheet-class-generator.js.map +1 -0
  132. package/out/cli/components/vue/vue-datatable2-component-generator.js +939 -0
  133. package/out/cli/components/vue/vue-datatable2-component-generator.js.map +1 -0
  134. package/out/cli/components/vue/vue-document-creation-app.js +140 -0
  135. package/out/cli/components/vue/vue-document-creation-app.js.map +1 -0
  136. package/out/cli/components/vue/vue-document-creation-sheet.js +105 -0
  137. package/out/cli/components/vue/vue-document-creation-sheet.js.map +1 -0
  138. package/out/cli/components/vue/vue-generator.js +240 -0
  139. package/out/cli/components/vue/vue-generator.js.map +1 -0
  140. package/out/cli/components/vue/vue-mixin.js +338 -0
  141. package/out/cli/components/vue/vue-mixin.js.map +1 -0
  142. package/out/cli/components/vue/vue-pinned-datatable-component-generator.js +306 -0
  143. package/out/cli/components/vue/vue-pinned-datatable-component-generator.js.map +1 -0
  144. package/out/cli/components/vue/vue-prompt-generator.js +201 -0
  145. package/out/cli/components/vue/vue-prompt-generator.js.map +1 -0
  146. package/out/cli/components/vue/vue-prompt-sheet-class-generator.js +252 -0
  147. package/out/cli/components/vue/vue-prompt-sheet-class-generator.js.map +1 -0
  148. package/out/cli/components/vue/vue-sheet-application-generator.js +2008 -0
  149. package/out/cli/components/vue/vue-sheet-application-generator.js.map +1 -0
  150. package/out/cli/components/vue/vue-sheet-class-generator.js +484 -0
  151. package/out/cli/components/vue/vue-sheet-class-generator.js.map +1 -0
  152. package/out/cli/generator.js +659 -0
  153. package/out/cli/generator.js.map +1 -0
  154. package/out/cli/main.js +43 -0
  155. package/out/cli/main.js.map +1 -0
  156. package/out/datatables.min.css +54 -0
  157. package/out/datatables.min.js +178 -0
  158. package/out/extension/github/githubAuthProvider.js +345 -0
  159. package/out/extension/github/githubAuthProvider.js.map +1 -0
  160. package/out/extension/github/githubConfig.js +132 -0
  161. package/out/extension/github/githubConfig.js.map +1 -0
  162. package/out/extension/github/githubGistActions.js +251 -0
  163. package/out/extension/github/githubGistActions.js.map +1 -0
  164. package/out/extension/github/githubGistManager.js +255 -0
  165. package/out/extension/github/githubGistManager.js.map +1 -0
  166. package/out/extension/github/githubManager.js +1735 -0
  167. package/out/extension/github/githubManager.js.map +1 -0
  168. package/out/extension/github/githubQuickActions.js +659 -0
  169. package/out/extension/github/githubQuickActions.js.map +1 -0
  170. package/out/extension/github/githubTreeProvider.js +181 -0
  171. package/out/extension/github/githubTreeProvider.js.map +1 -0
  172. package/out/extension/github/system-workflow.yml +48 -0
  173. package/out/extension/main.cjs +70315 -0
  174. package/out/extension/main.cjs.map +7 -0
  175. package/out/extension/main.js +237 -0
  176. package/out/extension/main.js.map +1 -0
  177. package/out/extension/package.json +426 -0
  178. package/out/isdl.png +0 -0
  179. package/out/language/generated/ast.js +2992 -0
  180. package/out/language/generated/ast.js.map +1 -0
  181. package/out/language/generated/grammar.js +13970 -0
  182. package/out/language/generated/grammar.js.map +1 -0
  183. package/out/language/generated/module.js +20 -0
  184. package/out/language/generated/module.js.map +1 -0
  185. package/out/language/intelligent-system-design-language-formatter.js +85 -0
  186. package/out/language/intelligent-system-design-language-formatter.js.map +1 -0
  187. package/out/language/intelligent-system-design-language-module.js +69 -0
  188. package/out/language/intelligent-system-design-language-module.js.map +1 -0
  189. package/out/language/intelligent-system-design-language-quickfixes.js +37 -0
  190. package/out/language/intelligent-system-design-language-quickfixes.js.map +1 -0
  191. package/out/language/intelligent-system-design-language-validator.js +515 -0
  192. package/out/language/intelligent-system-design-language-validator.js.map +1 -0
  193. package/out/language/isdl-hover-provider.js +77 -0
  194. package/out/language/isdl-hover-provider.js.map +1 -0
  195. package/out/language/isdl-scope-provider.js +149 -0
  196. package/out/language/isdl-scope-provider.js.map +1 -0
  197. package/out/language/main.cjs +47655 -0
  198. package/out/language/main.cjs.map +7 -0
  199. package/out/language/main.js +11 -0
  200. package/out/language/main.js.map +1 -0
  201. package/out/missing-character.png +0 -0
  202. package/out/package.json +426 -0
  203. package/out/paperdoll_default.png +0 -0
  204. package/out/progressbar.min.js +7 -0
  205. package/out/styles.scss +722 -0
  206. package/out/test/formatting/formatter.test.js +46 -0
  207. package/out/test/formatting/formatter.test.js.map +1 -0
  208. package/out/vuetify.esm.js +30279 -0
  209. package/package.json +426 -0
@@ -0,0 +1,643 @@
1
+ import { expandToNode, joinToNode, toString } from 'langium/generate';
2
+ import * as fs from 'node:fs';
3
+ import * as path from 'node:path';
4
+ import { isAccess, isAction, isActor, isAttributeExp, isBooleanExp, isHookHandler, isHtmlExp, isIfStatement, isInitiativeProperty, isNumberExp, isNumberParamValue, isProperty, isResourceExp, isSection, isStatusProperty, isStringExp, isTrackerExp, isLayout, isMacroField, isDamageTypeChoiceField, isStringParamChoices } from '../../language/generated/ast.js';
5
+ import { getSystemPath, getAllOfType } from './utils.js';
6
+ export function generateBaseActiveEffectBaseSheet(entry, id, destination) {
7
+ const generatedFileDir = path.join(destination, "system", "sheets", "vue");
8
+ const generatedFilePath = path.join(generatedFileDir, `active-effect-sheet.mjs`);
9
+ if (!fs.existsSync(generatedFileDir)) {
10
+ fs.mkdirSync(generatedFileDir, { recursive: true });
11
+ }
12
+ function generateAddValue(document, property) {
13
+ if (isAccess(property) || isAction(property) || isIfStatement(property) || isHookHandler(property) || isMacroField(property))
14
+ return undefined;
15
+ if (isLayout(property)) {
16
+ return joinToNode(property.body, property => generateAddValue(document, property), { appendNewLineIfNotEmpty: true });
17
+ }
18
+ if (isHtmlExp(property) || isInitiativeProperty(property) || isStatusProperty(property) || !isProperty(property))
19
+ return;
20
+ if (property.modifier == "locked")
21
+ return;
22
+ if (isResourceExp(property)) {
23
+ return expandToNode `
24
+ addChange("${document.name.toLowerCase()}", "${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.value", 1);
25
+ addChange("${document.name.toLowerCase()}", "${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.max");
26
+ `;
27
+ }
28
+ if (isTrackerExp(property)) {
29
+ return expandToNode `
30
+ addChange("${document.name.toLowerCase()}", "${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.min");
31
+ addChange("${document.name.toLowerCase()}", "${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.value", 1);
32
+ addChange("${document.name.toLowerCase()}", "${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.temp", 1);
33
+ addChange("${document.name.toLowerCase()}", "${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.max");
34
+ `;
35
+ }
36
+ if (isAttributeExp(property)) {
37
+ return expandToNode `
38
+ addChange("${document.name.toLowerCase()}", "${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.value");
39
+ addChange("${document.name.toLowerCase()}", "${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.max");
40
+ `;
41
+ }
42
+ if (isNumberExp(property)) {
43
+ return expandToNode `
44
+ addChange("${document.name.toLowerCase()}", "${document.name.toLowerCase()}.system.${property.name.toLowerCase()}", 1);
45
+ `;
46
+ }
47
+ return expandToNode `
48
+ addChange("${document.name.toLowerCase()}", "${document.name.toLowerCase()}.${getSystemPath(property)}");
49
+ `;
50
+ }
51
+ function generateDamageTypeActiveEffectFields(entry, document) {
52
+ if (!isActor(document))
53
+ return expandToNode ``;
54
+ const damageTypes = collectDamageTypes(entry);
55
+ if (damageTypes.length === 0) {
56
+ return expandToNode ``;
57
+ }
58
+ const damageTypeFields = damageTypes.map(damageType => {
59
+ const safeTypeName = damageType.toLowerCase().replace(/[^a-z0-9]/g, '');
60
+ return expandToNode `
61
+ // ${damageType} damage type Active Effect fields
62
+ addChange("${document.name.toLowerCase()}", "${document.name.toLowerCase()}.system.${safeTypeName}bonusdamage");
63
+ addChange("${document.name.toLowerCase()}", "${document.name.toLowerCase()}.system.${safeTypeName}damageresistanceflat");
64
+ addChange("${document.name.toLowerCase()}", "${document.name.toLowerCase()}.system.${safeTypeName}damageresistancepercent");
65
+ `;
66
+ });
67
+ return expandToNode `
68
+ // Auto-generated damage type Active Effect fields
69
+ ${joinToNode(damageTypeFields, field => field, { appendNewLineIfNotEmpty: true })}
70
+ `;
71
+ }
72
+ // Collect all damage types from the entry (same function as in datamodel-generator)
73
+ function collectDamageTypes(entry) {
74
+ var _a;
75
+ const damageTypes = new Set();
76
+ // Search through all documents for damage type choice fields
77
+ for (const document of entry.documents) {
78
+ const damageTypeFields = getAllOfType(document.body, isDamageTypeChoiceField);
79
+ for (const field of damageTypeFields) {
80
+ const damageField = field; // Cast to access params
81
+ const choicesParam = (_a = damageField.params) === null || _a === void 0 ? void 0 : _a.find((p) => isStringParamChoices(p));
82
+ if (choicesParam && choicesParam.choices) {
83
+ for (const choice of choicesParam.choices) {
84
+ // Handle simple string choices like "None"
85
+ if (typeof choice.value === 'string') {
86
+ damageTypes.add(choice.value);
87
+ }
88
+ // Handle extended choices like { label: "🔥Fire", value: "Fire", ... }
89
+ else if (choice.value && typeof choice.value === 'object') {
90
+ const extendedChoice = choice.value;
91
+ // Try direct access to value property first
92
+ if (extendedChoice.value && typeof extendedChoice.value === 'string') {
93
+ damageTypes.add(extendedChoice.value);
94
+ }
95
+ // Try properties array access
96
+ else if (extendedChoice.properties && Array.isArray(extendedChoice.properties)) {
97
+ // Based on the ISDL syntax { label: "🔥Fire", value: "Fire", icon: "...", color: "...", ... }
98
+ // Property 0 = label, Property 1 = value, Property 2 = icon, Property 3 = color, rest = custom
99
+ if (extendedChoice.properties.length > 1 && extendedChoice.properties[1].value) {
100
+ const damageTypeValue = extendedChoice.properties[1].value;
101
+ damageTypes.add(damageTypeValue);
102
+ }
103
+ }
104
+ }
105
+ }
106
+ }
107
+ }
108
+ }
109
+ return Array.from(damageTypes).sort();
110
+ }
111
+ // let stringChoices = document.body.filter(x => isStringExp(x) && x.choices != undefined && x.choices.length > 0).map(x => x as StringExp);
112
+ // for (let section of document.body.filter(x => isSection(x))) {
113
+ // stringChoices = stringChoices.concat((section as Section).body.filter(x => isStringExp(x) && x.choices != undefined && x.choices.length > 0).map(x => x as StringExp));
114
+ // }
115
+ // function generateStringChoices(document: Document, property: StringExp): CompositeGeneratorNode | undefined {
116
+ // // We need to map an array of form [ "A", "B", "C" ] to an object of form { A: "A", B: "B", C: "C" }
117
+ // return expandToNode`
118
+ // context.${property.name.toLowerCase()}Choices = {
119
+ // ${joinToNode(property.choices, x => expandToNode`${toMachineIdentifier(x)}: "${document.name}.${property.name}.${x}",`.appendNewLineIfNotEmpty())}
120
+ // };
121
+ // `;
122
+ // }
123
+ const fileNode = expandToNode `
124
+ import VueRenderingMixin from './VueRenderingMixin.mjs';
125
+ import { ActiveEffectApp } from "./components/components.vue.es.mjs";
126
+ const { DOCUMENT_OWNERSHIP_LEVELS } = CONST;
127
+ export default class ${entry.config.name}EffectVueSheet extends VueRenderingMixin(foundry.applications.api.DocumentSheetV2) {
128
+
129
+ vueParts = {
130
+ "active-effect": {
131
+ component: ActiveEffectApp,
132
+ template: "<active-effect :context=\\"context\\">Vue rendering for sheet failed.</active-effect>"
133
+ }
134
+ };
135
+
136
+ _arrayEntryKey = 0;
137
+ _renderKey = 0;
138
+
139
+
140
+ /** @override */
141
+ static DEFAULT_OPTIONS = {
142
+ classes: ["${id}", "sheet", "vue-sheet", "active-effect", "active-effect-sheet"],
143
+ viewPermission: DOCUMENT_OWNERSHIP_LEVELS.LIMITED,
144
+ editPermission: DOCUMENT_OWNERSHIP_LEVELS.OWNER,
145
+ position: {
146
+ width: 600,
147
+ height: 600,
148
+ },
149
+ window: {
150
+ resizable: true,
151
+ title: "Active Effect"
152
+ },
153
+ tag: "form",
154
+ actions: {
155
+ onEditImage: this._onEditImage
156
+ },
157
+ changeActions: {
158
+ },
159
+ // Custom property that's merged into this.options
160
+ dragDrop: [
161
+ ],
162
+ form: {
163
+ handler: ${entry.config.name}EffectVueSheet._onSubmitForm,
164
+ submitOnChange: false,
165
+ submitOnClose: true,
166
+ closeOnSubmit: false
167
+ }
168
+ };
169
+
170
+ /* -------------------------------------------- */
171
+
172
+ static async _onEditImage(event, target) {
173
+ const current = foundry.utils.getProperty(this.document, target.dataset.edit);
174
+ const fp = new FilePicker({
175
+ current,
176
+ type: "image",
177
+ callback: (path) => {
178
+ this.document.update({ [target.dataset.edit]: path });
179
+ },
180
+ top: this.position.top + 40,
181
+ left: this.position.left + 10
182
+ });
183
+ return fp.browse();
184
+ }
185
+
186
+ /* -------------------------------------------- */
187
+
188
+ async _prepareContext(options) {
189
+ const context = await super._prepareContext(options);
190
+ this.object = this.document.toObject();
191
+ context.effect = this.object;
192
+ context.descriptionHTML = await TextEditor.enrichHTML(this.object.description, {secrets: this.object.isOwner});
193
+
194
+ // Status Conditions
195
+ const statuses = CONFIG.statusEffects.map(s => {
196
+ return {
197
+ id: s.id,
198
+ label: game.i18n.localize(s.name),
199
+ selected: context.effect.statuses.includes(s.id) ? "selected" : ""
200
+ };
201
+ });
202
+ context.statuses = statuses;
203
+ if ( context.effect.origin ) {
204
+ context.originLink = await TextEditor.enrichHTML("@UUID[" + context.effect.origin + "]");
205
+ }
206
+
207
+ function setValue(obj, access, value, mode) {
208
+ if ( typeof(access)=='string' ) {
209
+ access = access.split('.');
210
+ }
211
+ // Split up an access path into sub-objects, such as "system.attribute.value" => "system": {"attribute": {"value": ...}}
212
+ if ( access.length > 1 ) {
213
+ const key = access.shift();
214
+ if ( !obj[key] ) obj[key] = {};
215
+ setValue(obj[key], access, value, mode);
216
+ }
217
+ else {
218
+ obj[access[0]] = value;
219
+ obj[access[0] + "-mode"] = mode;
220
+ }
221
+ }
222
+
223
+ // Turn the changes into the friendlier format
224
+ for ( const change of context.effect.changes ) {
225
+ setValue(context, change.key, change.value, change.mode);
226
+ }
227
+
228
+ // Output initialization
229
+ const vueContext = {
230
+ // Validates both permissions and compendium status
231
+ editable: this.isEditable,
232
+ owner: this.document.isOwner,
233
+ limited: this.document.limited,
234
+
235
+ // Add the document.
236
+ object: context.effect,
237
+ document: this.document,
238
+
239
+ // Add the data to context.data for easier access, as well as flags.
240
+ system: this.document.system,
241
+ flags: this.document.flags,
242
+
243
+ // Editors
244
+ editors: {},
245
+
246
+ // Force re-renders. Defined in the vue mixin.
247
+ _renderKey: this._renderKey ?? 0,
248
+ _arrayEntryKey: this._arrayEntryKey ?? 0,
249
+ isItemEffect: this.document.parent.documentName === "Item",
250
+ originLink: context.originLink
251
+ // tabs: this._getTabs(options.parts),
252
+ };
253
+
254
+ await this._enrichEditor(vueContext, "description");
255
+
256
+ const numberTypes = ['multiply', 'add', 'downgrade', 'upgrade', 'override'];
257
+ const stringTypes = ['override'];
258
+ const booleanTypes = ['override'];
259
+
260
+ vueContext.numberModes = numberTypes.map(type => ({
261
+ value: type,
262
+ label: game.i18n.localize(\`EFFECT.CHANGES.TYPES.\${type}\`)
263
+ }));
264
+ vueContext.numberModes.push({
265
+ value: 'custom',
266
+ label: game.i18n.localize("EFFECTS.AddOnce")
267
+ });
268
+ vueContext.basicNumberModes = numberTypes.map(type => ({
269
+ value: type,
270
+ label: game.i18n.localize(\`EFFECT.CHANGES.TYPES.\${type}\`)
271
+ }));
272
+ vueContext.stringModes = stringTypes.map(type => ({
273
+ value: type,
274
+ label: game.i18n.localize(\`EFFECT.CHANGES.TYPES.\${type}\`)
275
+ }));
276
+ vueContext.booleanModes = booleanTypes.map(type => ({
277
+ value: type,
278
+ label: game.i18n.localize(\`EFFECT.CHANGES.TYPES.\${type}\`)
279
+ }));
280
+ vueContext.resourceModes = [
281
+ { value: 'custom', label: game.i18n.localize("EFFECTS.AddOnce") }
282
+ ];
283
+ vueContext.trackerModes = [
284
+ { value: 'custom', label: game.i18n.localize("EFFECTS.AddOnce") }
285
+ ];
286
+
287
+ // Copy current change values into vueContext so the Vue component can read them
288
+ for ( const change of context.effect.changes ) {
289
+ setValue(vueContext, change.key, change.value, change.mode);
290
+ }
291
+
292
+ console.dir("Vue Active Effect Context", vueContext);
293
+ return vueContext;
294
+ }
295
+
296
+
297
+ async _enrichEditor(context, field) {
298
+ const enrichmentOptions = {
299
+ // Whether to show secret blocks in the finished html
300
+ secrets: this.document.isOwner,
301
+ // Data to fill in for inline rolls
302
+ rollData: {},
303
+ // Relative UUID resolution
304
+ relativeTo: this.document
305
+ };
306
+
307
+ const editorOptions = {
308
+ toggled: true,
309
+ collaborate: true,
310
+ documentUUID: this.document.uuid,
311
+ height: 300
312
+ };
313
+
314
+ const editorValue = this.document.system?.[field] ?? foundry.utils.getProperty(this.document.system, field);
315
+ context.editors[\`\${field}\`] = {
316
+ enriched: await TextEditor.enrichHTML(editorValue, enrichmentOptions),
317
+ element: foundry.applications.elements.HTMLProseMirrorElement.create({
318
+ ...editorOptions,
319
+ name: \`system.\${field}\`,
320
+ value: editorValue ?? ""
321
+ })
322
+ };
323
+ }
324
+
325
+ /* -------------------------------------------- */
326
+
327
+ _prepareSubmitData(event, form, formData) {
328
+ // We don't modify the image via the sheet itself, so we can remove it from the submit data to avoid errors.
329
+ delete formData.object.img;
330
+ return super._prepareSubmitData(event, form, formData);
331
+ }
332
+
333
+ /* -------------------------------------------- */
334
+
335
+ /**
336
+ * Process form submission for the sheet
337
+ * @this {${entry.config.name}EffectVueSheet} The handler is called with the application as its bound scope
338
+ * @param {SubmitEvent} event The originating form submission event
339
+ * @param {HTMLFormElement} form The form element that was submitted
340
+ * @param {FormDataExtended} formData Processed data for the submitted form
341
+ * @returns {Promise<void>}
342
+ */
343
+ static async _onSubmitForm(event, form, formData) {
344
+ console.log("Updating Active Effect", formData);
345
+ const flags = foundry.utils.duplicate(this.document.flags);
346
+ if ( !flags["${id}"] ) {
347
+ flags["${id}"] = {};
348
+ }
349
+
350
+ // Retrieve the existing effects.
351
+ let changes = this.document.changes ? [...this.document.changes] : [];
352
+
353
+ // Build an array of effects from the form data
354
+ let newChanges = [];
355
+
356
+ function addChange(documentName, key, customMode) {
357
+ const value = foundry.utils.getProperty(formData.object, key);
358
+ if ( value === undefined ) {
359
+ // Field not rendered in the form - preserve any existing change.
360
+ return;
361
+ }
362
+ if ( !value ) {
363
+ // Field explicitly cleared (empty string / zero) - remove the change.
364
+ changes = changes.filter(c => c.key !== key);
365
+ return;
366
+ }
367
+ const type = foundry.utils.getProperty(formData.object, key + "-type") ?? 'add';
368
+ newChanges.push({
369
+ key: key,
370
+ value: value,
371
+ type: type
372
+ });
373
+ if ( customMode ) flags["${id}"][key + "-custommode"] = customMode;
374
+ }
375
+
376
+ ${joinToNode(entry.documents.filter(d => isActor(d)), document => joinToNode(document.body, property => generateAddValue(document, property), { appendNewLineIfNotEmpty: true }))}
377
+
378
+ // Auto-generated damage type Active Effect fields
379
+ ${joinToNode(entry.documents.filter(d => isActor(d)), document => generateDamageTypeActiveEffectFields(entry, document), { appendNewLineIfNotEmpty: true })}
380
+
381
+ // Update the existing changes to replace duplicates.
382
+ for (let i = 0; i < changes.length; i++) {
383
+ const newChange = newChanges.find(c => c.key == changes[i].key);
384
+ if (newChange) {
385
+ // Replace with the new change and update the array to prevent duplicates.
386
+ changes[i] = newChange;
387
+ newChanges = newChanges.filter(c => c.key != changes[i].key);
388
+ }
389
+ }
390
+
391
+ // Filter changes for empty form fields.
392
+ const finalChanges = changes.concat(newChanges).filter(c => c.value !== null && c.value !== undefined && c.value !== '');
393
+ console.log("Active Effect Changes", finalChanges);
394
+ await this.document.update({
395
+ name: formData.object.name,
396
+ description: formData.object.description ?? '',
397
+ disabled: formData.object.disabled ?? false,
398
+ transfer: formData.object.transfer ?? false,
399
+ changes: finalChanges,
400
+ flags: flags
401
+ });
402
+
403
+ // Rerender the parent sheets to update the effect lists.
404
+ this.document.parent?.sheet?.render();
405
+ if ( this.document.parent?.documentName === "Item" ) {
406
+ this.document.parent?.parent?.applyActiveEffects();
407
+
408
+ // Wait half a second
409
+ await new Promise(r => setTimeout(r, 500));
410
+ this.document.parent?.parent?.sheet?.render();
411
+ }
412
+ }
413
+ }
414
+ `.appendNewLineIfNotEmpty();
415
+ fs.writeFileSync(generatedFilePath, toString(fileNode));
416
+ }
417
+ export function generateActiveEffectHandlebars(id, entry, destination) {
418
+ const generatedFileDir = path.join(destination, "system", "templates");
419
+ const generatedFilePath = path.join(generatedFileDir, `active-effect-sheet.hbs`);
420
+ if (!fs.existsSync(generatedFileDir)) {
421
+ fs.mkdirSync(generatedFileDir, { recursive: true });
422
+ }
423
+ function generateField(document, property) {
424
+ if (isAccess(property) || isAction(property) || isIfStatement(property))
425
+ return undefined;
426
+ if (isSection(property)) {
427
+ if (property.body.length == 0)
428
+ return undefined;
429
+ let fields = [];
430
+ for (let p of property.body) {
431
+ let field = generateField(document, p);
432
+ if (field != undefined)
433
+ fields.push(field);
434
+ }
435
+ if (fields.length == 0)
436
+ return undefined;
437
+ return expandToNode `
438
+ <!-- ${property.name} Section -->
439
+ <fieldset>
440
+ <legend>{{localize "${property.name}"}}</legend>
441
+ ${joinToNode(fields, field => field, { appendNewLineIfNotEmpty: true })}
442
+ </fieldset>
443
+ `;
444
+ }
445
+ if (isLayout(property)) {
446
+ return joinToNode(property.body, property => generateField(document, property), { appendNewLineIfNotEmpty: true });
447
+ }
448
+ if (isHtmlExp(property) || isInitiativeProperty(property) || isStatusProperty(property) || isHookHandler(property) || !isProperty(property))
449
+ return;
450
+ if (property.modifier == "locked")
451
+ return;
452
+ if (isNumberExp(property)) {
453
+ // If this is calculated, it's implicitly locked
454
+ if (property.params.find(x => isNumberParamValue(x)))
455
+ return;
456
+ return expandToNode `
457
+ <div class="form-group">
458
+ <label>{{localize "${property.name}"}}</label>
459
+ <select name="${document.name.toLowerCase()}.${getSystemPath(property)}-mode" data-dtype="Number">
460
+ {{selectOptions numberModes selected=${document.name.toLowerCase()}.${getSystemPath(property)}-mode}}
461
+ </select>
462
+ <input type="number" name="${document.name.toLowerCase()}.${getSystemPath(property)}" value="{{${document.name.toLowerCase()}.${getSystemPath(property)}}}" />
463
+ </div>
464
+ `;
465
+ }
466
+ if (isAttributeExp(property)) {
467
+ // return expandToNode`
468
+ // <div class="form-group">
469
+ // <label>{{localize "${property.name}"}} Value</label>
470
+ // <select name="${document.name.toLowerCase()}.${getSystemPath(property)}-mode" data-dtype="Number">
471
+ // {{selectOptions numberModes selected=${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.value-mode}}
472
+ // </select>
473
+ // <input type="number" name="${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.value" value="{{${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.value}}" />
474
+ // </div>
475
+ // <div class="form-group">
476
+ // <label>{{localize "${property.name}"}} Max</label>
477
+ // <select name="${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.max-mode" data-dtype="Number">
478
+ // {{selectOptions numberModes selected=${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.max-mode}}
479
+ // </select>
480
+ // <input type="number" name="${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.max" value="{{${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.max}}" />
481
+ // </div>
482
+ // `;
483
+ return expandToNode `
484
+ <div class="form-group">
485
+ <label>{{localize "${property.name}"}} Value</label>
486
+ <select name="${document.name.toLowerCase()}.${getSystemPath(property)}-mode" data-dtype="Number">
487
+ {{selectOptions numberModes selected=${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.value-mode}}
488
+ </select>
489
+ <input type="number" name="${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.value" value="{{${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.value}}" />
490
+ </div>
491
+ `;
492
+ }
493
+ if (isResourceExp(property)) {
494
+ return expandToNode `
495
+ <div class="form-group">
496
+ <label>{{localize "${property.name}"}} Current</label>
497
+ <select name="${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.value-mode" data-dtype="Number">
498
+ {{selectOptions resourceModes selected=${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.value-mode}}
499
+ </select>
500
+ <input type="number" name="${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.value" value="{{${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.value}}" />
501
+ </div>
502
+ <div class="form-group">
503
+ <label>{{localize "${property.name}"}} Max</label>
504
+ <select name="${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.max-mode" data-dtype="Number">
505
+ {{selectOptions numberModes selected=${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.max-mode}}
506
+ </select>
507
+ <input type="number" name="${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.max" value="{{${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.max}}" />
508
+ </div>
509
+ `;
510
+ }
511
+ if (isTrackerExp(property)) {
512
+ return expandToNode `
513
+ <div class="form-group">
514
+ <label>{{localize "${property.name}"}} Min</label>
515
+ <select name="${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.min-mode" data-dtype="Number">
516
+ {{selectOptions numberModes selected=${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.min-mode}}
517
+ </select>
518
+ <input type="number" name="${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.min" value="{{${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.min}}" />
519
+ </div>
520
+ <div class="form-group">
521
+ <label>{{localize "${property.name}"}} Current</label>
522
+ <select name="${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.value-mode" data-dtype="Number">
523
+ {{selectOptions resourceModes selected=${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.value-mode}}
524
+ </select>
525
+ <input type="number" name="${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.value" value="{{${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.value}}" />
526
+ </div>
527
+ <div class="form-group">
528
+ <label>{{localize "${property.name}"}} Temp</label>
529
+ <select name="${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.temp-mode" data-dtype="Number">
530
+ {{selectOptions resourceModes selected=${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.temp-mode}}
531
+ </select>
532
+ <input type="number" name="${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.temp" value="{{${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.temp}}" />
533
+ </div>
534
+ <div class="form-group">
535
+ <label>{{localize "${property.name}"}} Max</label>
536
+ <select name="${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.max-mode" data-dtype="Number">
537
+ {{selectOptions numberModes selected=${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.max-mode}}
538
+ </select>
539
+ <input type="number" name="${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.max" value="{{${document.name.toLowerCase()}.system.${property.name.toLowerCase()}.max}}" />
540
+ </div>
541
+ `;
542
+ }
543
+ if (isStringExp(property)) {
544
+ // if (property.choices != undefined && property.choices.length > 0) {
545
+ // return expandToNode`
546
+ // <div class="form-group">
547
+ // <label>{{localize "${property.name}"}}</label>
548
+ // <select name="${document.name.toLowerCase()}.${getSystemPath(property)}-mode" data-dtype="String">
549
+ // {{selectOptions stringModes selected=${document.name.toLowerCase()}.${getSystemPath(property)}-mode}}
550
+ // </select>
551
+ // <select name="${document.name.toLowerCase()}.${getSystemPath(property)}">
552
+ // {{selectOptions ${property.name.toLowerCase()}Choices selected=${document.name.toLowerCase()}.${getSystemPath(property)} localize=true }}
553
+ // </select>
554
+ // </div>
555
+ // `;
556
+ // }
557
+ return expandToNode `
558
+ <div class="form-group">
559
+ <label>{{localize "${property.name}"}}</label>
560
+ <select name="${document.name.toLowerCase()}.${getSystemPath(property)}-mode" data-dtype="String">
561
+ {{selectOptions stringModes selected=${document.name.toLowerCase()}.${getSystemPath(property)}-mode}}
562
+ </select>
563
+ <input type="text" name="${document.name.toLowerCase()}.${getSystemPath(property)}" value="{{${document.name.toLowerCase()}.${getSystemPath(property)}}}" />
564
+ </div>
565
+ `;
566
+ }
567
+ if (isBooleanExp(property)) {
568
+ return expandToNode `
569
+ <div class="form-group">
570
+ <label>{{localize "${property.name}"}}</label>
571
+ <select name="${document.name.toLowerCase()}.${getSystemPath(property)}-mode" data-dtype="Boolean">
572
+ {{selectOptions booleanModes selected=${document.name.toLowerCase()}.${getSystemPath(property)}-mode}}
573
+ </select>
574
+ <input type="checkbox" name="${document.name.toLowerCase()}.${getSystemPath(property)}" {{checked ${document.name.toLowerCase()}.${getSystemPath(property)}}} />
575
+ </div>
576
+ `;
577
+ }
578
+ return;
579
+ }
580
+ function generateDocumentTab(document) {
581
+ return expandToNode `
582
+ <!-- ${document.name} Tab -->
583
+ <section class="tab" data-tab="${document.name.toLowerCase()}">
584
+ ${joinToNode(document.body, property => generateField(document, property), { appendNewLineIfNotEmpty: true })}
585
+ </section>
586
+ `;
587
+ }
588
+ const fileNode = expandToNode `
589
+ <form class="{{cssClass}}" autocomplete="off">
590
+ <!-- Effect Header -->
591
+ <header class="sheet-header">
592
+ <img class="effect-icon effect-img" src="{{ effect.img }}" data-edit="img">
593
+ <h1 class="effect-title"><input type="text" name="name" value="{{effect.name}}" placeholder="{{localize 'ARCHMAGE.name'}}"/></h1>
594
+ </header>
595
+
596
+ <article class="sheet-content">
597
+ <section class="sheet-body">
598
+ <!-- Effect Configuration Tabs -->
599
+ <nav class="sheet-tabs tabs">
600
+ <a class="item" data-tab="info"><i class="fas fa-book"></i> {{localize "Info"}}</a>
601
+ ${joinToNode(entry.documents.filter(d => isActor(d)), property => `<a class="item" data-tab="${property.name.toLowerCase()}">{{localize "${property.name}"}}</a>`, { appendNewLineIfNotEmpty: true })}
602
+ </nav>
603
+
604
+ <div class="sheet-tabs-content">
605
+ <!-- Info Tab -->
606
+ <section class="tab" data-tab="info">
607
+ <div class="form-group stacked">
608
+ <label>{{ localize "EFFECT.Description" }}</label>
609
+ {{editor descriptionHTML target="description" button=false editable=editable engine="prosemirror" collaborate=false}}
610
+ </div>
611
+
612
+ <div class="form-group">
613
+ <label>{{ localize "EFFECT.Disabled" }}</label>
614
+ <input type="checkbox" name="disabled" {{ checked effect.disabled }}/>
615
+ </div>
616
+
617
+ {{#if originLink}}
618
+ <div class="form-group">
619
+ <label>{{ localize "EFFECT.Origin" }}</label>
620
+ {{{originLink}}}
621
+ </div>
622
+ {{/if}}
623
+
624
+ {{#if isItemEffect}}
625
+ <div class="form-group">
626
+ <label>{{ labels.transfer.name }}</label>
627
+ <div class="form-fields">
628
+ <input type="checkbox" name="transfer" {{checked data.transfer}}/>
629
+ </div>
630
+ <p class="hint">{{ labels.transfer.hint }}</p>
631
+ </div>
632
+ {{/if}}
633
+ </div>
634
+
635
+ ${joinToNode(entry.documents, property => generateDocumentTab(property), { appendNewLineIfNotEmpty: true })}
636
+ </section>
637
+ </section>
638
+ </article>
639
+ </form>
640
+ `.appendNewLineIfNotEmpty();
641
+ fs.writeFileSync(generatedFilePath, toString(fileNode));
642
+ }
643
+ //# sourceMappingURL=active-effect-sheet-generator.js.map