@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
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: property-documentation
|
|
3
|
+
category: switch-project
|
|
4
|
+
order: 21
|
|
5
|
+
summary: "Writing guidance for `Tooltip` and `DetailedInfo` content on properties/connections"
|
|
6
|
+
triggers:
|
|
7
|
+
- "Writing or reviewing the text in a property's or connection's `Tooltip`/`DetailedInfo`"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Writing Property and Connection Documentation
|
|
11
|
+
|
|
12
|
+
Guidance for the *content* of `Tooltip` and `DetailedInfo` on properties and connections — see
|
|
13
|
+
[script-declaration.md](script-declaration.md#custom-property-elements-elementfields) for
|
|
14
|
+
the attribute mechanics (when each is required, what breaks if omitted). This page covers what to
|
|
15
|
+
actually write in them.
|
|
16
|
+
|
|
17
|
+
Both attributes are read only inside Switch Designer, by someone who has already added the flow
|
|
18
|
+
element to a flow. Compare with [app-store-listing.md](../switch-appstore/app-store-listing.md), read by
|
|
19
|
+
someone deciding whether to install the app at all, and [app-manual.md](../switch-appstore/app-manual.md), a
|
|
20
|
+
separate uploaded document.
|
|
21
|
+
|
|
22
|
+
**Delivery:** write this content directly into the `Tooltip`/`DetailedInfo` attributes in
|
|
23
|
+
`<ScriptID>.xml` — there is no separate file. See
|
|
24
|
+
[script-declaration.md § Agent editing policy](script-declaration.md#agent-editing-policy)
|
|
25
|
+
for how to edit the declaration safely.
|
|
26
|
+
|
|
27
|
+
## Tooltip
|
|
28
|
+
|
|
29
|
+
The one-line hint shown in the Properties pane. This is the field that matters most here — it's
|
|
30
|
+
always visible to whoever is configuring the property, connection, or the app's own icon, with no
|
|
31
|
+
extra click required.
|
|
32
|
+
|
|
33
|
+
- Add information the property name doesn't already give: units, valid range, format, or an
|
|
34
|
+
example value. A tooltip that just restates the label ("Output folder: the output folder to
|
|
35
|
+
use") wastes the one line a user reliably reads.
|
|
36
|
+
- If no sensible default is possible, put an example value in the tooltip — see the `Default`
|
|
37
|
+
guideline in [script-declaration.md](script-declaration.md#custom-property-elements-elementfields).
|
|
38
|
+
- Sentence-style capitalization, no trailing period, one line. Match the style already used in
|
|
39
|
+
declarations: `Tooltip="Select the output folder"`.
|
|
40
|
+
- Skip it only when the property is genuinely self-explanatory from its name alone, with no
|
|
41
|
+
constraints worth stating (e.g. "Number of copies" with no min/max).
|
|
42
|
+
|
|
43
|
+
## DetailedInfo
|
|
44
|
+
|
|
45
|
+
Feeds the HTML documentation Switch Designer can export for a whole *flow* — not something
|
|
46
|
+
specific to this app, it's compiled from every element the flow builder happens to have placed in
|
|
47
|
+
that flow. Real, but low priority in practice: it's an opt-in export most flow builders never
|
|
48
|
+
generate, and plenty of shipped apps leave it blank. Don't treat an empty `DetailedInfo` as a
|
|
49
|
+
defect to pad out.
|
|
50
|
+
|
|
51
|
+
Fill it in when the tooltip's one line genuinely isn't enough — an interaction with another
|
|
52
|
+
property, an edge case worth flagging, or why a setting matters, not a restatement of the tooltip
|
|
53
|
+
in longer sentences. A trivial property with `DetailedInfo=""` is expected and fine.
|
|
54
|
+
|
|
55
|
+
If you do write `DetailedInfo`, don't rely on it being the only place that content exists — the
|
|
56
|
+
property's fuller description belongs in [app-manual.md](../switch-appstore/app-manual.md#properties-detailed-info)
|
|
57
|
+
regardless, since that document is far more likely to actually be read.
|
|
58
|
+
|
|
59
|
+
## Writing quality
|
|
60
|
+
|
|
61
|
+
Applies to both fields, and is the same bar [app-store-listing.md](../switch-appstore/app-store-listing.md)
|
|
62
|
+
and [app-manual.md](../switch-appstore/app-manual.md) hold their content to:
|
|
63
|
+
|
|
64
|
+
- **Don't restate the field name.** A tooltip on "Output folder" that says "The output folder"
|
|
65
|
+
adds nothing a user didn't already know.
|
|
66
|
+
- **No generic AI/marketing vocabulary** — powerful, seamless, robust, intuitive, and similar
|
|
67
|
+
words that could describe any property in any app. Say the specific thing this one does.
|
|
68
|
+
- **No meta-commentary about the implementation.** Write what the user sees or does, not how the
|
|
69
|
+
script is coded internally ("this property is passed to the internal handler").
|
|
70
|
+
- **No vague filler.** "Set this to an appropriate value" tells a user nothing; a concrete unit,
|
|
71
|
+
range, or example does.
|
|
72
|
+
- **No copy-pasted boilerplate across properties.** Identical tooltip text reused on unrelated
|
|
73
|
+
properties signals nobody thought about the individual property.
|
|
74
|
+
- **Keep it translatable.** Idioms and culture-specific references don't translate cleanly into
|
|
75
|
+
the six Switch languages — see [switch.md § Translation extraction rules](../switch-api/switch.md#translation-extraction-rules).
|
|
@@ -1,20 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: property-editors
|
|
3
|
+
category: switch-project
|
|
4
|
+
order: 15
|
|
5
|
+
summary: "Property editor types, string return values, literal editors, dropdowns"
|
|
6
|
+
triggers:
|
|
7
|
+
- "Defining property editors in XML or reading property values in code"
|
|
8
|
+
---
|
|
9
|
+
|
|
1
10
|
# Property Editors
|
|
2
11
|
|
|
3
12
|
Property editors determine how a user enters a value in Switch Designer, and what string is
|
|
4
13
|
returned by `getPropertyStringValue()` at runtime. They're set in the XML declaration via the
|
|
5
14
|
`Editor` and `Type` attributes on a custom property — see
|
|
6
|
-
[
|
|
15
|
+
[script-declaration.md](script-declaration.md) for the surrounding attribute grammar.
|
|
7
16
|
|
|
8
17
|
All property values are returned as `string` or `string[]`. `getPropertyType()` returns one of a
|
|
9
18
|
fixed set of `PropertyType` values (`literal`, `string`, `number`, `date`, `boolean`, `filepath`,
|
|
10
|
-
`folderpath`, `regex`, `oauthtoken`, etc. — see [
|
|
19
|
+
`folderpath`, `regex`, `oauthtoken`, etc. — see [enums.md](../switch-api/enums.md)) describing what kind of
|
|
11
20
|
value is actually present; `literal` is only one of these, not a binary "literal vs. user-entered"
|
|
12
21
|
flag. Use it before interpreting the returned string, e.g. to check for a literal editor's constant
|
|
13
22
|
before comparing it.
|
|
14
23
|
|
|
15
24
|
`Editor` is a `;`-joined list: the inline editor's token (if any) first, then modal editor tokens in
|
|
16
25
|
the order they're offered. `Type` follows from which editor(s) are chosen — see the tables below and
|
|
17
|
-
[the Type reference](
|
|
26
|
+
[the Type reference](script-declaration.md#type-reference).
|
|
18
27
|
|
|
19
28
|
---
|
|
20
29
|
|
|
@@ -48,8 +57,8 @@ open a dialog when the user clicks the editor button. All have `Type="string"` u
|
|
|
48
57
|
| `regexp` | Regular expression string as entered |
|
|
49
58
|
| `filetype` | Filename pattern(s) for the selected file type |
|
|
50
59
|
| `types` (`Type="filefilter"`) | `string[]` — one pattern string per selected file type |
|
|
51
|
-
| `askplugin` | String value selected from the library dialog (calls `getLibraryForProperty`) |
|
|
52
|
-
| `askplugin2` | `string[]` — one string per selected library item (calls `getLibraryForMultipleProperty`) |
|
|
60
|
+
| `askplugin` | String value selected from the library dialog (calls `getLibraryForProperty`) — **requires the script to implement `getLibraryForProperty`** (`getLibraryForConnectionProperty` for a connection field), see [entry-points.md](../switch-api/entry-points.md#property-ui-callbacks) |
|
|
61
|
+
| `askplugin2` | `string[]` — one string per selected library item (calls `getLibraryForMultipleProperty`) — **requires a matching library-callback entry point**, same as `askplugin` above. ⚠ `getLibraryForMultipleProperty` isn't documented anywhere in [entry-points.md](../switch-api/entry-points.md#property-ui-callbacks), which only lists `getLibraryForProperty`/`getLibraryForConnectionProperty` — this may be the same entry point handling both single- and multi-select, or a genuinely separate, undocumented one; needs verifying against source before relying on the name here. |
|
|
53
62
|
| `description` | Multi-line text as a single string (may include newlines) |
|
|
54
63
|
| `scriptexp` | Result of script expression evaluated in job context, as a string |
|
|
55
64
|
| `sltextwithvar` | Single-line text with variables substituted, as a string |
|
|
@@ -58,7 +67,7 @@ open a dialog when the user clicks the editor button. All have `Type="string"` u
|
|
|
58
67
|
| `filepatterns` | `string[]` — one pattern string per entry |
|
|
59
68
|
| `folderpatterns` | `string[]` — one pattern string per entry |
|
|
60
69
|
| `stringlist` (`Type="stringlist"`) | `string[]` — one string per line |
|
|
61
|
-
| `oauth` | OAuth 2.0 access token string, or `""` if not yet authorized — see [ExtraProperties](
|
|
70
|
+
| `oauth` | OAuth 2.0 access token string, or `""` if not yet authorized — see [ExtraProperties](script-declaration.md#extraproperties) |
|
|
62
71
|
| `external`, `external2`, … | File path to a property set edited by an external companion app |
|
|
63
72
|
|
|
64
73
|
> Duplicate tokens in `Editor` are meaningless — each modal editor can only be offered once, except
|
|
@@ -75,6 +84,14 @@ constant as one of the choices; all literal tokens have `Type="string"`.
|
|
|
75
84
|
Always call `getPropertyType()` first to check whether the value is a literal before comparing the
|
|
76
85
|
string.
|
|
77
86
|
|
|
87
|
+
Use the matching literal editor for a keyword-style value like "Default", "None", or "Automatic"
|
|
88
|
+
instead of making it a typed string default — e.g. `default` instead of a `Default`
|
|
89
|
+
attribute set to the literal text `"Default"`. Typing the keyword as an ordinary string default lets
|
|
90
|
+
a user accidentally change it to arbitrary text and loses the `PropertyType.Literal` signal the
|
|
91
|
+
script relies on. `none` is specifically the sanctioned way to let a property hold an empty value
|
|
92
|
+
under `Validation="Standard"` — combine it into the `Editor` chain instead of relaxing to
|
|
93
|
+
`Validation="None"` just to permit emptiness.
|
|
94
|
+
|
|
78
95
|
| `Editor` token | `getPropertyStringValue()` returns |
|
|
79
96
|
|---|---|
|
|
80
97
|
| `default` | `"Default"` |
|
|
@@ -89,6 +106,19 @@ string.
|
|
|
89
106
|
| `next` | `"Next"` |
|
|
90
107
|
| `current` | `"Current"` |
|
|
91
108
|
|
|
109
|
+
`nofiles`/`allfiles`/`allotherfiles` and `nofolders`/`allfolders`/`allotherfolders` are not
|
|
110
|
+
general-purpose — every real use of them is a connection **include/exclude filter mask** (an
|
|
111
|
+
`IncludeMask`/`ExcludeMask`, or `IncludeFolderMask`/`ExcludeFolderMask`, on a `ConnectionType="Filter"`
|
|
112
|
+
connection). Switch Designer labels them "No/All/All other jobs" and "No/All folders" in that
|
|
113
|
+
context, not the XML token names above. See [Common practices](#common-practices) below for the
|
|
114
|
+
exact chain.
|
|
115
|
+
|
|
116
|
+
`next` and `current` exist in the editor grammar but have no confirmed script-facing use case — no
|
|
117
|
+
built-in Switch flow element declares a property using them, and Enfocus's own property-editor
|
|
118
|
+
documentation omits both (along with `allotherfolders`, apparently by oversight, since it's used the
|
|
119
|
+
same way as `allotherfiles`). Don't reach for `next`/`current` without confirming a concrete need
|
|
120
|
+
first.
|
|
121
|
+
|
|
92
122
|
---
|
|
93
123
|
|
|
94
124
|
## Extra XML attributes for certain editors
|
|
@@ -115,6 +145,17 @@ flow is exported.
|
|
|
115
145
|
The following are recommended conventions for pairing property kinds with editor chains, not
|
|
116
146
|
restrictions enforced by Switch — a script writer can combine editors differently if asked to.
|
|
117
147
|
|
|
148
|
+
Enable the dynamic editors (`sltextwithvar`/`mltextwithvar` and `conditionwithvar`, `scriptexp`)
|
|
149
|
+
wherever the value could plausibly vary per job — the rows below already reflect this. Conversely,
|
|
150
|
+
don't add them to a property whose value is inherently static (e.g. a dataset name, or anything a
|
|
151
|
+
`Dependency` master needs to read at flow-configuration time) — offering a variable/script option
|
|
152
|
+
there just invites a value the script can't sensibly use.
|
|
153
|
+
|
|
154
|
+
**App guideline (mandatory for apps, recommended for scripts):** make sure at least one editor in
|
|
155
|
+
the chain works without an add-on Switch module: `scriptexp` requires the Scripting Module, so never
|
|
156
|
+
offer it as the property's only editor — pair it with a module-free option (e.g. `inline` or
|
|
157
|
+
`sltextwithvar`) so the property still works for a user without that module.
|
|
158
|
+
|
|
118
159
|
| Property kind | Recommended `Editor` chain | Why |
|
|
119
160
|
|---|---|---|
|
|
120
161
|
| Secret (password, token, API key) | `password` only | Masks the value and avoids leaking it via logs or variable inspection if a var/expression editor were combined. |
|
|
@@ -125,7 +166,9 @@ restrictions enforced by Switch — a script writer can combine editors differen
|
|
|
125
166
|
| Boolean consumed directly by script logic (not a `Dependency` master) | `inline` + `conditionwithvar` + `scriptexp` | Safe to toggle dynamically since nothing else depends on it for visibility. Also covers booleans that are themselves a `Dependency` *dependent* (not a master). |
|
|
126
167
|
| Enum (`Type="enum:..."`) | `inline` only, always | No editor guarantees a var/expression result matches one of the declared items. |
|
|
127
168
|
| File/folder path that must exist for the app to work | `choosefile`/`choosefolder` only | Switch validates the picked path exists at flow start. |
|
|
128
|
-
| File/folder path that legitimately varies per job | `choosefile`/`choosefolder` + `sltextwithvar` + `scriptexp` | Dynamic values only resolve when read during `jobArrived` — see the "Workaround for deferred processing" note in [
|
|
169
|
+
| File/folder path that legitimately varies per job | `choosefile`/`choosefolder` + `sltextwithvar` + `scriptexp` | Dynamic values only resolve when read during `jobArrived` — see the "Workaround for deferred processing" note in [flow-element.md](../switch-api/flow-element.md#properties) if the path is needed later in the flow. |
|
|
170
|
+
| Connection include-mask filter (which jobs pass through) | `allfiles;allotherfiles;types;filepatterns;regexp;scriptexp`, `Default="All Files"`, `Subtype="allfiles"` | Matches Switch's own built-in connection filter properties exactly — `Default`/`Subtype` must hold the chosen literal's exact rendered string. Folder version: `allfolders;allotherfolders;folderpatterns;regexp;scriptexp` with `Default="All Folders"`, `Subtype="allfolders"`. |
|
|
171
|
+
| Connection exclude-mask filter (which jobs are blocked) | `nofiles;types;filepatterns;regexp;scriptexp`, `Default="No Files"`, `Subtype="nofiles"` | Same reasoning as the include mask, starting from `nofiles` instead since there's no "exclude all/all other" case. Folder version: `nofolders;folderpatterns;regexp;scriptexp` with `Default="No Folders"`, `Subtype="nofolders"`. |
|
|
129
172
|
|
|
130
173
|
`regexp`, `filetype`/`types`, `askplugin`/`askplugin2`, `oauth`, and `external` can technically be
|
|
131
174
|
combined with `sltextwithvar`/`scriptexp` too, but this is uncommon in practice and not covered by a
|
|
@@ -137,8 +180,12 @@ dedicated row above.
|
|
|
137
180
|
|
|
138
181
|
- **OAuth 2.0**: endpoint, client ID/secret, scope, and redirect ports are configured per-property
|
|
139
182
|
in a matching `<ExtraProperties>` child element (see
|
|
140
|
-
[
|
|
183
|
+
[script-declaration.md § ExtraProperties](script-declaration.md#extraproperties)), not in
|
|
141
184
|
`Editor`/`Type`. The script receives a ready-to-use access token string via
|
|
142
185
|
`getPropertyStringValue()`.
|
|
143
186
|
- **External editor**: requires a separate companion application. The script receives a file path to
|
|
144
187
|
the property set file. Entry point `findExternalEditorPath` resolves the editor executable path.
|
|
188
|
+
One of these two must be true — either a dependent property named `Application` (see
|
|
189
|
+
[Dependency](script-declaration.md#custom-property-elements-elementfields)) is non-empty, or
|
|
190
|
+
the script implements `findExternalEditorPath` — see
|
|
191
|
+
[entry-points.md](../switch-api/entry-points.md#property-ui-callbacks).
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: script-declaration
|
|
3
|
+
category: switch-project
|
|
4
|
+
order: 14
|
|
5
|
+
summary: "XML declaration reference: properties, connections, execution config; agents may edit this file directly"
|
|
6
|
+
triggers:
|
|
7
|
+
- "Understanding, adding, or editing script properties/connections/execution config"
|
|
8
|
+
---
|
|
9
|
+
|
|
1
10
|
# Script Declaration (XML)
|
|
2
11
|
|
|
3
12
|
The file `<ScriptID>.xml` defines the script's metadata, custom properties, connection properties,
|
|
@@ -13,8 +22,10 @@ documented below — you can edit it directly.
|
|
|
13
22
|
- `Name` is the script's stable ID — never change it on an existing script (it's used as the flow
|
|
14
23
|
element type and referenced by installed flows). `DisplayName`, tooltips, defaults, adding/removing
|
|
15
24
|
custom properties, and connection topology are all safe to change directly.
|
|
16
|
-
-
|
|
17
|
-
Switch
|
|
25
|
+
- `Version` identifies a released build, not an edit. Bump it only when the current value has
|
|
26
|
+
already been released (installed on a customer's or production Switch, or published on the
|
|
27
|
+
Appstore). If the current value was never released, keep editing under it; don't bump per
|
|
28
|
+
change. See the `Version` row below for format and what Switch does with it.
|
|
18
29
|
- Custom property tag names must match `^[A-Za-z][A-Za-z0-9]*$`, must not start with `xml`
|
|
19
30
|
(case-insensitive), and must not collide with a [reserved tag](#reserved-tag-names) below. Switch
|
|
20
31
|
does **not** sanitize or rewrite bad tag names on load — it just fails to work correctly.
|
|
@@ -54,11 +65,11 @@ value is non-string (see the table); an empty string field can omit `Type`.
|
|
|
54
65
|
|---|---|---|
|
|
55
66
|
| `Name` | string | Stable script ID — **never change on an existing script**. Becomes the flow element `Type`. |
|
|
56
67
|
| `DisplayName` | string | Shown in Switch. Empty falls back to `Name`. A `~` splits "Vendor~Element" — Switch shows the part after `~` as the short name and the whole string (space-joined) as the full name. |
|
|
57
|
-
| `Version` | number | Format `[1-9][0-9]*(\.(0\|[1-9][0-9]*))*`, e.g. `1`, `2.1`. Bump
|
|
68
|
+
| `Version` | number | Format `[1-9][0-9]*(\.(0\|[1-9][0-9]*))*`, e.g. `1`, `2.1`. SwitchScripter accepts a whole number only for a script and at most one minor level for an app (`2.1`); it resets anything else. Bump once per release, not per edit (see [Agent editing policy](#agent-editing-policy)). Each flow records the version of the element it uses; Switch compares that recorded value with `UpgradeMaximumVersion` to decide whether to show `FlowUpgradeWarning`. |
|
|
58
69
|
| `Keywords` | string | Space/comma/semicolon-separated. Elements pane search. |
|
|
59
70
|
| `Tooltip` | string | Elements pane tooltip. |
|
|
60
|
-
| `IncomingConnections` | `Yes` \| `No` | Add `RequireAtLeastOne="Yes"` when `Yes`. |
|
|
61
|
-
| `OutgoingConnections` | `No` \| `One` \| `Unlimited` | Add `RequireAtLeastOne="Yes"` when `One`/`Unlimited`. Always carries `DetailedInfo=""` (or a prose description of the connections, for generated docs). |
|
|
71
|
+
| `IncomingConnections` | `Yes` \| `No` | Add `RequireAtLeastOne="Yes"` when `Yes`. When `Yes`, the script must implement `jobArrived` (optionally `timerFired` too); when `No`, it must implement `timerFired` instead — see [entry-points.md](../switch-api/entry-points.md#job-processing). |
|
|
72
|
+
| `OutgoingConnections` | `No` \| `One` \| `Unlimited` | Add `RequireAtLeastOne="Yes"` when `One`/`Unlimited`. Always carries `DetailedInfo=""` (or a prose description of the connections, for generated docs). When not `No`, the script must call a `sendTo*()` method at least once for any job it actually routes (a purely timer/event-driven script that never touches a job — polling an API, rotating logs, etc. — is a legitimate exception); when `Unlimited`, never use `job.sendToSingle()` — see [job-patterns.md § Sending jobs](../switch-api/job-patterns.md#sending-jobs). |
|
|
62
73
|
| `ConnectionType` | `Move` \| `Filter` \| `TrafficLight` | Governs which `ConnectionFields` children are legal — see [ConnectionFields](#connectionfields). |
|
|
63
74
|
| `FunctionsNodeJSScript` | `;`-separated names | Entry point function names found in the script. Omit the element entirely if there is no Node.js program. |
|
|
64
75
|
| `ExecutionMode` | `Concurrent` \| `Serialized` | |
|
|
@@ -108,13 +119,13 @@ Key attributes:
|
|
|
108
119
|
|---|---|
|
|
109
120
|
| `UserDefined` | Always `"true"` for custom properties. |
|
|
110
121
|
| `Type` | Value type discriminator — see [Type reference](#type-reference). |
|
|
111
|
-
| `Editor` | `;`-joined chain of editor tokens (inline editor first, then modal editors) — see [
|
|
122
|
+
| `Editor` | `;`-joined chain of editor tokens (inline editor first, then modal editors) — see [property-editors.md](property-editors.md). |
|
|
112
123
|
| `Subtype` | Which editor in the `Editor` chain is currently active for the stored value. For a single-editor property this equals that editor's token (e.g. `"inline"`); for a bare modal editor with no inline component, leave it `""`. This attribute is read by Switch's validator at runtime, not just bookkeeping — keep it consistent with `Editor`. |
|
|
113
|
-
| `LocalizedTagName` | Display name shown in the Properties pane. |
|
|
114
|
-
| `Tooltip` | Tooltip shown in the Properties pane. |
|
|
124
|
+
| `LocalizedTagName` | Display name shown in the Properties pane. **App guideline (mandatory for apps, recommended for scripts):** 30 characters max, sentence-style capitalization (`"Customer name"`, not `"Customer Name"`). |
|
|
125
|
+
| `Tooltip` | Tooltip shown in the Properties pane. **App guideline (mandatory for apps, recommended for scripts):** give every property a tooltip. The only exception is a property that's fully self-explanatory from its name alone with no extra constraints (e.g. "Number of copies" with no min/max) — if there's anything a user would need to know (units, valid range, format, an example value), put it in the tooltip. |
|
|
115
126
|
| `DetailedInfo` | Long-form description for generated docs. Always include the attribute (empty string `""` is fine) — omitting it makes the property non-editable in Switch Designer. |
|
|
116
|
-
| `Validation` | `None` (skip validation) \| `Standard` (built-in validator) \| `Custom` (needs
|
|
117
|
-
| `Default` | Default value string. Omit only if the value is emitted as CDATA instead. |
|
|
127
|
+
| `Validation` | `None` (skip validation) \| `Standard` (built-in validator) \| `Custom` (needs a `validateProperties` entry point) \| `Standard and custom` (both, custom only runs if standard passes). If any property uses `Custom` or `Standard and custom`, the script must implement `validateProperties` (or `validateConnectionProperties` for a connection field) — see [entry-points.md](../switch-api/entry-points.md#property-ui-callbacks). To let a property hold an empty value under `Standard` validation, add the `none` literal editor to the `Editor` chain (see [property-editors.md § Literal editors](property-editors.md#literal-editors)) instead of relaxing to `Validation="None"` just to permit emptiness. |
|
|
128
|
+
| `Default` | Default value string. Omit only if the value is emitted as CDATA instead. **App guideline (mandatory for apps, recommended for scripts):** always provide a default unless there's genuinely no sensible one; if a default truly isn't possible, give an example value in the `Tooltip` instead. |
|
|
118
129
|
| `Dependency` | Tag of the master property this one depends on. Written flat (not nested) — the dependent element is a sibling of its master, not a child. |
|
|
119
130
|
| `DependencyCondition` | One of: `Not-empty`, `Equals`, `Not-equals`, `Contains`, `Does not contain`, `Matches`, `Does not match`, `Starts with`, `Does not start with`. |
|
|
120
131
|
| `Dependencyvalue` | Value(s) to compare against — `;`-separated for multiple. Note the lowercase `v`. |
|
|
@@ -131,6 +142,24 @@ Key attributes:
|
|
|
131
142
|
Validation="Standard" Default=""></OutputFolder>
|
|
132
143
|
```
|
|
133
144
|
|
|
145
|
+
**Runtime pitfall:** when a dependent property is hidden (its master's current value doesn't satisfy
|
|
146
|
+
`DependencyCondition`/`Dependencyvalue`), Switch treats the tag as if it doesn't exist. Calling
|
|
147
|
+
`flowElement.getPropertyStringValue(tag)` on it throws `"Invalid tag: <tag>"` — see
|
|
148
|
+
[flow-element.md](../switch-api/flow-element.md#properties). Only fetch a dependent property once you know
|
|
149
|
+
its condition holds, either by checking the already-read master value yourself, or by calling
|
|
150
|
+
`flowElement.hasProperty(tag)` first (it returns `false` for a hidden dependent). This matters most
|
|
151
|
+
for an enum/drop-down master with several dependents keyed off different values — fetch only the
|
|
152
|
+
ones actually shown for the current selection, not all of them.
|
|
153
|
+
|
|
154
|
+
A script must never assume the set of fetchable dependents is fixed once at flow configuration
|
|
155
|
+
time: if the master's own value is dynamic (a Switch variable or script expression, resolved per
|
|
156
|
+
job in `jobArrived`), which dependents are shown can differ from job to job in the same flow
|
|
157
|
+
execution. Re-check the condition (or call `hasProperty()`) on every invocation rather than caching
|
|
158
|
+
an earlier "shown" determination. There is no way to read a currently-hidden dependent's value for
|
|
159
|
+
a given job — if a script genuinely needs data from more than one dependency group at once (e.g.
|
|
160
|
+
values entered while the master previously pointed elsewhere), this pattern cannot provide it, and
|
|
161
|
+
a different property structure (not `Dependency`-based hiding) is needed instead.
|
|
162
|
+
|
|
134
163
|
Attribute order in the file doesn't matter functionally — SwitchScripter's own output happens to be
|
|
135
164
|
alphabetical (QDom sorts attributes on write), but any order parses correctly.
|
|
136
165
|
|
|
@@ -172,6 +201,11 @@ most important thing to get right when hand-editing this section:
|
|
|
172
201
|
|
|
173
202
|
Custom (author-defined) connection properties may be added regardless of `ConnectionType`.
|
|
174
203
|
|
|
204
|
+
The declared connections and the script's `sendTo*()` calls must agree with each other — see
|
|
205
|
+
[job-patterns.md § Sending jobs](../switch-api/job-patterns.md#sending-jobs) for the exact rules per
|
|
206
|
+
`ConnectionType`. In particular, omit a `Success`/`Warning`/`Error` element entirely (as shown
|
|
207
|
+
above) if the script never routes to it, rather than leaving an unused connection declared.
|
|
208
|
+
|
|
175
209
|
**Caution — package-swap connection preservation:** Switch Designer decides whether existing flow
|
|
176
210
|
connections survive a script package replace by comparing the serialised `ConnectionFields` and
|
|
177
211
|
`IncomingConnections` text **byte-for-byte** between old and new declarations, and additionally
|
|
@@ -184,7 +218,7 @@ properties to reset on next package update.
|
|
|
184
218
|
## ExtraProperties
|
|
185
219
|
|
|
186
220
|
Only used for OAuth 2.0 (`Editor` containing `oauth`, see
|
|
187
|
-
[
|
|
221
|
+
[property-editors.md](property-editors.md)). One child element per OAuth property, named
|
|
188
222
|
identically to the property's tag, in `ElementFields` or `ConnectionFields`:
|
|
189
223
|
|
|
190
224
|
```xml
|
|
@@ -236,7 +270,7 @@ If no OAuth property exists on the script, omit `ExtraProperties` entirely or le
|
|
|
236
270
|
|
|
237
271
|
This is the *authoring* vocabulary written into the XML `Type` attribute. It does not map one-to-one
|
|
238
272
|
onto the runtime `PropertyType` returned by `getPropertyType()` (see
|
|
239
|
-
[
|
|
273
|
+
[property-editors.md](property-editors.md) and [enums.md](../switch-api/enums.md)) — e.g. XML
|
|
240
274
|
`bool` becomes runtime `boolean`, XML `path` splits into runtime `filepath`/`folderpath`, and several
|
|
241
275
|
XML types (`rational`, `stringlist`, `accountlist`, `enum:...`, `datetime`, `time`) have no direct
|
|
242
276
|
`PropertyType` counterpart while several runtime values (`filetype`, `folderpattern`, `regex`,
|
|
@@ -244,7 +278,7 @@ XML types (`rational`, `stringlist`, `accountlist`, `enum:...`, `datetime`, `tim
|
|
|
244
278
|
interchangeable.
|
|
245
279
|
|
|
246
280
|
`Type` is not independently authored on properties with a modal editor chain — it follows from
|
|
247
|
-
which editor(s) you choose, per [
|
|
281
|
+
which editor(s) you choose, per [property-editors.md](property-editors.md). When combining
|
|
248
282
|
an inline editor with modal editors (e.g. `Editor="inline;sltextwithvar;scriptexp"`), the inline
|
|
249
283
|
editor's type wins: an inline Number editor plus those modal editors still yields `Type="number"`.
|
|
250
284
|
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: script-structure
|
|
3
|
+
category: switch-project
|
|
4
|
+
order: 10
|
|
5
|
+
summary: "What files a script folder contains, `manifest.xml` format, how `SwitchVersion` selects the Node.js version and which tools overwrite it, Script vs App"
|
|
6
|
+
triggers:
|
|
7
|
+
- "Setting up a new script project, converting a Script to an App, or working out which Node.js version a script or app will run on"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Script Project Structure
|
|
11
|
+
|
|
12
|
+
A Switch script project lives in a **script folder** during development and is distributed as a `.sscript` package (ZIP).
|
|
13
|
+
|
|
14
|
+
> **Agent editing policy**: Edit TypeScript/JavaScript source files (`main.ts`, `main.js`) and the XML declaration (`<ScriptID>.xml`) freely — see [script-declaration.md](script-declaration.md) for the declaration's rules, and [entry-points.md § Entry-point scanner constraints](../switch-api/entry-points.md#entry-point-scanner-constraints) before writing any string/regex literal or division, since certain shapes make Switch's entry-point scanner silently drop functions. Leave `manifest.xml` to the user unless explicitly asked.
|
|
15
|
+
|
|
16
|
+
## Script folder files
|
|
17
|
+
|
|
18
|
+
| File | Required | Notes |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| `manifest.xml` | Yes | Switch internal use only. Do not edit manually. |
|
|
21
|
+
| `<ScriptID>.xml` | Yes | Script declaration (properties, connections, execution config). See [script-declaration.md](script-declaration.md). |
|
|
22
|
+
| `main.ts` | Yes (TypeScript) | Source file. Edit this. |
|
|
23
|
+
| `main.js` | Yes | Compiled output executed by Switch. Generated by transpiling `main.ts`. |
|
|
24
|
+
| `main.js.map` | No | Source map, generated alongside `main.js`. |
|
|
25
|
+
| `package.json` | Yes (TypeScript) | NPM config for type declarations. |
|
|
26
|
+
| `tsconfig.json` | Yes (TypeScript) | TypeScript transpilation options. |
|
|
27
|
+
| `<IconFileName>.png` | No | 32×32 px, RGB, not interlaced. Extension must be `.png`. |
|
|
28
|
+
| `node_modules/` | No | Local npm packages. |
|
|
29
|
+
| `Resources/` | No | Extra resource files bundled when packing with SwitchScriptTool. Never bundle an Oracle Java Runtime Environment here — licensing terms don't permit redistributing it, in a script or an app. |
|
|
30
|
+
| `<LanguageCode>.ts` | No | Translation files (Switch App SDK). |
|
|
31
|
+
| `.vscode/launch.json` | No | Debug config (created by SwitchScriptTool). |
|
|
32
|
+
| `.vscode/switch.code-snippets` | No | Entry point snippets (TypeScript only). |
|
|
33
|
+
|
|
34
|
+
> After editing `main.ts`, transpile with SwitchScriptTool to regenerate `main.js` before testing in Switch.
|
|
35
|
+
|
|
36
|
+
## manifest.xml format
|
|
37
|
+
|
|
38
|
+
```xml
|
|
39
|
+
<Manifest>
|
|
40
|
+
<ScripterInstanceName>myScript</ScripterInstanceName>
|
|
41
|
+
<SwitchVersion>24.0</SwitchVersion>
|
|
42
|
+
<ScriptPackageFormatVersion>1.0</ScriptPackageFormatVersion>
|
|
43
|
+
<ScriptPasswordProtected>No</ScriptPasswordProtected>
|
|
44
|
+
<ScriptPackageType>Script</ScriptPackageType>
|
|
45
|
+
<ScriptDeclarationFile>myScript.xml</ScriptDeclarationFile>
|
|
46
|
+
<ScriptProgramFiles>
|
|
47
|
+
<ScriptProgramFile ScriptLanguage="NodeJSScript">main.ts</ScriptProgramFile>
|
|
48
|
+
</ScriptProgramFiles>
|
|
49
|
+
<ScriptIconFile>myScript_32.png</ScriptIconFile>
|
|
50
|
+
<LocalizationItems/>
|
|
51
|
+
</Manifest>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`ScriptPackageType` is either `Script` (regular) or `App` (scripted plug-in).
|
|
55
|
+
|
|
56
|
+
## Node.js version per Switch version
|
|
57
|
+
|
|
58
|
+
The Switch Server running the script picks its Node.js version by looking up `SwitchVersion` from
|
|
59
|
+
`manifest.xml` in a fixed table that ships with each Switch release:
|
|
60
|
+
|
|
61
|
+
| Switch version | `SwitchVersion` | Node.js used |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| Switch 2020 Spring | `20.0` | 12 |
|
|
64
|
+
| Switch 2020 Fall | `20.1` | 12 |
|
|
65
|
+
| Switch 2021 Spring | `21.0` | 14 |
|
|
66
|
+
| Switch 2021 Fall | `21.1` | 16 |
|
|
67
|
+
| Switch 2022 Spring | `22.0` | 16 |
|
|
68
|
+
| Switch 2022 Fall | `22.1` | 16 |
|
|
69
|
+
| Switch 2023 Fall | `23.1` | 18 |
|
|
70
|
+
| Switch 2024 Spring | `24.0` | 18 |
|
|
71
|
+
| Switch 2024 Fall | `24.1` | 20 |
|
|
72
|
+
| Switch 25.07 | `25.07` | 20 |
|
|
73
|
+
| Switch 25.11 | `25.11` | 20 |
|
|
74
|
+
| Switch 26.03 | `26.03` | 24 |
|
|
75
|
+
| Switch 26.07 | `26.07` | 24 |
|
|
76
|
+
|
|
77
|
+
Switch 26.07 bundles Node.js 12.22.12, 14.21.3, 16.20.2, 18.20.8, 20.20.0, and 24.13.0.
|
|
78
|
+
|
|
79
|
+
`SwitchVersion` controls the Node.js version only. Which scripting API methods exist depends on the
|
|
80
|
+
Switch version the script runs on, see [api-versions.md](../switch-api/api-versions.md).
|
|
81
|
+
|
|
82
|
+
### What writes `SwitchVersion`
|
|
83
|
+
|
|
84
|
+
`SwitchVersion` is the version of whichever tool last wrote the manifest. It is not a setting the
|
|
85
|
+
author picks:
|
|
86
|
+
|
|
87
|
+
- `SwitchScriptTool --create` writes the tool's own version into the new script folder.
|
|
88
|
+
- `SwitchScriptTool --pack` writes the tool's own version into the packed `.sscript`, whatever the
|
|
89
|
+
script folder's manifest says. The script folder's manifest itself is left unchanged. Verified
|
|
90
|
+
with SwitchScriptTool 26.07: a folder whose manifest said `21.0` packed to a `.sscript` whose
|
|
91
|
+
manifest says `26.07`, which moves the script from Node.js 16 to Node.js 24.
|
|
92
|
+
- SwitchScripter writes its own version on every save. Opening a script with a different
|
|
93
|
+
`SwitchVersion` shows a warning that saving updates the script to the current Node.js version.
|
|
94
|
+
|
|
95
|
+
**Gotcha:** a script folder tested directly in Switch and the `.sscript` packed from it can run on
|
|
96
|
+
different Node.js versions. A folder created with an older SwitchScriptTool keeps that tool's
|
|
97
|
+
version, but packing it with a newer SwitchScriptTool stamps the newer one. Test the packed
|
|
98
|
+
`.sscript`, not only the folder, before shipping it.
|
|
99
|
+
|
|
100
|
+
To target an older Node.js version, build the package with the SwitchScriptTool or SwitchScripter
|
|
101
|
+
of that Switch release. Editing `SwitchVersion` by hand doesn't last, because `--pack` and
|
|
102
|
+
SwitchScripter overwrite it.
|
|
103
|
+
|
|
104
|
+
### Values missing from the table
|
|
105
|
+
|
|
106
|
+
Behavior of the Switch 26.07 Server:
|
|
107
|
+
|
|
108
|
+
- No `SwitchVersion` element: treated as `20.1`, so Node.js 12.
|
|
109
|
+
- Lower than the first entry: Node.js 12.
|
|
110
|
+
- Higher than the last entry, for example a package built by a newer tool than the Switch it runs
|
|
111
|
+
on: the newest Node.js that Switch bundles. The Server logs a debug message that the script
|
|
112
|
+
"might not be compatible with the current Switch version" and runs it anyway.
|
|
113
|
+
- **Known issue:** a value that isn't an exact entry but falls numerically between the first and
|
|
114
|
+
last entries matches no Node.js version, for example `25.7` instead of `25.07`, `24.10` instead of
|
|
115
|
+
`24.1`, or `23.0`. The Server then fails to build the path to a Node.js binary, so no executor
|
|
116
|
+
process starts for the script. This was confirmed by running the Switch 26.07 lookup code with
|
|
117
|
+
these values, not by running such a script in Switch, so the exact symptom in Switch hasn't been
|
|
118
|
+
checked. A value such as `26.3` works today only because it's higher than the last entry, and it
|
|
119
|
+
will break once a later release adds an entry above it. Never hand-edit `SwitchVersion`. If you
|
|
120
|
+
must, copy a value exactly as the table above spells it.
|
|
121
|
+
|
|
122
|
+
### Other effects of `SwitchVersion`
|
|
123
|
+
|
|
124
|
+
- npm dependencies that are ES modules are bundled with esbuild before execution only when
|
|
125
|
+
`SwitchVersion` is `24.0` or higher.
|
|
126
|
+
- A script expression has no manifest. It always runs on the newest Node.js the running Switch
|
|
127
|
+
bundles.
|
|
128
|
+
|
|
129
|
+
> **Mac (Apple Silicon):** For scripts whose `SwitchVersion` is `21.1` (Switch 2021 Fall) or later, Switch runs the native ARM build of Node.js on Apple Silicon. Scripts with an earlier `SwitchVersion` run under Rosetta, because the bundled Node.js 12 and 14 are Intel-only builds. If a script bundles platform-specific binaries, ship both Intel and ARM variants.
|
|
130
|
+
|
|
131
|
+
## Script vs App
|
|
132
|
+
|
|
133
|
+
| | Script | App |
|
|
134
|
+
|---|---|---|
|
|
135
|
+
| `ScriptPackageType` | `Script` | `App` |
|
|
136
|
+
| Appears in Elements pane | No (used via Script element) | Yes, as its own element |
|
|
137
|
+
| Distribution | Freely | Enfocus Appstore only |
|
|
138
|
+
| Position in pane | — | Configured via `PositionInElementPane` in XML |
|
|
139
|
+
|
|
140
|
+
## Packing an app
|
|
141
|
+
|
|
142
|
+
An app is produced by SwitchScripter, not by SwitchScriptTool, and the two workflows have to be
|
|
143
|
+
joined up explicitly:
|
|
144
|
+
|
|
145
|
+
- **A script folder can only be typed `Script`.** To ship one as an app, pack it with
|
|
146
|
+
`SwitchScriptTool --pack` first, then open the resulting package in SwitchScripter and change the
|
|
147
|
+
type to `App` before creating the `.enfpack`. If "Create pack" is greyed out, the type is still
|
|
148
|
+
`Script`.
|
|
149
|
+
- **Extra files can't be managed while SwitchScripter is working with a script folder.** Convert to
|
|
150
|
+
a script package first. The conversion is reversible, so the `.pdesc` holding the extra-files
|
|
151
|
+
configuration can be round-tripped back into the script folder and kept in version control.
|
|
152
|
+
- **Creating a pack does not save the script.** Save first, or the pack is built from the last
|
|
153
|
+
saved state.
|
|
154
|
+
- **The pack ID is derived from the script ID and always starts with `com.enfocus.`**, whatever the
|
|
155
|
+
company name and domain in SwitchScripter preferences. To keep it stable across an update, open
|
|
156
|
+
the previous `.enfpack` rather than the `.sscript` — SwitchScripter carries the pack ID over from
|
|
157
|
+
the pack it opened, even if the script ID or domain has since changed.
|
|
158
|
+
|
|
159
|
+
### SwitchScripter and Switch version compatibility
|
|
160
|
+
|
|
161
|
+
An app loads in the Switch version it was built with **or newer**, never older. So the SwitchScripter
|
|
162
|
+
used must be at or below the oldest Switch version you intend to support, and portable
|
|
163
|
+
SwitchScripters exist for older releases specifically to build backwards-compatible apps. There is
|
|
164
|
+
no SwitchScripter for Switch 25.07 or 25.11 — use the Switch 2024 Fall SwitchScripter for those.
|
|
165
|
+
Apps as a concept require Switch 13.1 or later.
|
|
166
|
+
|
|
167
|
+
The SwitchScripter version also fixes the app's Node.js version, see
|
|
168
|
+
[Node.js version per Switch version](#nodejs-version-per-switch-version). An app built with the
|
|
169
|
+
Switch 2024 Fall SwitchScripter has `SwitchVersion` `24.1`, so it runs on Node.js 20 in every Switch
|
|
170
|
+
version that loads it, including 26.x. Switch 26.07 ships SwitchScripter 26.07. An app built with
|
|
171
|
+
it runs on Node.js 24, and it loads only in Switch 26.07 or newer.
|
|
172
|
+
|
|
173
|
+
An unsigned app loads only in Switch on the machine that created it. That's what allows local
|
|
174
|
+
testing before submission; it loads elsewhere only once Enfocus has signed it.
|
|
175
|
+
|
|
176
|
+
## App Store submission guidelines
|
|
177
|
+
|
|
178
|
+
App-specific submission rules (localization, universal/signed macOS binaries, immutable extra
|
|
179
|
+
files) live in [app-guidelines.md § App-only](../switch-appstore/app-guidelines.md#app-only), alongside the
|
|
180
|
+
rest of the pre-publish checklist.
|
|
181
|
+
|
|
182
|
+
## Execution modes
|
|
183
|
+
|
|
184
|
+
`Concurrent`/`Serialized`, `ExecutionGroup` and `NumberOfSlots` are set in the XML declaration (see
|
|
185
|
+
[script-declaration.md](script-declaration.md#built-in-elementfields) for the attributes)
|
|
186
|
+
and documented in
|
|
187
|
+
[execution-environment.md § Execution modes](../switch-api/execution-environment.md#execution-modes),
|
|
188
|
+
which also explains why none of them maps to a count of Node.js processes.
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: tooling
|
|
3
|
+
category: switch-project
|
|
4
|
+
order: 11
|
|
5
|
+
summary: "SwitchScriptTool commands and install paths, folder vs `.sscript` trade-offs, deployment"
|
|
6
|
+
triggers:
|
|
7
|
+
- "Running SwitchScriptTool: transpiling, packing, unpacking, or deploying"
|
|
8
|
+
---
|
|
9
|
+
|
|
1
10
|
# Script Folders, Packages & SwitchScriptTool
|
|
2
11
|
|
|
3
12
|
## Script folder vs script package
|
|
@@ -36,10 +45,87 @@ location for the current OS if the bare command isn't found.
|
|
|
36
45
|
|
|
37
46
|
**Transpile** is required after every edit to `main.ts` before testing a **script folder** directly in Switch. Switch executes `main.js` only — `main.ts` is never run directly. Using SwitchScriptTool (not `tsc`) ensures the same transpile options as SwitchScripter, which is required for consistent behavior. This step is **not** needed before packing — see Pack below.
|
|
38
47
|
|
|
39
|
-
**Pack** transpiles `main.ts` fresh into the package on every run; it never reads or modifies any `main.js` already sitting in the source folder (a stale hand-edited `main.js` there is ignored and left untouched — see the excluded-files note below). It always excludes `package.json` and `.vscode/` from the packed output, printed as an "Info: will not be packed" list even without `--verbose`; `--verbose` additionally prints the full list of what *will* be packed. `node_modules` is packed as-is, so run `npm prune --production` first (see Deployment) — otherwise `devDependencies` (including `@types/*` packages, which the scaffolded `package.json` puts there) get bundled into the package for no runtime benefit. One harmless quirk: the placeholder `<ScriptID>.sscript` file scaffolded by `--create` is not excluded and ends up packed inside the real `.sscript` too.
|
|
48
|
+
**Pack** transpiles `main.ts` fresh into the package on every run; it never reads or modifies any `main.js` already sitting in the source folder (a stale hand-edited `main.js` there is ignored and left untouched — see the excluded-files note below). It always excludes `package.json` and `.vscode/` from the packed output, printed as an "Info: will not be packed" list even without `--verbose`; `--verbose` additionally prints the full list of what *will* be packed. `node_modules` is packed as-is, so run `npm prune --production` first (see Deployment) — otherwise `devDependencies` (including `@types/*` packages, which the scaffolded `package.json` puts there) get bundled into the package for no runtime benefit. One harmless quirk: the placeholder `<ScriptID>.sscript` file scaffolded by `--create` is not excluded and ends up packed inside the real `.sscript` too. Pack also replaces `SwitchVersion` in the packed `manifest.xml` with SwitchScriptTool's own version (`--create` writes it too), and that value picks the Node.js version the package runs on. See [script-structure.md § What writes `SwitchVersion`](script-structure.md#what-writes-switchversion).
|
|
40
49
|
|
|
41
50
|
**Unpack** prints package metadata (`Type`, `Protection`, `Status`) before extracting. For a TypeScript-sourced package it extracts only `main.ts` — the compiled `main.js`/`main.js.map` are not written back out, so a pack → unpack round trip returns a clean, editable script folder rather than a compiled snapshot.
|
|
42
51
|
|
|
52
|
+
## Verify entry points before packing
|
|
53
|
+
|
|
54
|
+
Switch's entry-point scanner is regex-based, not a real parser, and can silently drop entry-point
|
|
55
|
+
functions from certain string/regex/division shapes — see
|
|
56
|
+
[entry-points.md § Entry-point scanner constraints](../switch-api/entry-points.md#entry-point-scanner-constraints).
|
|
57
|
+
`--pack` does not validate or warn about this: a script that packs cleanly can still fail to load,
|
|
58
|
+
or load with a property callback that silently never runs. Compiling and passing tests doesn't
|
|
59
|
+
catch it either, since the source is syntactically valid JS/TS — only extraction against the built
|
|
60
|
+
`main.js` does.
|
|
61
|
+
|
|
62
|
+
After any edit to `main.ts`/`main.js`, run the extracted entry points against the **built**
|
|
63
|
+
`main.js` and confirm the expected names come back. Python:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
#!/usr/bin/env python3
|
|
67
|
+
import re, sys
|
|
68
|
+
|
|
69
|
+
STRIP_PATTERN = re.compile(
|
|
70
|
+
r'(?:/\*.*?\*/)'
|
|
71
|
+
r'|(?:(["\'`])\1)'
|
|
72
|
+
r'|(?://.*?$)'
|
|
73
|
+
r'|(?:([/"\'`]).*?[^\\]\2)'
|
|
74
|
+
r'|(?:/(?:\\.|[^/\n])*/)'
|
|
75
|
+
r'|(?:\(\s*\w+\s*/\s*\w+\s*\))'
|
|
76
|
+
r'|(?:\w+\s*/\s*\w+)',
|
|
77
|
+
re.DOTALL | re.MULTILINE,
|
|
78
|
+
)
|
|
79
|
+
FUNC_PATTERN = re.compile(r'function[\s\n\r]+(\$?\w+)[\s\n\r]*\(', re.MULTILINE)
|
|
80
|
+
NODE_ENTRY_POINTS = {
|
|
81
|
+
'timerFired', 'jobArrived', 'getLibraryForProperty', 'getLibraryForConnectionProperty',
|
|
82
|
+
'findExternalEditorPath', 'validateProperties', 'validateConnectionProperties',
|
|
83
|
+
'httpRequestTriggeredSync', 'httpRequestTriggeredAsync', 'flowStopTriggered',
|
|
84
|
+
'flowStartTriggered', 'abort',
|
|
85
|
+
}
|
|
86
|
+
REQUIRED_ANY = {'jobArrived', 'timerFired', 'flowStopTriggered', 'httpRequestTriggeredAsync'}
|
|
87
|
+
|
|
88
|
+
code = open(sys.argv[1], encoding='utf-8').read()
|
|
89
|
+
stripped = STRIP_PATTERN.sub('', code)
|
|
90
|
+
found = [m.group(1) for m in FUNC_PATTERN.finditer(stripped) if m.group(1) in NODE_ENTRY_POINTS]
|
|
91
|
+
print('Entry points found:', found or '(none)')
|
|
92
|
+
if not (REQUIRED_ANY & set(found)):
|
|
93
|
+
sys.exit('FAIL: none of ' + str(sorted(REQUIRED_ANY)) + ' survived extraction.')
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Or Node.js:
|
|
97
|
+
|
|
98
|
+
```js
|
|
99
|
+
#!/usr/bin/env node
|
|
100
|
+
const fs = require('fs');
|
|
101
|
+
|
|
102
|
+
const STRIP_PATTERN = /(?:\/\*[\s\S]*?\*\/)|(?:(["'`])\1)|(?:\/\/.*?$)|(?:([/"'`])[\s\S]*?[^\\]\2)|(?:\/(?:\\.|[^/\n])*\/)|(?:\(\s*\w+\s*\/\s*\w+\s*\))|(?:\w+\s*\/\s*\w+)/gm;
|
|
103
|
+
const FUNC_PATTERN = /function[\s\n\r]+(\$?\w+)[\s\n\r]*\(/gm;
|
|
104
|
+
const NODE_ENTRY_POINTS = new Set([
|
|
105
|
+
'timerFired', 'jobArrived', 'getLibraryForProperty', 'getLibraryForConnectionProperty',
|
|
106
|
+
'findExternalEditorPath', 'validateProperties', 'validateConnectionProperties',
|
|
107
|
+
'httpRequestTriggeredSync', 'httpRequestTriggeredAsync', 'flowStopTriggered',
|
|
108
|
+
'flowStartTriggered', 'abort',
|
|
109
|
+
]);
|
|
110
|
+
const REQUIRED_ANY = ['jobArrived', 'timerFired', 'flowStopTriggered', 'httpRequestTriggeredAsync'];
|
|
111
|
+
|
|
112
|
+
const stripped = fs.readFileSync(process.argv[2], 'utf8').replace(STRIP_PATTERN, '');
|
|
113
|
+
const found = [];
|
|
114
|
+
let m;
|
|
115
|
+
while ((m = FUNC_PATTERN.exec(stripped)) !== null) {
|
|
116
|
+
if (NODE_ENTRY_POINTS.has(m[1])) found.push(m[1]);
|
|
117
|
+
}
|
|
118
|
+
console.log('Entry points found:', found.length ? found : '(none)');
|
|
119
|
+
if (!found.some((f) => REQUIRED_ANY.includes(f))) {
|
|
120
|
+
console.error('FAIL: none of', REQUIRED_ANY, 'survived extraction.');
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
If the required entry point is missing, dump `stripped`/the stripped output and diff it against
|
|
126
|
+
`main.js` — the first swallowed region starts at the string, regex, or division literal identified
|
|
127
|
+
in the rules above.
|
|
128
|
+
|
|
43
129
|
## Deployment
|
|
44
130
|
|
|
45
131
|
Before packing, remove dev dependencies to reduce package size — this matters because `--pack` bundles `node_modules` as-is, and the scaffolded `package.json` puts type-only packages (`@types/node`, `@types/switch-scripting`, `undici-types`) under `devDependencies`:
|