@luquimbo/bi-superpowers 3.1.1 → 4.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 (186) hide show
  1. package/.claude-plugin/marketplace.json +5 -3
  2. package/.claude-plugin/plugin.json +28 -2
  3. package/.claude-plugin/skill-manifest.json +22 -6
  4. package/.plugin/plugin.json +1 -1
  5. package/AGENTS.md +52 -36
  6. package/CHANGELOG.md +295 -0
  7. package/README.md +75 -26
  8. package/bin/build-plugin.js +17 -10
  9. package/bin/cli.js +278 -322
  10. package/bin/commands/build-desktop.js +35 -16
  11. package/bin/commands/diff.js +31 -13
  12. package/bin/commands/install.js +93 -72
  13. package/bin/commands/lint.js +40 -26
  14. package/bin/commands/mcp-setup.js +3 -10
  15. package/bin/commands/update-check.js +389 -0
  16. package/bin/lib/agents.js +19 -0
  17. package/bin/lib/generators/claude-plugin.js +144 -6
  18. package/bin/lib/generators/shared.js +29 -33
  19. package/bin/lib/mcp-config.js +191 -16
  20. package/bin/lib/skills.js +115 -27
  21. package/bin/postinstall.js +4 -2
  22. package/bin/utils/mcp-detect.js +2 -2
  23. package/commands/bi-start.md +218 -0
  24. package/commands/pbi-connect.md +43 -65
  25. package/commands/project-kickoff.md +393 -673
  26. package/commands/report-design.md +403 -0
  27. package/desktop-extension/manifest.json +5 -12
  28. package/desktop-extension/server.js +34 -25
  29. package/package.json +6 -10
  30. package/skills/bi-start/SKILL.md +220 -0
  31. package/skills/bi-start/scripts/update-check.js +389 -0
  32. package/skills/pbi-connect/SKILL.md +45 -67
  33. package/skills/pbi-connect/scripts/update-check.js +389 -0
  34. package/skills/project-kickoff/SKILL.md +395 -675
  35. package/skills/project-kickoff/scripts/update-check.js +389 -0
  36. package/skills/report-design/SKILL.md +405 -0
  37. package/skills/report-design/references/cli-commands.md +184 -0
  38. package/skills/report-design/references/cli-setup.md +101 -0
  39. package/skills/report-design/references/close-write-open-pattern.md +80 -0
  40. package/skills/report-design/references/layouts/finance.md +65 -0
  41. package/skills/report-design/references/layouts/generic.md +46 -0
  42. package/skills/report-design/references/layouts/hr.md +48 -0
  43. package/skills/report-design/references/layouts/marketing.md +45 -0
  44. package/skills/report-design/references/layouts/operations.md +44 -0
  45. package/skills/report-design/references/layouts/sales.md +50 -0
  46. package/skills/report-design/references/native-visuals.md +341 -0
  47. package/skills/report-design/references/pbi-desktop-installation.md +87 -0
  48. package/skills/report-design/references/pbir-preview-activation.md +40 -0
  49. package/skills/report-design/references/slicer.md +89 -0
  50. package/skills/report-design/references/textbox.md +101 -0
  51. package/skills/report-design/references/themes/BISuperpowers.json +915 -0
  52. package/skills/report-design/references/troubleshooting.md +135 -0
  53. package/skills/report-design/references/visual-types.md +78 -0
  54. package/skills/report-design/scripts/apply-theme.js +243 -0
  55. package/skills/report-design/scripts/create-visual.js +878 -0
  56. package/skills/report-design/scripts/ensure-pbi-cli.sh +41 -0
  57. package/skills/report-design/scripts/update-check.js +389 -0
  58. package/skills/report-design/scripts/validate-pbir.js +322 -0
  59. package/src/content/base.md +12 -68
  60. package/src/content/mcp-requirements.json +0 -25
  61. package/src/content/routing.md +19 -74
  62. package/src/content/skills/bi-start.md +191 -0
  63. package/src/content/skills/pbi-connect.md +22 -65
  64. package/src/content/skills/project-kickoff.md +372 -673
  65. package/src/content/skills/report-design/SKILL.md +376 -0
  66. package/src/content/skills/report-design/references/cli-commands.md +184 -0
  67. package/src/content/skills/report-design/references/cli-setup.md +101 -0
  68. package/src/content/skills/report-design/references/close-write-open-pattern.md +80 -0
  69. package/src/content/skills/report-design/references/layouts/finance.md +65 -0
  70. package/src/content/skills/report-design/references/layouts/generic.md +46 -0
  71. package/src/content/skills/report-design/references/layouts/hr.md +48 -0
  72. package/src/content/skills/report-design/references/layouts/marketing.md +45 -0
  73. package/src/content/skills/report-design/references/layouts/operations.md +44 -0
  74. package/src/content/skills/report-design/references/layouts/sales.md +50 -0
  75. package/src/content/skills/report-design/references/native-visuals.md +341 -0
  76. package/src/content/skills/report-design/references/pbi-desktop-installation.md +87 -0
  77. package/src/content/skills/report-design/references/pbir-preview-activation.md +40 -0
  78. package/src/content/skills/report-design/references/slicer.md +89 -0
  79. package/src/content/skills/report-design/references/textbox.md +101 -0
  80. package/src/content/skills/report-design/references/themes/BISuperpowers.json +915 -0
  81. package/src/content/skills/report-design/references/troubleshooting.md +135 -0
  82. package/src/content/skills/report-design/references/visual-types.md +78 -0
  83. package/src/content/skills/report-design/scripts/apply-theme.js +243 -0
  84. package/src/content/skills/report-design/scripts/create-visual.js +878 -0
  85. package/src/content/skills/report-design/scripts/ensure-pbi-cli.sh +41 -0
  86. package/src/content/skills/report-design/scripts/validate-pbir.js +322 -0
  87. package/bin/commands/add.js +0 -533
  88. package/bin/commands/add.test.js +0 -77
  89. package/bin/commands/changelog.js +0 -443
  90. package/bin/commands/install.test.js +0 -289
  91. package/bin/commands/lint.test.js +0 -103
  92. package/bin/commands/pull.js +0 -287
  93. package/bin/commands/pull.test.js +0 -36
  94. package/bin/commands/push.js +0 -231
  95. package/bin/commands/push.test.js +0 -14
  96. package/bin/commands/search.js +0 -344
  97. package/bin/commands/search.test.js +0 -115
  98. package/bin/commands/setup.js +0 -545
  99. package/bin/commands/setup.test.js +0 -46
  100. package/bin/commands/sync-profile.js +0 -405
  101. package/bin/commands/sync-profile.test.js +0 -14
  102. package/bin/commands/sync-source.js +0 -418
  103. package/bin/commands/sync-source.test.js +0 -14
  104. package/bin/lib/generators/claude-plugin.test.js +0 -111
  105. package/bin/lib/mcp-config.test.js +0 -310
  106. package/bin/lib/microsoft-mcp.test.js +0 -115
  107. package/bin/utils/errors.js +0 -159
  108. package/bin/utils/git.js +0 -298
  109. package/bin/utils/logger.js +0 -142
  110. package/bin/utils/mcp-detect.test.js +0 -81
  111. package/bin/utils/pbix.js +0 -305
  112. package/bin/utils/pbix.test.js +0 -37
  113. package/bin/utils/profiles.js +0 -312
  114. package/bin/utils/projects.js +0 -169
  115. package/bin/utils/readline.js +0 -206
  116. package/bin/utils/readline.test.js +0 -47
  117. package/bin/utils/tui.test.js +0 -127
  118. package/docs/openrouter-free-models.md +0 -92
  119. package/library/examples/README.md +0 -151
  120. package/library/examples/finance-reporting/README.md +0 -351
  121. package/library/examples/finance-reporting/data-model.md +0 -267
  122. package/library/examples/finance-reporting/measures.dax +0 -557
  123. package/library/examples/hr-analytics/README.md +0 -371
  124. package/library/examples/hr-analytics/data-model.md +0 -315
  125. package/library/examples/hr-analytics/measures.dax +0 -460
  126. package/library/examples/marketing-analytics/README.md +0 -37
  127. package/library/examples/marketing-analytics/data-model.md +0 -62
  128. package/library/examples/marketing-analytics/measures.dax +0 -110
  129. package/library/examples/retail-analytics/README.md +0 -439
  130. package/library/examples/retail-analytics/data-model.md +0 -288
  131. package/library/examples/retail-analytics/measures.dax +0 -481
  132. package/library/examples/supply-chain/README.md +0 -37
  133. package/library/examples/supply-chain/data-model.md +0 -69
  134. package/library/examples/supply-chain/measures.dax +0 -77
  135. package/library/examples/udf-library/README.md +0 -228
  136. package/library/examples/udf-library/functions.dax +0 -571
  137. package/library/snippets/dax/README.md +0 -292
  138. package/library/snippets/dax/business-domains.md +0 -576
  139. package/library/snippets/dax/calculate-patterns.md +0 -276
  140. package/library/snippets/dax/calculation-groups.md +0 -489
  141. package/library/snippets/dax/error-handling.md +0 -495
  142. package/library/snippets/dax/iterators-and-aggregations.md +0 -474
  143. package/library/snippets/dax/kpis-and-metrics.md +0 -293
  144. package/library/snippets/dax/rankings-and-topn.md +0 -235
  145. package/library/snippets/dax/security-patterns.md +0 -413
  146. package/library/snippets/dax/text-and-formatting.md +0 -316
  147. package/library/snippets/dax/time-intelligence.md +0 -196
  148. package/library/snippets/dax/user-defined-functions.md +0 -477
  149. package/library/snippets/dax/virtual-tables.md +0 -546
  150. package/library/snippets/excel-formulas/README.md +0 -84
  151. package/library/snippets/excel-formulas/aggregations.md +0 -330
  152. package/library/snippets/excel-formulas/dates-and-times.md +0 -361
  153. package/library/snippets/excel-formulas/dynamic-arrays.md +0 -314
  154. package/library/snippets/excel-formulas/lookups.md +0 -169
  155. package/library/snippets/excel-formulas/text-functions.md +0 -363
  156. package/library/snippets/governance/naming-conventions.md +0 -97
  157. package/library/snippets/governance/review-checklists.md +0 -107
  158. package/library/snippets/power-query/README.md +0 -389
  159. package/library/snippets/power-query/api-integration.md +0 -707
  160. package/library/snippets/power-query/connections.md +0 -434
  161. package/library/snippets/power-query/data-cleaning.md +0 -298
  162. package/library/snippets/power-query/error-handling.md +0 -526
  163. package/library/snippets/power-query/parameters.md +0 -350
  164. package/library/snippets/power-query/performance.md +0 -506
  165. package/library/snippets/power-query/transformations.md +0 -330
  166. package/library/snippets/report-design/accessibility.md +0 -78
  167. package/library/snippets/report-design/chart-selection.md +0 -54
  168. package/library/snippets/report-design/layout-patterns.md +0 -87
  169. package/library/templates/data-models/README.md +0 -93
  170. package/library/templates/data-models/finance-model.md +0 -627
  171. package/library/templates/data-models/retail-star-schema.md +0 -473
  172. package/library/templates/excel/README.md +0 -83
  173. package/library/templates/excel/budget-tracker.md +0 -432
  174. package/library/templates/excel/data-entry-form.md +0 -533
  175. package/library/templates/power-bi/README.md +0 -72
  176. package/library/templates/power-bi/finance-report.md +0 -449
  177. package/library/templates/power-bi/kpi-scorecard.md +0 -461
  178. package/library/templates/power-bi/sales-dashboard.md +0 -281
  179. package/library/themes/excel/README.md +0 -436
  180. package/library/themes/power-bi/README.md +0 -271
  181. package/library/themes/power-bi/accessible.json +0 -307
  182. package/library/themes/power-bi/bi-superpowers-default.json +0 -858
  183. package/library/themes/power-bi/corporate-blue.json +0 -291
  184. package/library/themes/power-bi/dark-mode.json +0 -291
  185. package/library/themes/power-bi/minimal.json +0 -292
  186. package/library/themes/power-bi/print-friendly.json +0 -309
@@ -1,526 +0,0 @@
1
- # Error Handling in Power Query
2
-
3
- Patterns for handling errors, debugging, and building robust data pipelines.
4
-
5
- ---
6
-
7
- ## Try-Otherwise Pattern
8
-
9
- ### Basic Error Handling
10
-
11
- ```m
12
- let
13
- Source = YourSource,
14
-
15
- // Safe transformation - returns null on error
16
- SafeConvert = Table.TransformColumns(Source, {
17
- {"Amount", each try Number.From(_) otherwise null, type number}
18
- })
19
- in
20
- SafeConvert
21
- ```
22
-
23
- ### With Custom Default Value
24
-
25
- ```m
26
- let
27
- Source = YourSource,
28
-
29
- // Return 0 instead of null on error
30
- SafeAmount = Table.TransformColumns(Source, {
31
- {"Amount", each try Number.From(_) otherwise 0, type number}
32
- })
33
- in
34
- SafeAmount
35
- ```
36
-
37
- ### With Error Logging
38
-
39
- ```m
40
- let
41
- Source = YourSource,
42
-
43
- // Capture both value and error status
44
- WithErrorInfo = Table.AddColumn(Source, "ParseResult",
45
- each
46
- let
47
- Result = try Number.From([Amount])
48
- in
49
- [
50
- Value = if Result[HasError] then null else Result[Value],
51
- HasError = Result[HasError],
52
- Error = if Result[HasError] then Result[Error][Message] else null
53
- ]
54
- ),
55
-
56
- // Expand the record
57
- Expanded = Table.ExpandRecordColumn(WithErrorInfo, "ParseResult",
58
- {"Value", "HasError", "Error"},
59
- {"Amount_Parsed", "Amount_HasError", "Amount_Error"}
60
- )
61
- in
62
- Expanded
63
- ```
64
-
65
- ---
66
-
67
- ## Try Expression Details
68
-
69
- ### Structure of Try Result
70
-
71
- ```m
72
- let
73
- // try returns a record with these fields:
74
- // [HasError] - true/false
75
- // [Value] - result if no error
76
- // [Error] - error record if error occurred
77
-
78
- Result = try Number.From("abc"),
79
-
80
- // Result = [HasError = true, Error = [Reason = "...", Message = "...", Detail = "..."]]
81
-
82
- SafeValue = if Result[HasError] then 0 else Result[Value]
83
- in
84
- SafeValue
85
- ```
86
-
87
- ### Access Error Details
88
-
89
- ```m
90
- let
91
- Source = YourSource,
92
-
93
- WithErrorDetails = Table.AddColumn(Source, "ErrorInfo",
94
- each
95
- let
96
- Result = try SomeRiskyOperation([ColumnA])
97
- in
98
- if Result[HasError] then
99
- "Error: " & Result[Error][Reason] &
100
- " - " & Result[Error][Message]
101
- else
102
- "Success"
103
- )
104
- in
105
- WithErrorDetails
106
- ```
107
-
108
- ---
109
-
110
- ## Null Handling
111
-
112
- ### COALESCE Pattern (First Non-Null)
113
-
114
- ```m
115
- let
116
- Source = YourSource,
117
-
118
- // Return first non-null value
119
- WithCoalesce = Table.AddColumn(Source, "ContactEmail",
120
- each
121
- if [PrimaryEmail] <> null then [PrimaryEmail]
122
- else if [SecondaryEmail] <> null then [SecondaryEmail]
123
- else if [WorkEmail] <> null then [WorkEmail]
124
- else "unknown@example.com",
125
- type text
126
- )
127
- in
128
- WithCoalesce
129
- ```
130
-
131
- ### Null-Safe Operations
132
-
133
- ```m
134
- let
135
- Source = YourSource,
136
-
137
- // Safe text operations (handle null)
138
- SafeText = Table.TransformColumns(Source, {
139
- {"Name", each if _ = null then "" else Text.Trim(_), type text}
140
- }),
141
-
142
- // Safe number operations
143
- SafeNumber = Table.TransformColumns(Source, {
144
- {"Amount", each if _ = null then 0 else _, type number}
145
- })
146
- in
147
- SafeNumber
148
- ```
149
-
150
- ### Check for Null Before Operation
151
-
152
- ```m
153
- let
154
- Source = YourSource,
155
-
156
- SafeCalculation = Table.AddColumn(Source, "Result",
157
- each
158
- if [Denominator] = null or [Denominator] = 0 then
159
- null
160
- else
161
- [Numerator] / [Denominator],
162
- type number
163
- )
164
- in
165
- SafeCalculation
166
- ```
167
-
168
- ---
169
-
170
- ## Error Row Separation
171
-
172
- ### Split Clean and Error Rows
173
-
174
- ```m
175
- let
176
- Source = YourSource,
177
-
178
- // Add error flag
179
- WithFlag = Table.AddColumn(Source, "_HasError",
180
- each
181
- try (
182
- // Validate required fields
183
- [CustomerID] <> null and
184
- [Amount] <> null and
185
- Number.From([Amount]) >= 0
186
- ) otherwise false,
187
- type logical
188
- ),
189
-
190
- // Separate good and bad rows
191
- CleanRows = Table.SelectRows(WithFlag, each [_HasError] = true),
192
- ErrorRows = Table.SelectRows(WithFlag, each [_HasError] = false),
193
-
194
- // Remove flag from clean data
195
- CleanData = Table.RemoveColumns(CleanRows, {"_HasError"})
196
- in
197
- CleanData // or return both via Record
198
- ```
199
-
200
- ### Return Both Clean and Error Tables
201
-
202
- ```m
203
- let
204
- Source = YourSource,
205
-
206
- // Validation function
207
- ValidateRow = (row as record) as logical =>
208
- row[CustomerID] <> null and
209
- row[Amount] <> null and
210
- (try Number.From(row[Amount]) >= 0 otherwise false),
211
-
212
- // Flag rows
213
- Flagged = Table.AddColumn(Source, "_IsValid", each ValidateRow(_), type logical),
214
-
215
- // Split
216
- Result = [
217
- CleanData = Table.SelectRows(Flagged, each [_IsValid] = true),
218
- ErrorData = Table.SelectRows(Flagged, each [_IsValid] = false),
219
- ErrorCount = Table.RowCount(Table.SelectRows(Flagged, each [_IsValid] = false)),
220
- CleanCount = Table.RowCount(Table.SelectRows(Flagged, each [_IsValid] = true))
221
- ]
222
- in
223
- Result
224
- ```
225
-
226
- ---
227
-
228
- ## Replace Errors
229
-
230
- ### Replace All Errors in Table
231
-
232
- ```m
233
- let
234
- Source = YourSource,
235
-
236
- // Replace errors in specific columns
237
- ReplacedErrors = Table.ReplaceErrorValues(Source, {
238
- {"Amount", 0},
239
- {"Quantity", 0},
240
- {"Date", null},
241
- {"Name", "Unknown"}
242
- })
243
- in
244
- ReplacedErrors
245
- ```
246
-
247
- ### Replace Errors in All Columns
248
-
249
- ```m
250
- let
251
- Source = YourSource,
252
- ColumnNames = Table.ColumnNames(Source),
253
-
254
- // Create replacement list for all columns
255
- ReplacementList = List.Transform(
256
- ColumnNames,
257
- each {_, null} // Replace with null
258
- ),
259
-
260
- ReplacedErrors = Table.ReplaceErrorValues(Source, ReplacementList)
261
- in
262
- ReplacedErrors
263
- ```
264
-
265
- ---
266
-
267
- ## Validation Patterns
268
-
269
- ### Data Type Validation
270
-
271
- ```m
272
- let
273
- Source = YourSource,
274
-
275
- // Validate data types before processing
276
- Validated = Table.AddColumn(Source, "ValidationResult",
277
- each
278
- let
279
- Checks = {
280
- {[CustomerID] <> null, "CustomerID is required"},
281
- {try Number.From([Amount]) <> null otherwise false, "Amount must be numeric"},
282
- {try Date.From([OrderDate]) <> null otherwise false, "OrderDate must be valid date"},
283
- {[Status] <> null and List.Contains({"Open", "Closed", "Pending"}, [Status]), "Invalid Status"}
284
- },
285
- Failures = List.Select(Checks, each not _{0}),
286
- Messages = List.Transform(Failures, each _{1})
287
- in
288
- if List.Count(Messages) = 0 then "Valid"
289
- else Text.Combine(Messages, "; ")
290
- )
291
- in
292
- Validated
293
- ```
294
-
295
- ### Business Rule Validation
296
-
297
- ```m
298
- let
299
- Source = YourSource,
300
-
301
- ValidatedData = Table.AddColumn(Source, "BusinessRuleCheck",
302
- each
303
- let
304
- Rules = {
305
- // Rule 1: Amount must be positive
306
- {[Amount] > 0, "Amount must be positive"},
307
-
308
- // Rule 2: Discount cannot exceed amount
309
- {[Discount] <= [Amount], "Discount exceeds amount"},
310
-
311
- // Rule 3: Order date must be in the past
312
- {[OrderDate] <= DateTime.Date(DateTime.LocalNow()), "Future order date"},
313
-
314
- // Rule 4: Customer must exist
315
- {[CustomerID] <> null, "Missing customer"}
316
- },
317
- Failures = List.Select(Rules, each not _{0}),
318
- ErrorMessages = List.Transform(Failures, each _{1})
319
- in
320
- [
321
- IsValid = List.Count(ErrorMessages) = 0,
322
- Errors = Text.Combine(ErrorMessages, "; ")
323
- ]
324
- ),
325
-
326
- // Expand validation results
327
- Expanded = Table.ExpandRecordColumn(ValidatedData, "BusinessRuleCheck",
328
- {"IsValid", "Errors"}
329
- )
330
- in
331
- Expanded
332
- ```
333
-
334
- ---
335
-
336
- ## Connection Error Handling
337
-
338
- ### Handle Missing Data Source
339
-
340
- ```m
341
- let
342
- // Try to connect, fall back gracefully
343
- TryConnection = try Sql.Database("server", "database"),
344
-
345
- Result =
346
- if TryConnection[HasError] then
347
- #table(
348
- {"Status", "Message"},
349
- {{"Error", "Could not connect to database: " & TryConnection[Error][Message]}}
350
- )
351
- else
352
- let
353
- Source = TryConnection[Value],
354
- Data = Source{[Schema="dbo", Item="Sales"]}[Data]
355
- in
356
- Data
357
- in
358
- Result
359
- ```
360
-
361
- ### File Existence Check
362
-
363
- ```m
364
- let
365
- FilePath = "C:\Data\input.csv",
366
-
367
- // Check if file exists
368
- FileExists = try File.Contents(FilePath) <> null otherwise false,
369
-
370
- Result =
371
- if not FileExists then
372
- error Error.Record("File Not Found", "The file " & FilePath & " does not exist")
373
- else
374
- Csv.Document(File.Contents(FilePath), [Delimiter=","])
375
- in
376
- Result
377
- ```
378
-
379
- ---
380
-
381
- ## Debugging Helpers
382
-
383
- ### Add Row Numbers for Tracking
384
-
385
- ```m
386
- let
387
- Source = YourSource,
388
-
389
- // Add index for debugging
390
- WithIndex = Table.AddIndexColumn(Source, "_RowNumber", 1, 1, Int64.Type),
391
-
392
- // Now you can reference specific rows in error messages
393
- Processed = Table.TransformColumns(WithIndex, {
394
- {"Amount", each try Number.From(_) otherwise
395
- error Error.Record("Parse Error", "Row " & Text.From([_RowNumber]) & ": Invalid amount")}
396
- })
397
- in
398
- Processed
399
- ```
400
-
401
- ### Log Processing Steps
402
-
403
- ```m
404
- let
405
- // Create log entries
406
- Log = (message as text) => Diagnostics.Trace(TraceLevel.Information, message, () => true, true),
407
-
408
- Source = Log("Starting query") then YourSource,
409
- Step1 = Log("Filtering rows") then Table.SelectRows(Source, each [Status] = "Active"),
410
- Step2 = Log("Transforming columns") then Table.TransformColumns(Step1, {{"Amount", each _ * 1.1}}),
411
- Final = Log("Query complete, rows: " & Text.From(Table.RowCount(Step2))) then Step2
412
- in
413
- Final
414
- ```
415
-
416
- ### Conditional Debug Output
417
-
418
- ```m
419
- let
420
- DebugMode = true, // Set to false in production
421
-
422
- Source = YourSource,
423
-
424
- // Only add debug columns in debug mode
425
- WithDebug =
426
- if DebugMode then
427
- Table.AddColumn(
428
- Table.AddColumn(Source, "_DebugRowNum", each [Index]),
429
- "_DebugValues", each Text.From([Amount]) & "," & [Status]
430
- )
431
- else
432
- Source
433
- in
434
- WithDebug
435
- ```
436
-
437
- ---
438
-
439
- ## Custom Error Creation
440
-
441
- ### Raise Custom Error
442
-
443
- ```m
444
- let
445
- Source = YourSource,
446
- RowCount = Table.RowCount(Source),
447
-
448
- // Validate before processing
449
- Validated =
450
- if RowCount = 0 then
451
- error Error.Record(
452
- "EmptySourceError",
453
- "Source data is empty",
454
- [RowCount = 0, Source = "YourSource"]
455
- )
456
- else if RowCount > 1000000 then
457
- error Error.Record(
458
- "DataTooLargeError",
459
- "Source has too many rows: " & Text.From(RowCount),
460
- [RowCount = RowCount, MaxAllowed = 1000000]
461
- )
462
- else
463
- Source
464
- in
465
- Validated
466
- ```
467
-
468
- ### Error with Details
469
-
470
- ```m
471
- let
472
- ValidateAmount = (amount as any) =>
473
- let
474
- NumericValue = try Number.From(amount)
475
- in
476
- if NumericValue[HasError] then
477
- error Error.Record(
478
- "InvalidAmountError",
479
- "Could not parse amount: " & Text.From(amount),
480
- [
481
- OriginalValue = amount,
482
- OriginalType = Value.Type(amount),
483
- ParseError = NumericValue[Error][Message]
484
- ]
485
- )
486
- else if NumericValue[Value] < 0 then
487
- error Error.Record(
488
- "NegativeAmountError",
489
- "Amount cannot be negative",
490
- [Value = NumericValue[Value]]
491
- )
492
- else
493
- NumericValue[Value],
494
-
495
- Source = YourSource,
496
- Validated = Table.TransformColumns(Source, {
497
- {"Amount", ValidateAmount, type number}
498
- })
499
- in
500
- Validated
501
- ```
502
-
503
- ---
504
-
505
- ## Best Practices Summary
506
-
507
- ### Error Handling Checklist
508
-
509
- | Scenario | Pattern |
510
- |----------|---------|
511
- | Type conversion | `try Number.From(_) otherwise null` |
512
- | Null values | Check with `= null` before operation |
513
- | Division | Check denominator before dividing |
514
- | Missing columns | `try Record.Field(_, "Column") otherwise` |
515
- | Connection errors | Wrap source in `try` block |
516
- | Validation | Add validation column, filter errors |
517
- | Debugging | Add row numbers, use Diagnostics.Trace |
518
-
519
- ### Don'ts
520
-
521
- | Bad Practice | Why |
522
- |--------------|-----|
523
- | Ignoring errors silently | Hides data quality issues |
524
- | Catching too broadly | May mask real problems |
525
- | Not logging errors | Can't diagnose issues |
526
- | Failing on first error | Loses batch visibility |