@enfocussw/switch-scripting-context 25.11.0-beta.9 → 25.11.1-beta.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.
Files changed (35) hide show
  1. package/CHANGELOG.md +256 -0
  2. package/README.md +59 -35
  3. package/dist/init.d.ts +15 -0
  4. package/dist/init.js +130 -76
  5. package/docs/switch-api/api-versions.md +116 -0
  6. package/docs/switch-api/connection.md +82 -0
  7. package/docs/switch-api/{api-document-classes.md → document-classes.md} +13 -2
  8. package/docs/switch-api/entry-points.md +171 -0
  9. package/docs/switch-api/{api-enums.md → enums.md} +23 -12
  10. package/docs/switch-api/{api-execution-environment.md → execution-environment.md} +39 -12
  11. package/docs/switch-api/{api-flow-element.md → flow-element.md} +23 -7
  12. package/docs/switch-api/{api-http.md → http.md} +10 -1
  13. package/docs/switch-api/job-patterns.md +178 -0
  14. package/docs/switch-api/{api-job.md → job.md} +23 -9
  15. package/docs/switch-api/{api-logging.md → logging.md} +47 -5
  16. package/docs/switch-api/{api-switch.md → switch.md} +68 -4
  17. package/docs/switch-appstore/app-guidelines.md +258 -0
  18. package/docs/switch-appstore/app-manual.md +84 -0
  19. package/docs/switch-appstore/app-store-listing.md +69 -0
  20. package/docs/switch-appstore/app-store-submission.md +83 -0
  21. package/docs/{switch-api/api-debugging.md → switch-project/debugging.md} +9 -0
  22. package/docs/{switch-api/api-logs-and-dataroot.md → switch-project/logs-and-dataroot.md} +10 -1
  23. package/docs/switch-project/project-planning.md +117 -0
  24. package/docs/switch-project/property-documentation.md +75 -0
  25. package/docs/{switch-api/api-property-editors.md → switch-project/property-editors.md} +55 -8
  26. package/docs/{switch-api/api-script-declaration.md → switch-project/script-declaration.md} +47 -13
  27. package/docs/switch-project/script-structure.md +188 -0
  28. package/docs/{switch-api/api-tooling.md → switch-project/tooling.md} +87 -1
  29. package/docs/{switch-api/api-vscode.md → switch-project/vscode.md} +19 -0
  30. package/docs/switch-scripting.md +49 -23
  31. package/package.json +11 -7
  32. package/docs/switch-api/api-connection.md +0 -63
  33. package/docs/switch-api/api-entry-points.md +0 -82
  34. package/docs/switch-api/api-job-patterns.md +0 -79
  35. package/docs/switch-api/api-script-structure.md +0 -85
package/dist/init.js CHANGED
@@ -33,6 +33,8 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.parseRoutingTable = parseRoutingTable;
37
+ exports.apiFiles = apiFiles;
36
38
  exports.generateAgentsMd = generateAgentsMd;
37
39
  exports.generateGeminiMd = generateGeminiMd;
38
40
  exports.generateWindsurfRules = generateWindsurfRules;
@@ -47,6 +49,46 @@ const readline = __importStar(require("readline"));
47
49
  // ─── Markers ─────────────────────────────────────────────────────────────────
48
50
  const MARKER_BEGIN = '<!-- switch-scripting-context begin -->';
49
51
  const MARKER_END = '<!-- switch-scripting-context end -->';
52
+ // ─── Shared content (single source of truth for all generated tool files) ────
53
+ /** Package root, whether running from src/ (ts-node) or dist/. */
54
+ function packageRoot() {
55
+ return path.resolve(__dirname, '..');
56
+ }
57
+ /**
58
+ * The routing table in docs/switch-scripting.md is the single source of truth for
59
+ * which API docs exist and when to load each one. Everything the CLI generates is
60
+ * derived from it, so a new doc file needs registering in exactly one place here
61
+ * (plus README.md, which init.test.ts checks).
62
+ */
63
+ function parseRoutingTable(root = packageRoot()) {
64
+ const hub = fs.readFileSync(path.join(root, 'docs', 'switch-scripting.md'), 'utf8');
65
+ const docs = [];
66
+ for (const line of hub.split('\n')) {
67
+ // | `<switch-api|switch-project|switch-appstore>/<file>.md` | <contents> | <load when> |
68
+ const m = /^\|\s*`(switch-api|switch-project|switch-appstore)\/([a-z0-9-]+\.md)`\s*\|(.*)\|(.*)\|\s*$/.exec(line);
69
+ if (m)
70
+ docs.push({ file: `${m[1]}/${m[2]}`, loadWhen: m[4].trim() });
71
+ }
72
+ if (docs.length === 0) {
73
+ throw new Error('No API docs found in docs/switch-scripting.md — the routing table format changed. ' +
74
+ 'Generated tool config would be empty; fix parseRoutingTable() before publishing.');
75
+ }
76
+ return docs;
77
+ }
78
+ /** Filenames only, in routing-table order. */
79
+ function apiFiles(root) {
80
+ return parseRoutingTable(root).map(d => d.file);
81
+ }
82
+ const INLINE_CORE_RULES = `## Core rules
83
+
84
+ - Entry point functions are top-level async functions — do NOT use \`export\`, arrow functions, or class methods; declare them with the literal \`function\` keyword.
85
+ - Switch finds entry points with a regex, not a parser. Never write a string literal whose content ends with a backslash, a regex literal, or division outside the plain \`word / word\` shape — each silently deletes a span of real code and the entry points inside it, with no error. Read \`entry-points.md\` § Entry-point scanner constraints before editing \`main.ts\`/\`main.js\`.
86
+ - Every \`jobArrived\` must end with exactly one \`job.sendTo*()\` or \`job.fail()\`.
87
+ - Use \`AccessLevel.ReadOnly\` for \`job.get()\` unless the file content will be modified.
88
+ - After \`createJob()\`, \`createChild()\`, or \`createDataset()\` with a file path, delete the source file after routing — Switch does not auto-remove it.
89
+ - The XML declaration (\`<ScriptID>.xml\`) can be edited directly — read \`script-declaration.md\` first and follow its rules exactly (nothing validates this format, so mistakes fail silently). Never change an existing script's \`Name\`; bump \`Version\` on every declaration edit. Leave \`manifest.xml\` to the user unless explicitly asked.
90
+ - After editing \`main.ts\`, transpile with \`SwitchScriptTool --transpile <folder>\` — do not use \`tsc\` directly.
91
+ - Never use a script folder in production — pack with \`SwitchScriptTool --pack\` first; folders are excluded from flow exports.`;
50
92
  // ─── Content generators ──────────────────────────────────────────────────────
51
93
  function generateClaudeMd(docsDir) {
52
94
  return `${MARKER_BEGIN}
@@ -76,27 +118,6 @@ You are working on an Enfocus Switch scripting project (Node.js/TypeScript).
76
118
  ${MARKER_END}`;
77
119
  }
78
120
  function generateCursorMdc(docsDir) {
79
- const apiFiles = [
80
- 'api-entry-points.md',
81
- 'api-job.md',
82
- 'api-flow-element.md',
83
- 'api-connection.md',
84
- 'api-http.md',
85
- 'api-enums.md',
86
- 'api-document-classes.md',
87
- 'api-script-declaration.md',
88
- 'api-script-structure.md',
89
- 'api-tooling.md',
90
- 'api-debugging.md',
91
- 'api-vscode.md',
92
- 'api-property-editors.md',
93
- 'api-job-patterns.md',
94
- 'api-switch.md',
95
- 'api-execution-environment.md',
96
- 'api-logging.md',
97
- 'api-logs-and-dataroot.md',
98
- ];
99
- const fileList = apiFiles.map(f => `- \`${docsDir}/switch-api/${f}\``).join('\n');
100
121
  return `---
101
122
  description: Enfocus Switch scripting rules and API reference for Node.js/TypeScript scripts
102
123
  globs: ["**/*.ts", "**/*.js"]
@@ -106,55 +127,21 @@ alwaysApply: false
106
127
  ${MARKER_BEGIN}
107
128
  You are working on an Enfocus Switch scripting project (Node.js/TypeScript).
108
129
 
109
- ## Core rules
110
-
111
- - Entry point functions are top-level async functions — do NOT use \`export\`.
112
- - Every \`jobArrived\` must end with exactly one \`job.sendTo*()\` or \`job.fail()\`.
113
- - Use \`AccessLevel.ReadOnly\` for \`job.get()\` unless the file content will be modified.
114
- - After \`createJob()\`, \`createChild()\`, or \`createDataset()\` with a file path, delete the source file after routing — Switch does not auto-remove it.
115
- - Never edit \`<ScriptID>.xml\` or \`manifest.xml\` directly. For property/connection changes, instruct the user to use SwitchScripter.
116
- - After editing \`main.ts\`, transpile with \`SwitchScriptTool --transpile <folder>\` — do not use \`tsc\` directly.
117
- - Never use a script folder in production — pack with \`SwitchScriptTool --pack\` first; folders are excluded from flow exports.
130
+ ${INLINE_CORE_RULES}
118
131
 
119
132
  ## API reference
120
133
 
121
- Read \`${docsDir}/switch-scripting.md\` for the full index, then consult the relevant file:
134
+ Load the file matching the task below. \`${docsDir}/switch-scripting.md\` has the same index plus
135
+ the project-wide key rules:
122
136
 
123
- ${fileList}
137
+ ${inlineApiFileList(docsDir)}
124
138
  ${MARKER_END}`;
125
139
  }
126
- // ─── Shared inline content (for tools without @file import support) ──────────
127
- const INLINE_CORE_RULES = `## Core rules
128
-
129
- - Entry point functions are top-level async functions — do NOT use \`export\`.
130
- - Every \`jobArrived\` must end with exactly one \`job.sendTo*()\` or \`job.fail()\`.
131
- - Use \`AccessLevel.ReadOnly\` for \`job.get()\` unless the file content will be modified.
132
- - After \`createJob()\`, \`createChild()\`, or \`createDataset()\` with a file path, delete the source file after routing — Switch does not auto-remove it.
133
- - Never edit \`<ScriptID>.xml\` or \`manifest.xml\` directly. For property/connection changes, instruct the user to use SwitchScripter.
134
- - After editing \`main.ts\`, transpile with \`SwitchScriptTool --transpile <folder>\` — do not use \`tsc\` directly.
135
- - Never use a script folder in production — pack with \`SwitchScriptTool --pack\` first; folders are excluded from flow exports.`;
136
- const API_FILES = [
137
- 'api-entry-points.md',
138
- 'api-job.md',
139
- 'api-flow-element.md',
140
- 'api-connection.md',
141
- 'api-http.md',
142
- 'api-enums.md',
143
- 'api-document-classes.md',
144
- 'api-script-declaration.md',
145
- 'api-script-structure.md',
146
- 'api-tooling.md',
147
- 'api-debugging.md',
148
- 'api-vscode.md',
149
- 'api-property-editors.md',
150
- 'api-job-patterns.md',
151
- 'api-switch.md',
152
- 'api-execution-environment.md',
153
- 'api-logging.md',
154
- 'api-logs-and-dataroot.md',
155
- ];
140
+ // ─── Inline block (for tools without @file import support) ──────────────────
156
141
  function inlineApiFileList(docsDir) {
157
- return API_FILES.map(f => `- \`${docsDir}/switch-api/${f}\``).join('\n');
142
+ return parseRoutingTable()
143
+ .map(d => `- \`${docsDir}/${d.file}\` — ${d.loadWhen}`)
144
+ .join('\n');
158
145
  }
159
146
  function generateInlineBlock(docsDir) {
160
147
  return `You are working on an Enfocus Switch scripting project (Node.js/TypeScript).
@@ -163,7 +150,8 @@ ${INLINE_CORE_RULES}
163
150
 
164
151
  ## API reference
165
152
 
166
- Read \`${docsDir}/switch-scripting.md\` for the full index, then consult the relevant file:
153
+ Load the file matching the task below. \`${docsDir}/switch-scripting.md\` has the same index plus
154
+ the project-wide key rules:
167
155
 
168
156
  ${inlineApiFileList(docsDir)}`;
169
157
  }
@@ -345,13 +333,36 @@ function applyFileAction(action, dryRun) {
345
333
  console.log(` ${rel} → ${label}`);
346
334
  }
347
335
  // ─── Docs copy ────────────────────────────────────────────────────────────────
336
+ /** Paths under docs/ that are never shipped to a consuming project. */
337
+ const DOCS_EXCLUDE = ['superpowers', 'temp'];
348
338
  function copyDocs(packageRoot, destDir, dryRun) {
349
339
  const src = path.join(packageRoot, 'docs');
340
+ const rel = path.relative(process.cwd(), destDir);
350
341
  if (dryRun) {
351
- console.log(` [dry-run] Copying docs/ → ${path.relative(process.cwd(), destDir)}/`);
342
+ if (fs.existsSync(destDir)) {
343
+ console.log(` [dry-run] ${rel}/ → wiped (removes files from a previous version, e.g. after a doc was renamed or moved)`);
344
+ }
345
+ console.log(` [dry-run] Copying docs/ → ${rel}/`);
352
346
  return;
353
347
  }
354
- fs.cpSync(src, destDir, { recursive: true });
348
+ // destDir is entirely owned by this tool (see the .gitignore comment it writes), so wiping
349
+ // it first is safe. Without this, a doc renamed or moved between versions (e.g. a docs/
350
+ // folder restructuring) would leave the old file behind forever: cpSync only adds/overwrites,
351
+ // it never removes, and destDir is gitignored so nothing would surface the staleness.
352
+ if (fs.existsSync(destDir)) {
353
+ fs.rmSync(destDir, { recursive: true, force: true });
354
+ }
355
+ // The published tarball already omits these, but init may run from a git clone.
356
+ fs.cpSync(src, destDir, {
357
+ recursive: true,
358
+ filter: (from) => {
359
+ const rel = path.relative(src, from);
360
+ if (!rel)
361
+ return true;
362
+ const [top] = rel.split(path.sep);
363
+ return !DOCS_EXCLUDE.includes(top) && path.basename(from) !== '.DS_Store';
364
+ },
365
+ });
355
366
  console.log(` docs → ${path.relative(process.cwd(), destDir)}/`);
356
367
  }
357
368
  // ─── .gitignore update ───────────────────────────────────────────────────────
@@ -370,20 +381,46 @@ function updateGitignore(targetRoot, docsDir, dryRun) {
370
381
  fs.appendFileSync(gitignorePath, entry, 'utf8');
371
382
  console.log(` .gitignore → appended ${docsDir}/ entry`);
372
383
  }
373
- /** All AI config file paths that init may have created. */
374
- function aiConfigPaths(targetRoot, docsDir) {
375
- return TOOL_REGISTRY.flatMap(t => t.files.map(f => f.targetPath(targetRoot, docsDir)));
384
+ /** AI config files that init may have created, for all tools or only the given tool ids. */
385
+ function aiConfigFiles(targetRoot, docsDir, tools) {
386
+ return TOOL_REGISTRY
387
+ .filter(t => !tools || tools.includes(t.id))
388
+ .flatMap(t => t.files.map(file => ({ filePath: file.targetPath(targetRoot, docsDir), file })));
389
+ }
390
+ /** The frontmatter a generator writes above the marker, trimmed; empty if it writes none. */
391
+ function generatedFrontmatter(file, docsDir) {
392
+ const generated = file.generate(docsDir);
393
+ return generated.slice(0, generated.indexOf(MARKER_BEGIN)).trim();
376
394
  }
377
- function removeAiConfig(filePath, dryRun) {
395
+ /** Deletes now-empty folders from dir upwards, stopping at targetRoot. */
396
+ function removeEmptyDirs(dir, targetRoot) {
397
+ while (dir !== targetRoot && dir.startsWith(targetRoot + path.sep) && fs.readdirSync(dir).length === 0) {
398
+ fs.rmdirSync(dir);
399
+ dir = path.dirname(dir);
400
+ }
401
+ }
402
+ function removeAiConfig(filePath, file, docsDir, targetRoot, dryRun) {
378
403
  if (!fs.existsSync(filePath))
379
404
  return;
380
- const content = fs.readFileSync(filePath, 'utf8');
405
+ const raw = fs.readFileSync(filePath, 'utf8');
406
+ const eol = raw.includes('\r\n') ? '\r\n' : '\n';
407
+ const content = raw.replace(/\r\n/g, '\n');
381
408
  const range = findMarkerRange(content);
382
409
  if (!range)
383
410
  return; // nothing from us in this file
384
411
  const rel = path.relative(process.cwd(), filePath);
385
- const before = content.slice(0, range[0]).trim();
412
+ let before = content.slice(0, range[0]).trim();
386
413
  const after = content.slice(range[1]).trim();
414
+ // Copilot scoped instructions and Cursor .mdc put frontmatter above the marker. Only an exact
415
+ // copy of what the generator writes counts as ours; edited or user-written frontmatter stays.
416
+ const ours = generatedFrontmatter(file, docsDir);
417
+ if (ours && before === ours) {
418
+ before = '';
419
+ }
420
+ else if (ours && before.endsWith('\n' + ours)) {
421
+ // init appended our block, frontmatter included, below the user's own content
422
+ before = before.slice(0, -ours.length).trim();
423
+ }
387
424
  if (!before && !after) {
388
425
  // File is entirely our content — delete it
389
426
  if (dryRun) {
@@ -391,6 +428,7 @@ function removeAiConfig(filePath, dryRun) {
391
428
  return;
392
429
  }
393
430
  fs.unlinkSync(filePath);
431
+ removeEmptyDirs(path.dirname(filePath), targetRoot);
394
432
  console.log(` ${rel} → deleted`);
395
433
  }
396
434
  else {
@@ -400,7 +438,7 @@ function removeAiConfig(filePath, dryRun) {
400
438
  console.log(` [dry-run] ${rel} → removed Switch section`);
401
439
  return;
402
440
  }
403
- fs.writeFileSync(filePath, stripped, 'utf8');
441
+ fs.writeFileSync(filePath, stripped.replace(/\n/g, eol), 'utf8');
404
442
  console.log(` ${rel} → removed Switch section`);
405
443
  }
406
444
  }
@@ -427,6 +465,18 @@ function remove(options) {
427
465
  const docsDestDir = path.join(targetRoot, options.docsDir);
428
466
  if (options.dryRun)
429
467
  console.log('\nDry run — no files will be written.\n');
468
+ const tools = options.tools;
469
+ const partial = tools && !TOOL_REGISTRY.every(t => tools.includes(t.id));
470
+ if (partial) {
471
+ // Removing some tools leaves the rest configured, and they still reference the docs folder.
472
+ // Listing every tool leaves nothing referencing it, so that falls through to a full remove.
473
+ console.log('Cleaning AI config files...');
474
+ for (const { filePath, file } of aiConfigFiles(targetRoot, options.docsDir, options.tools)) {
475
+ removeAiConfig(filePath, file, options.docsDir, targetRoot, options.dryRun);
476
+ }
477
+ console.log('\nDone.\n');
478
+ return;
479
+ }
430
480
  // 1. Remove docs dir
431
481
  console.log('Removing docs...');
432
482
  if (fs.existsSync(docsDestDir)) {
@@ -443,8 +493,8 @@ function remove(options) {
443
493
  }
444
494
  // 2. Remove AI config sections / files
445
495
  console.log('\nCleaning AI config files...');
446
- for (const filePath of aiConfigPaths(targetRoot, options.docsDir)) {
447
- removeAiConfig(filePath, options.dryRun);
496
+ for (const { filePath, file } of aiConfigFiles(targetRoot, options.docsDir)) {
497
+ removeAiConfig(filePath, file, options.docsDir, targetRoot, options.dryRun);
448
498
  }
449
499
  // 3. Update .gitignore
450
500
  console.log('\nUpdating .gitignore...');
@@ -519,6 +569,7 @@ function parseArgs(argv) {
519
569
  process.exit(1);
520
570
  }
521
571
  initOptions.tools = raw.map(t => idMap.get(t));
572
+ removeOptions.tools = initOptions.tools;
522
573
  toolsExplicit = true;
523
574
  }
524
575
  else if (arg === '--docs-dir' && args[i + 1]) {
@@ -569,7 +620,7 @@ Usage: switch-scripting-context <command> [options]
569
620
 
570
621
  Commands:
571
622
  init Copy docs and generate AI context config files
572
- remove Remove all files and config added by init
623
+ remove Remove files and config added by init (all of it, or only some tools' config)
573
624
 
574
625
  Options (init):
575
626
  --tools <list> Comma-separated tools to configure
@@ -582,6 +633,8 @@ Options (init):
582
633
  --help Show this help message
583
634
 
584
635
  Options (remove):
636
+ --tools <list> Only remove these tools' config; keeps the docs folder and other tools
637
+ Default: remove everything, same as listing every tool
585
638
  --docs-dir <dir> Docs folder to remove (default: switch-docs)
586
639
  --dry-run Print what would happen without writing any files
587
640
 
@@ -591,6 +644,7 @@ Examples:
591
644
  npx switch-scripting-context init --docs-dir ai-docs --dry-run
592
645
  npx switch-scripting-context remove
593
646
  npx switch-scripting-context remove --dry-run
647
+ npx switch-scripting-context remove --tools cursor
594
648
  `);
595
649
  }
596
650
  // ─── Entry point ─────────────────────────────────────────────────────────────
@@ -0,0 +1,116 @@
1
+ ---
2
+ id: api-versions
3
+ category: switch-api
4
+ order: 25
5
+ summary: "Which Switch release added each scripting API class, method, and enum value; API availability follows the running Switch, not `manifest.xml`"
6
+ triggers:
7
+ - "Writing or reviewing code for a script or app that must run on a Switch version older than the latest, or when the user names a minimum Switch version"
8
+ ---
9
+
10
+ # API availability by Switch version
11
+
12
+ ## The running Switch decides which methods exist
13
+
14
+ Each Switch installation ships one copy of the scripting module, and every bundled Node.js version
15
+ uses that same copy. So which API methods a script can call depends on the Switch Server the script
16
+ runs on, not on anything in the script package. A script whose `manifest.xml` says `20.1` runs on
17
+ Node.js 12 in Switch 26.07, and it still gets the full 26.07 API.
18
+
19
+ The two versions are independent:
20
+
21
+ | Depends on | Decided by |
22
+ |---|---|
23
+ | Node.js version (language features, Node built-ins) | `SwitchVersion` in `manifest.xml`, looked up by the running Switch. See [script-structure.md § Node.js version per Switch version](../switch-project/script-structure.md#nodejs-version-per-switch-version) |
24
+ | Scripting API (classes, methods, enum values below) | The version of the Switch Server the script runs on |
25
+
26
+ When code must run on an older Switch, check every API call against the tables below for the
27
+ **oldest** Switch version the script or app must support. For an app, that is the version baseline
28
+ from [project-planning.md § Switch version baseline](../switch-project/project-planning.md#switch-version-baseline-apps-only).
29
+
30
+ ### Checking at runtime
31
+
32
+ `s.getServerVersion()` (Switch 24.0+) returns the running Switch version as a number, e.g. `25.11`.
33
+ It doesn't exist on older Switch versions, so it can't detect those. To use a newer method when
34
+ available and fall back otherwise, test for the method itself:
35
+
36
+ ```ts
37
+ if (typeof job.getVariableAsString === 'function') {
38
+ // Switch 24.0+
39
+ } else {
40
+ // fallback for older Switch versions
41
+ }
42
+ ```
43
+
44
+ ## Release names
45
+
46
+ | `SwitchVersion` | Release |
47
+ |---|---|
48
+ | `20.0` | Switch 2020 Spring |
49
+ | `20.1` | Switch 2020 Fall |
50
+ | `21.0` | Switch 2021 Spring |
51
+ | `21.1` | Switch 2021 Fall |
52
+ | `22.0` | Switch 2022 Spring |
53
+ | `22.1` | Switch 2022 Fall |
54
+ | `23.1` | Switch 2023 Fall |
55
+ | `24.0` | Switch 2024 Spring |
56
+ | `24.1` | Switch 2024 Fall |
57
+ | `25.07` | Switch 25.07 |
58
+ | `25.11` | Switch 25.11 |
59
+ | `26.03` | Switch 26.03 |
60
+ | `26.07` | Switch 26.07 |
61
+
62
+ ## Source and limits of this list
63
+
64
+ The list comes from Enfocus's published type declarations
65
+ (`github.com/enfocus-switch/types-switch-scripting`), diffed from one release's tags to the next.
66
+ Several tags for one release (for example 22.1.0 and 22.1.1) are corrections to the declarations
67
+ for that release, not API changes, so they count as one release. A release with no tag added
68
+ nothing.
69
+
70
+ - The first tags (1.0.0 and 1.0.1, October 2020) are the baseline. The declarations don't separate
71
+ Switch 2020 Spring from 2020 Fall, so treat the baseline as available in every Switch version
72
+ that runs Node.js scripts.
73
+ - Tag 1.1.0 (May 2021) is Switch 2021 Spring. The later tags carry the release number (21.1.x,
74
+ 22.0.x, 22.1.x, 24.0.x, 24.1.x).
75
+ - The declarations end at v24.1.1-final (Switch 2024 Fall). SwitchScriptTool 26.07 still scaffolds
76
+ that version. A check of the Switch 26.07 scripting module found no public class, method, or enum
77
+ value that v24.1.1 lacks. So nothing was added in 23.1, 25.07, 25.11, 26.03, or 26.07.
78
+ - Entry points aren't part of the type declarations, so this list doesn't record when each entry
79
+ point appeared. The webhook entry points (`httpRequestTriggeredSync`/`Async`) need
80
+ `s.httpRequestSubscribe()`, so they can't be used before Switch 21.1 either.
81
+
82
+ ## Baseline (every Switch version with Node.js scripting)
83
+
84
+ | Class | Members |
85
+ |---|---|
86
+ | `Switch` | `getGlobalData`, `setGlobalData`, `removeGlobalData` (including the `lock` parameter) |
87
+ | `FlowElement` | `getPropertyStringValue`, `getPropertyType`, `getPropertyDisplayName`, `hasProperty`, `getOutConnections`, `setTimerInterval`, `log`, `failProcess`, `createJob`, `getPluginResourcesPath` |
88
+ | `Job` | `getName`, `getId`, `isFile`, `isFolder`, `get`, `sendToNull`, `sendToSingle`, `sendTo`, `sendToData`, `sendToLog`, `fail`, `log`, `createChild`, `getPrivateData`, `setPrivateData`, `removePrivateData`, `listDatasets`, `createDataset`, `getDataset`, `removeDataset` |
89
+ | `Connection` | `getId`, `getName`, `getPropertyStringValue`, `getPropertyType`, `getPropertyDisplayName`, `hasProperty` |
90
+ | Enums | `AccessLevel` (all), `Connection.Level` (all), `PropertyType` (all), `LogLevel.Info`/`Warning`/`Error`, `DatasetModel.Opaque`/`XML`/`XMP`/`JDF`, `Scope.Element`/`FlowElement`/`Global` |
91
+
92
+ ## Added per release
93
+
94
+ | Release | Added |
95
+ |---|---|
96
+ | 21.0 | `flowElement.getJobs()`; `PdfDocument` and `PdfPage` (whole classes); `EnfocusSwitchPrivateDataTag` with `hierarchy`, `emailAddresses`, `emailBody`, `userName`, `userFullName`, `userEmail`, `origin`; `LogLevel.Debug` |
97
+ | 21.1 | `flowElement.getName()`; `HttpRequest` and `HttpResponse` (whole classes, including `HttpRequest.Method`); `s.httpRequestSubscribe()`, `s.httpRequestUnsubscribe()`; `ImageDocument` (whole class, including `ImageDocument.ColorMode` and `ImageDocument.ColorSpace`); `EnfocusSwitchPrivateDataTag.initiated`, `.submittedTo` |
98
+ | 22.0 | `flowElement.getFlowName()`; `Switch.tr()`; `XmlDocument` (whole class); `Scope.Flow`, `Scope.FlowElements`; `DatasetModel.JSON` |
99
+ | 22.1 | `job.getPriority()`, `job.setPriority()`, `Priority` enum; `job.sendToChannel()`, `flowElement.subscribeToChannel()`; `job.processLater()`; `s.setAbortData()`; `XmpDocument` (whole class), `pdfDocument.getXMP()`; `EnfocusSwitchPrivateDataTag.state` |
100
+ | 23.1 | Nothing |
101
+ | 24.0 | `flowElement.getScriptDataPath()`, `flowElement.createPathWithName()`; `job.getVariableAsString()`, `job.getxmlData()`, `job.getxmpData()`, `job.getJdfData()`, `job.getJSONData()`; `s.getPreferenceSetting()`, `s.getServerVersion()`; `NoYesListPropertyStringValue` |
102
+ | 24.1 | `connection.getType()`, `connection.getFileCount()`, `flowElement.getFileCount()` |
103
+ | 25.07, 25.11, 26.03, 26.07 | Nothing |
104
+
105
+ ## Declaration changes to existing methods
106
+
107
+ These signatures changed between releases in the declarations. The declarations don't say whether
108
+ older runtimes enforced the older signature, so when targeting a release before the change, write
109
+ code that satisfies both.
110
+
111
+ - Before 21.0, private data and global data values were declared as `string`; from 21.0 they are
112
+ `any`. On 20.x, store strings (for example `JSON.stringify` the value) and parse them on read.
113
+ - Before 21.0, `job.fail()` declared `messageParams` as required. On 20.x, pass an array, even an
114
+ empty one.
115
+ - Before 22.1, `flowElement.failProcess()` declared `messageParam` as a required `string`. On an
116
+ older Switch, pass a string.
@@ -0,0 +1,82 @@
1
+ ---
2
+ id: connection
3
+ category: switch-api
4
+ order: 6
5
+ summary: "`Connection`: type, properties, file count"
6
+ triggers:
7
+ - "Routing to specific connections or reading connection properties"
8
+ ---
9
+
10
+ # Connection Class
11
+
12
+ A `Connection` represents an outgoing connection from the flow element. Obtain instances via `flowElement.getOutConnections()`.
13
+
14
+ ## Identity
15
+
16
+ ```ts
17
+ connection.getId(): string
18
+ ```
19
+ Unique ID for the connection. Stable across deactivate/reactivate, Switch restarts, holding/releasing connections, and renaming the flow itself. Changes on export/re-import, a flow upgrade, or renaming the flow *element* (not the flow).
20
+
21
+ ```ts
22
+ connection.getName(): string
23
+ ```
24
+ Display name as shown on the canvas. May be an empty string.
25
+
26
+ ```ts
27
+ // Switch 24.1+
28
+ connection.getType(): string
29
+ ```
30
+ Connection type. One of: `"Move"`, `"Filter"`, `"Traffic-data"`, `"Traffic-log"`, `"Traffic-datawithlog"`.
31
+
32
+ ## Connection properties
33
+
34
+ Connection properties are declared in the script's XML declaration (`ConnectionFields`) and configured per-connection in the canvas. See [script-declaration.md](../switch-project/script-declaration.md) for how to declare them (via SwitchScripter).
35
+
36
+ ```ts
37
+ connection.getPropertyStringValue(tag: string): Promise<string | string[]>
38
+ ```
39
+ Returns the connection property value as a string. Throws `"Invalid tag: <tag>"` if the tag is unknown **or if it's a `Dependency` dependent currently hidden by its master's value** — see [script-declaration.md § Dependency](../switch-project/script-declaration.md#custom-property-elements-elementfields). Before fetching a dependent property, confirm its condition holds (from the already-read master value, or via `hasProperty(tag)` below) rather than fetching it unconditionally.
40
+
41
+ This is **not** how to check which traffic light level(s) a connection accepts before calling `job.sendToData()` — `"Success"`/`"Warning"`/`"Error"` are not property tags, so passing one throws the same invalid-tag error. There is no supported way to check in advance; see [Connection.Level enum](#connectionlevel-enum) below.
42
+
43
+ ```ts
44
+ connection.getPropertyType(tag: string): PropertyType
45
+ ```
46
+ Returns the `PropertyType` of the property.
47
+
48
+ ```ts
49
+ connection.getPropertyDisplayName(tag: string): string
50
+ ```
51
+ Returns the English display name of the property (for use in log messages).
52
+
53
+ ```ts
54
+ connection.hasProperty(tag: string): boolean
55
+ ```
56
+ Returns `true` if the property exists and is visible for the current configuration. Use this to guard `getPropertyStringValue(tag)` calls on `Dependency` dependents — see the note above.
57
+
58
+ ## File count
59
+
60
+ ```ts
61
+ // Switch 24.1+
62
+ connection.getFileCount(nested?: boolean): Promise<number>
63
+ ```
64
+ Returns the number of files in the folder at the other end of this connection. If `nested` is `false`, counts only direct children; if `true` (the default, so it can be omitted), counts recursively (subfolders themselves are not counted).
65
+
66
+ ## Connection.Level enum
67
+
68
+ Used with `job.sendToData()` and `job.sendToLog()` to select which traffic light connection a job routes to.
69
+
70
+ | Value | String |
71
+ |---|---|
72
+ | `Connection.Level.Success` | `"success"` |
73
+ | `Connection.Level.Warning` | `"warning"` |
74
+ | `Connection.Level.Error` | `"error"` |
75
+
76
+ Available as `EnfocusSwitch.Connection.Level.*` outside `main.ts`.
77
+
78
+ **Traffic light levels are not a readable connection property.** `flowElement.getOutConnections()`
79
+ returns the outgoing `Connection` objects, but the supported API has no way to determine which
80
+ level(s) a given connection accepts. Don't call `connection.getPropertyStringValue("Success")`, `"Warning"`, or `"Error"` expecting to
81
+ read this back; those are not valid property tags for a traffic light connection. To route
82
+ optionally, see [job-patterns.md § Sending jobs](job-patterns.md#sending-jobs).
@@ -1,7 +1,18 @@
1
+ ---
2
+ id: document-classes
3
+ category: switch-api
4
+ order: 9
5
+ summary: "`PdfDocument`, `PdfPage`, `ImageDocument`, `XmlDocument`, `XmpDocument`: read-only file introspection"
6
+ triggers:
7
+ - "Inspecting PDF, image, XML, or XMP file contents"
8
+ ---
9
+
1
10
  # Document Classes
2
11
 
3
12
  Read-only document introspection utilities. All methods may throw — wrap in `try/catch`. Load this file when working with PDF, image, XML, or XMP documents.
4
13
 
14
+ Each class needs a minimum Switch version: `PdfDocument` and `PdfPage` 21.0+, `ImageDocument` 21.1+, `XmlDocument` 22.0+, `XmpDocument` and `doc.getXMP()` 22.1+.
15
+
5
16
  ## PdfDocument
6
17
 
7
18
  Open a PDF to inspect metadata and page geometry.
@@ -31,7 +42,7 @@ doc.getSecurityMethod(): string
31
42
  PdfDocument.getSecurityMethod(path: string): string
32
43
 
33
44
  doc.getPage(pageNumber?: number): PdfPage // 1-based; defaults to page 1
34
- doc.getXMP(): XmpDocument
45
+ doc.getXMP(): XmpDocument // Switch 22.1+
35
46
  ```
36
47
 
37
48
  ### Static page dimension methods
@@ -121,7 +132,7 @@ img.getSamplesPerPixel(): number
121
132
  ImageDocument.getSamplesPerPixel(path: string): Promise<number>
122
133
  ```
123
134
 
124
- See [api-enums.md](api-enums.md) for `ImageDocument.ColorMode` and `ImageDocument.ColorSpace` values.
135
+ See [enums.md](enums.md) for `ImageDocument.ColorMode` and `ImageDocument.ColorSpace` values.
125
136
 
126
137
  ---
127
138