@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.
- package/CHANGELOG.md +256 -0
- package/README.md +59 -35
- package/dist/init.d.ts +15 -0
- package/dist/init.js +130 -76
- package/docs/switch-api/api-versions.md +116 -0
- package/docs/switch-api/connection.md +82 -0
- package/docs/switch-api/{api-document-classes.md → document-classes.md} +13 -2
- package/docs/switch-api/entry-points.md +171 -0
- package/docs/switch-api/{api-enums.md → enums.md} +23 -12
- package/docs/switch-api/{api-execution-environment.md → execution-environment.md} +39 -12
- package/docs/switch-api/{api-flow-element.md → flow-element.md} +23 -7
- package/docs/switch-api/{api-http.md → http.md} +10 -1
- package/docs/switch-api/job-patterns.md +178 -0
- package/docs/switch-api/{api-job.md → job.md} +23 -9
- package/docs/switch-api/{api-logging.md → logging.md} +47 -5
- package/docs/switch-api/{api-switch.md → switch.md} +68 -4
- package/docs/switch-appstore/app-guidelines.md +258 -0
- package/docs/switch-appstore/app-manual.md +84 -0
- package/docs/switch-appstore/app-store-listing.md +69 -0
- package/docs/switch-appstore/app-store-submission.md +83 -0
- package/docs/{switch-api/api-debugging.md → switch-project/debugging.md} +9 -0
- package/docs/{switch-api/api-logs-and-dataroot.md → switch-project/logs-and-dataroot.md} +10 -1
- package/docs/switch-project/project-planning.md +117 -0
- package/docs/switch-project/property-documentation.md +75 -0
- package/docs/{switch-api/api-property-editors.md → switch-project/property-editors.md} +55 -8
- package/docs/{switch-api/api-script-declaration.md → switch-project/script-declaration.md} +47 -13
- package/docs/switch-project/script-structure.md +188 -0
- package/docs/{switch-api/api-tooling.md → switch-project/tooling.md} +87 -1
- package/docs/{switch-api/api-vscode.md → switch-project/vscode.md} +19 -0
- package/docs/switch-scripting.md +49 -23
- package/package.json +11 -7
- package/docs/switch-api/api-connection.md +0 -63
- package/docs/switch-api/api-entry-points.md +0 -82
- package/docs/switch-api/api-job-patterns.md +0 -79
- 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
|
-
|
|
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
|
-
|
|
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
|
-
${
|
|
137
|
+
${inlineApiFileList(docsDir)}
|
|
124
138
|
${MARKER_END}`;
|
|
125
139
|
}
|
|
126
|
-
// ───
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
374
|
-
function
|
|
375
|
-
return TOOL_REGISTRY
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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 [
|
|
135
|
+
See [enums.md](enums.md) for `ImageDocument.ColorMode` and `ImageDocument.ColorSpace` values.
|
|
125
136
|
|
|
126
137
|
---
|
|
127
138
|
|