mx-empty-captions 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -87,6 +87,7 @@ mx-empty-captions -a 81977b9a-2dfa-4f2d-b179-b72ea4b00e20 -b trunk -o results.js
87
87
  | `--output` | `-o` | No | `found_Empty_Captions.json` | Output JSON file path |
88
88
  | `--token` | `-t` | No | — | PAT (overrides `MENDIX_TOKEN`) |
89
89
  | `--help` | `-h` | No | — | Show help |
90
+ | `--verbose` | `-v` | No | — | Print full stack trace on failure |
90
91
  | `--version` | `-V` | No | — | Show version |
91
92
 
92
93
  ## Output
@@ -113,6 +114,29 @@ Each module appears once. Under `microflows`, each entry lists a microflow and h
113
114
 
114
115
  ## Troubleshooting
115
116
 
117
+ When a run fails, the CLI prints an **error ID** (for example `MXEC-20260725-a3f2`) and saves full details locally:
118
+
119
+ ```
120
+ Error MXEC-20260725-a3f2: instance of Microflows$Microflow is not contained by a Projects$Module
121
+ Details saved to: C:\Users\you\.mx-empty-captions\logs\MXEC-20260725-a3f2.json
122
+ When reporting an issue, include error ID: MXEC-20260725-a3f2
123
+ ```
124
+
125
+ Logs are stored on the machine where you ran the command (not on npm):
126
+
127
+ | Platform | Log directory |
128
+ | -------- | ------------- |
129
+ | Windows | `%USERPROFILE%\.mx-empty-captions\logs\` |
130
+ | Linux/macOS | `~/.mx-empty-captions/logs/` |
131
+
132
+ Each error gets its own JSON file plus an append-only `index.jsonl` listing all errors. Open the file matching your error ID to see the stack trace, CLI version, app ID, branch, and microflow context.
133
+
134
+ Use `--verbose` to also print the stack trace in the terminal:
135
+
136
+ ```bash
137
+ mx-empty-captions -a <app-id> -v
138
+ ```
139
+
116
140
  | Error | Likely cause |
117
141
  | ------------------------------- | ------------------------------------------------------------------------------------------- |
118
142
  | `No Mendix PAT found` | Set `MENDIX_TOKEN` or pass `--token` |
package/dist/cli.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from "commander";
3
3
  import * as mendixPlatformSDK from "mendixplatformsdk";
4
+ import { formatErrorForUser, ScanError, writeErrorLog, } from "./errorLog.js";
4
5
  import { scanEmptyCaptions } from "./scan.js";
5
6
  function resolveToken(cliToken) {
6
7
  return cliToken ?? process.env.MENDIX_TOKEN;
@@ -9,11 +10,12 @@ const program = new Command();
9
10
  program
10
11
  .name("mx-empty-captions")
11
12
  .description("Scan a Mendix app for decision activities (Exclusive Split) with empty captions")
12
- .version("1.0.0")
13
+ .version("1.0.1")
13
14
  .requiredOption("-a, --app-id <uuid>", "Mendix app ID (Project ID)")
14
15
  .option("-b, --branch <name>", "Team Server branch", "main")
15
16
  .option("-o, --output <path>", "Output JSON file path", "found_Empty_Captions.json")
16
17
  .option("-t, --token <pat>", "Mendix Personal Access Token (defaults to MENDIX_TOKEN env var)")
18
+ .option("-v, --verbose", "Print full stack trace on failure")
17
19
  .action(async (options) => {
18
20
  const token = resolveToken(options.token);
19
21
  if (!token) {
@@ -32,7 +34,18 @@ program
32
34
  console.log(`Wrote ${results.length} module(s) to ${options.output}`);
33
35
  }
34
36
  catch (error) {
35
- console.error("Error:", error instanceof Error ? error.message : error);
37
+ const context = error instanceof ScanError
38
+ ? error.context
39
+ : {
40
+ appId: options.appId,
41
+ branch: options.branch,
42
+ };
43
+ const { id, filePath } = await writeErrorLog(error, context);
44
+ const message = error instanceof Error ? error.message : String(error);
45
+ console.error(formatErrorForUser(id, filePath, message));
46
+ if (options.verbose && error instanceof Error && error.stack) {
47
+ console.error(error.stack);
48
+ }
36
49
  process.exit(1);
37
50
  }
38
51
  });
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,iBAAiB,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAE9C,SAAS,YAAY,CAAC,QAA4B;IAChD,OAAO,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;AAC9C,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,mBAAmB,CAAC;KACzB,WAAW,CACV,iFAAiF,CAClF;KACA,OAAO,CAAC,OAAO,CAAC;KAChB,cAAc,CAAC,qBAAqB,EAAE,4BAA4B,CAAC;KACnE,MAAM,CAAC,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,CAAC;KAC3D,MAAM,CACL,qBAAqB,EACrB,uBAAuB,EACvB,2BAA2B,CAC5B;KACA,MAAM,CACL,mBAAmB,EACnB,iEAAiE,CAClE;KACA,MAAM,CAAC,KAAK,EAAE,OAA0E,EAAE,EAAE;IAC3F,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAE1C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CACX,+DAA+D,CAChE,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,iBAAiB,CAAC,iBAAiB,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC;YACtC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,UAAU,EAAE,OAAO,CAAC,MAAM;SAC3B,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CACT,SAAS,OAAO,CAAC,MAAM,iBAAiB,OAAO,CAAC,MAAM,EAAE,CACzD,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,iBAAiB,MAAM,mBAAmB,CAAC;AACvD,OAAO,EACL,kBAAkB,EAClB,SAAS,EACT,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAE9C,SAAS,YAAY,CAAC,QAA4B;IAChD,OAAO,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;AAC9C,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,mBAAmB,CAAC;KACzB,WAAW,CACV,iFAAiF,CAClF;KACA,OAAO,CAAC,OAAO,CAAC;KAChB,cAAc,CAAC,qBAAqB,EAAE,4BAA4B,CAAC;KACnE,MAAM,CAAC,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,CAAC;KAC3D,MAAM,CACL,qBAAqB,EACrB,uBAAuB,EACvB,2BAA2B,CAC5B;KACA,MAAM,CACL,mBAAmB,EACnB,iEAAiE,CAClE;KACA,MAAM,CAAC,eAAe,EAAE,mCAAmC,CAAC;KAC5D,MAAM,CACL,KAAK,EAAE,OAMN,EAAE,EAAE;IACH,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAE1C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CACX,+DAA+D,CAChE,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,iBAAiB,CAAC,iBAAiB,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,iBAAiB,CAAC;YACtC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,UAAU,EAAE,OAAO,CAAC,MAAM;SAC3B,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CACT,SAAS,OAAO,CAAC,MAAM,iBAAiB,OAAO,CAAC,MAAM,EAAE,CACzD,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GACX,KAAK,YAAY,SAAS;YACxB,CAAC,CAAC,KAAK,CAAC,OAAO;YACf,CAAC,CAAC;gBACE,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,MAAM,EAAE,OAAO,CAAC,MAAM;aACvB,CAAC;QAER,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC7D,MAAM,OAAO,GACX,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAEzD,OAAO,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;QAEzD,IAAI,OAAO,CAAC,OAAO,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAC7D,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CACF,CAAC;AAEJ,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,23 @@
1
+ export type ErrorContext = Record<string, string | number | boolean | undefined>;
2
+ export type ErrorLogEntry = {
3
+ id: string;
4
+ timestamp: string;
5
+ version: string;
6
+ message: string;
7
+ stack?: string;
8
+ context?: ErrorContext;
9
+ };
10
+ export declare function getErrorLogDir(): string;
11
+ export declare class ScanError extends Error {
12
+ readonly context: ErrorContext;
13
+ constructor(message: string, context: ErrorContext, options?: {
14
+ cause?: unknown;
15
+ });
16
+ }
17
+ export declare function writeErrorLog(error: unknown, context?: ErrorContext): Promise<{
18
+ id: string;
19
+ filePath: string;
20
+ entry: ErrorLogEntry;
21
+ }>;
22
+ export declare function formatErrorForUser(id: string, filePath: string, message: string): string;
23
+ //# sourceMappingURL=errorLog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorLog.d.ts","sourceRoot":"","sources":["../src/errorLog.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,YAAY,GAAG,MAAM,CAC/B,MAAM,EACN,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CACtC,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB,CAAC;AA0BF,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,qBAAa,SAAU,SAAQ,KAAK;IAClC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAE/B,YACE,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,YAAY,EACrB,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAK9B;CACF;AAED,wBAAsB,aAAa,CACjC,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,YAAY,GACrB,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,CAAC,CAmCjE;AAED,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,MAAM,CAMR"}
@@ -0,0 +1,67 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { readFileSync } from "node:fs";
3
+ import { appendFile, mkdir, writeFile } from "node:fs/promises";
4
+ import { homedir } from "node:os";
5
+ import { dirname, join } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ const LOG_DIR = join(homedir(), ".mx-empty-captions", "logs");
8
+ function getVersion() {
9
+ try {
10
+ const packagePath = join(dirname(fileURLToPath(import.meta.url)), "..", "package.json");
11
+ const pkg = JSON.parse(readFileSync(packagePath, "utf-8"));
12
+ return pkg.version ?? "unknown";
13
+ }
14
+ catch {
15
+ return "unknown";
16
+ }
17
+ }
18
+ function generateErrorId() {
19
+ const date = new Date().toISOString().slice(0, 10).replace(/-/g, "");
20
+ const suffix = randomBytes(3).toString("hex");
21
+ return `MXEC-${date}-${suffix}`;
22
+ }
23
+ export function getErrorLogDir() {
24
+ return LOG_DIR;
25
+ }
26
+ export class ScanError extends Error {
27
+ context;
28
+ constructor(message, context, options) {
29
+ super(message, options);
30
+ this.name = "ScanError";
31
+ this.context = context;
32
+ }
33
+ }
34
+ export async function writeErrorLog(error, context) {
35
+ const id = generateErrorId();
36
+ const message = error instanceof Error ? error.message : String(error);
37
+ const stack = error instanceof Error ? error.stack : undefined;
38
+ const mergedContext = error instanceof ScanError
39
+ ? { ...error.context, ...context }
40
+ : context;
41
+ const entry = {
42
+ id,
43
+ timestamp: new Date().toISOString(),
44
+ version: getVersion(),
45
+ message,
46
+ ...(stack ? { stack } : {}),
47
+ ...(mergedContext ? { context: mergedContext } : {}),
48
+ };
49
+ await mkdir(LOG_DIR, { recursive: true });
50
+ const filePath = join(LOG_DIR, `${id}.json`);
51
+ await writeFile(filePath, JSON.stringify(entry, null, 2), "utf-8");
52
+ await appendFile(join(LOG_DIR, "index.jsonl"), `${JSON.stringify({
53
+ id,
54
+ timestamp: entry.timestamp,
55
+ message,
56
+ filePath,
57
+ })}\n`, "utf-8");
58
+ return { id, filePath, entry };
59
+ }
60
+ export function formatErrorForUser(id, filePath, message) {
61
+ return [
62
+ `Error ${id}: ${message}`,
63
+ `Details saved to: ${filePath}`,
64
+ `When reporting an issue, include error ID: ${id}`,
65
+ ].join("\n");
66
+ }
67
+ //# sourceMappingURL=errorLog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorLog.js","sourceRoot":"","sources":["../src/errorLog.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,YAAY,EAAE,CAAC,CAyCzB"}
1
+ {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAYF,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,YAAY,EAAE,CAAC,CA4DzB"}
package/dist/scan.js CHANGED
@@ -2,6 +2,15 @@ import { MendixPlatformClient } from "mendixplatformsdk";
2
2
  import { microflows } from "mendixmodelsdk";
3
3
  import { writeFile } from "node:fs/promises";
4
4
  import { resolve } from "node:path";
5
+ import { ScanError } from "./errorLog.js";
6
+ function resolveModuleName(loadedMc) {
7
+ try {
8
+ return loadedMc.containerAsModule.name;
9
+ }
10
+ catch {
11
+ return undefined;
12
+ }
13
+ }
5
14
  export async function scanEmptyCaptions(options) {
6
15
  const client = new MendixPlatformClient();
7
16
  const app = await client.getApp(options.appId);
@@ -10,22 +19,36 @@ export async function scanEmptyCaptions(options) {
10
19
  const allMicroflows = model.allMicroflows();
11
20
  const modulesByName = new Map();
12
21
  for (const mc of allMicroflows) {
13
- const loadedMc = await mc.load();
14
- const emptyExclusiveSplits = loadedMc.objectCollection.objects.filter((activity) => activity instanceof microflows.ExclusiveSplit &&
15
- activity.caption === "");
16
- if (emptyExclusiveSplits.length === 0) {
17
- continue;
22
+ let loadedMc;
23
+ try {
24
+ loadedMc = await mc.load();
25
+ const emptyExclusiveSplits = loadedMc.objectCollection.objects.filter((activity) => activity instanceof microflows.ExclusiveSplit &&
26
+ activity.caption === "");
27
+ if (emptyExclusiveSplits.length === 0) {
28
+ continue;
29
+ }
30
+ const moduleName = resolveModuleName(loadedMc);
31
+ if (!moduleName) {
32
+ continue;
33
+ }
34
+ let moduleEntry = modulesByName.get(moduleName);
35
+ if (!moduleEntry) {
36
+ moduleEntry = { module: moduleName, microflows: [] };
37
+ modulesByName.set(moduleName, moduleEntry);
38
+ }
39
+ moduleEntry.microflows.push({
40
+ microflow: loadedMc.name,
41
+ emptyCaptions: emptyExclusiveSplits.length,
42
+ });
18
43
  }
19
- const moduleName = loadedMc.containerAsModule.name;
20
- let moduleEntry = modulesByName.get(moduleName);
21
- if (!moduleEntry) {
22
- moduleEntry = { module: moduleName, microflows: [] };
23
- modulesByName.set(moduleName, moduleEntry);
44
+ catch (error) {
45
+ throw new ScanError(error instanceof Error ? error.message : String(error), {
46
+ appId: options.appId,
47
+ branch: options.branch,
48
+ microflowId: mc.id,
49
+ microflowName: loadedMc?.name,
50
+ }, { cause: error });
24
51
  }
25
- moduleEntry.microflows.push({
26
- microflow: loadedMc.name,
27
- emptyCaptions: emptyExclusiveSplits.length,
28
- });
29
52
  }
30
53
  const results = [...modulesByName.values()];
31
54
  const outputPath = resolve(process.cwd(), options.outputPath);
package/dist/scan.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"scan.js","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBpC,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAAoB;IAEpB,MAAM,MAAM,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC1C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,0BAA0B,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACzE,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,SAAS,EAAE,CAAC;IAE5C,MAAM,aAAa,GAAG,KAAK,CAAC,aAAa,EAAE,CAAC;IAC5C,MAAM,aAAa,GAAG,IAAI,GAAG,EAAwB,CAAC;IAEtD,KAAK,MAAM,EAAE,IAAI,aAAa,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;QACjC,MAAM,oBAAoB,GAAG,QAAQ,CAAC,gBAAgB,CAAC,OAAO,CAAC,MAAM,CACnE,CAAC,QAAoC,EAAE,EAAE,CACvC,QAAQ,YAAY,UAAU,CAAC,cAAc;YAC7C,QAAQ,CAAC,OAAO,KAAK,EAAE,CAC1B,CAAC;QAEF,IAAI,oBAAoB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtC,SAAS;QACX,CAAC;QAED,MAAM,UAAU,GAAG,QAAQ,CAAC,iBAAiB,CAAC,IAAI,CAAC;QACnD,IAAI,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAEhD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,WAAW,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;YACrD,aAAa,CAAC,GAAG,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QAC7C,CAAC;QAED,WAAW,CAAC,UAAU,CAAC,IAAI,CAAC;YAC1B,SAAS,EAAE,QAAQ,CAAC,IAAI;YACxB,aAAa,EAAE,oBAAoB,CAAC,MAAM;SAC3C,CAAC,CAAC;IACL,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5C,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAE9D,MAAM,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAEvE,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../src/scan.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mx-empty-captions",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Scan Mendix apps for decision activities with empty captions",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",