@aryacode/dsh-engineering 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/README.md +4 -3
- package/package.json +10 -11
- package/vendor/l5x/SKILL.md +27 -7
- package/vendor/l5x/lib/engine/change-set.d.ts +9 -1
- package/vendor/l5x/lib/engine/change-set.js +32 -7
- package/vendor/l5x/lib/engine/documentation.d.ts +58 -0
- package/vendor/l5x/lib/engine/documentation.js +237 -0
- package/vendor/l5x/lib/engine/instructions.d.ts +50 -0
- package/vendor/l5x/lib/engine/instructions.js +107 -0
- package/vendor/l5x/lib/engine/ladder.d.ts +74 -0
- package/vendor/l5x/lib/engine/ladder.js +209 -0
- package/vendor/l5x/lib/index.d.ts +1 -0
- package/vendor/l5x/lib/index.js +3 -1
- package/vendor/l5x/lib/model/routines.js +6 -1
- package/vendor/l5x/lib/session.d.ts +20 -0
- package/vendor/l5x/lib/session.js +36 -0
- package/vendor/l5x/lib/tools/document.d.ts +18 -0
- package/vendor/l5x/lib/tools/document.js +119 -0
- package/vendor/l5x/lib/tools/drafts.js +109 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.0] - 2026-10-27
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Ladder generation that cannot emit invalid NeutralText.** Three pieces:
|
|
8
|
+
- `list_instructions` — the instruction catalog the composer validates: mnemonic, category, summary
|
|
9
|
+
and operand slots with their kinds (BOOL, NUMBER, TIMER, …), filterable. 41 instructions, covering
|
|
10
|
+
every mnemonic the Laminator project uses (45 distinct across 860 rungs).
|
|
11
|
+
- `compose_rung` — builds one rung from a structure tree (`spec_json`) or a named pattern
|
|
12
|
+
(`start_stop_latch`, `fault_latch`, `ton_delay`, `interlock`), resolves every operand against the
|
|
13
|
+
export (including unqualified program tags and aliases), type-checks each slot, emits the export's
|
|
14
|
+
own bracket style, and re-parses its output with the same parser `draft_rung` uses. Unknown
|
|
15
|
+
instructions name the nearest catalog entries; a wrong operand count, a non-BOOL contact, a
|
|
16
|
+
non-numeric value slot, an undeclared tag or an undeclared AOI is refused before anything is staged.
|
|
17
|
+
Passing `program`, `routine`, `mode` and `rung` stages the rung in the draft; `fault_latch` stages
|
|
18
|
+
its two rungs consecutively.
|
|
19
|
+
- **Rung comments are read and written.** The model read the `Comment` **attribute** only, so a real
|
|
20
|
+
Studio export's 572 child `<Comment>` elements were invisible. `decodeRung` now supports both shapes,
|
|
21
|
+
`draft_rung` accepts a `comment`, and `draft_rung_comment` sets or clears one on an existing rung.
|
|
22
|
+
CDATA terminators in a comment round-trip through the existing escaping.
|
|
23
|
+
- **Documentation dimension.** `document_project` writes a handover bundle into a NEW folder and never
|
|
24
|
+
touches the export: `PROJECT.md` (controller, revision, tasks, programs, counts), `io.md`/`io.csv`,
|
|
25
|
+
`tags.csv` and `tags-studio.csv` (the `Tag Name,Description` shape Studio's Tags and Comments import
|
|
26
|
+
expects), and `rungs/<program>.md` with each rung's number, comment, NeutralText, instructions and
|
|
27
|
+
resolved tags. Filters: `include`, `programs`, `routines`, `rungs_per_file`.
|
|
28
|
+
|
|
29
|
+
### Documentation
|
|
30
|
+
|
|
31
|
+
- `packages/l5x/SKILL.md`: a Generate section (catalog → compose → validate → apply) and a
|
|
32
|
+
Documentation section (bundle contents, the comment round trip, what the bundle cannot prove).
|
|
33
|
+
- README: 89 tools, L5X 44, and the 0.7.0 milestone.
|
|
34
|
+
|
|
3
35
|
## [0.6.0] - 2026-10-27
|
|
4
36
|
|
|
5
37
|
### Added
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
MotionWorks IEC and FactoryTalk Optix sit behind a single install, one row per surface. A row is the
|
|
5
5
|
switch: disable it and that plugin unloads, so its tool schemas leave the request.
|
|
6
6
|
|
|
7
|
-
`@aryacode/dsh-engineering` ·
|
|
7
|
+
`@aryacode/dsh-engineering` · 89 tools · 5 rows · 4 products · MIT
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -36,14 +36,14 @@ bundle.
|
|
|
36
36
|
|
|
37
37
|
| Product | Tools | Default | Needs |
|
|
38
38
|
|---|---|---|---|
|
|
39
|
-
| **Studio 5000 L5X** |
|
|
39
|
+
| **Studio 5000 L5X** | 44 | all on | Node for offline reads; Studio 5000 + Logix Designer SDK for SDK work; a controller for live |
|
|
40
40
|
| **FactoryTalk View ME** | 14 | all on | Node for an export folder; FactoryTalk View Studio ME for discovery and the handoff |
|
|
41
41
|
| **MotionWorks IEC** | 24 | all on | MotionWorks IEC 3 Pro installed; verified against 1.19 |
|
|
42
42
|
| **FactoryTalk Optix** | 10 (3 need preview) | all on | Optix Studio installed; Tesseract for OCR |
|
|
43
43
|
|
|
44
44
|
Tool groups, by product:
|
|
45
45
|
|
|
46
|
-
- **L5X** —
|
|
46
|
+
- **L5X** — 13 read (`open_project` … `document_project`), 11 staged drafts (`draft_*`, `compose_rung`), 6 Logix
|
|
47
47
|
Designer SDK, 7 supervised controller, 7 live EtherNet/IP (2 reads, 2 identity/discovery, 1 batch read, 2 approval-gated writes)
|
|
48
48
|
- **FactoryTalk View** — 6 read, 5 staged edits, 3 Studio handoff
|
|
49
49
|
- **MotionWorks IEC** — 7 session, 7 saved-project reads, 3 verify, 7 direct edits
|
|
@@ -120,6 +120,7 @@ the lean profile is the one that turns them off.
|
|
|
120
120
|
|
|
121
121
|
| Version | What landed |
|
|
122
122
|
|---|---|
|
|
123
|
+
| **0.7.0** | Ladder generation that cannot emit invalid NeutralText: an instruction catalog, a pattern/tree composer that resolves and type-checks every operand, rung comments read and written, and a documentation bundle (`document_project`) with the Studio tags-and-comments CSV |
|
|
123
124
|
| **0.5.0** | Commissioned on real files: FactoryTalk View reads genuine Studio exports (`<gfx>` displays, comma CSVs, UTF-16) instead of reporting zero; L5X alias resolution cuts 315 false "unresolved reference" findings to 16 on a 1279-tag project; `add_tag` no longer demands a value; a locked ACD exports from a copy |
|
|
124
125
|
| **0.4.17** | MotionWorks edits the real project again: the pre-edit backup is written where the bridge and engine verify it, an already-open project is attached instead of reloaded, and `mw_get` returns the body hash the edit takes |
|
|
125
126
|
| **0.4.15** | Every tool surface ships on by default; the row Configure pages switch them off |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aryacode/dsh-engineering",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "AryaCode engineering bundle: one install surface for the Studio 5000 L5X, FactoryTalk View ME, MotionWorks IEC and FactoryTalk Optix surfaces, one row per product, with the ladder and display previews.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|
|
@@ -55,15 +55,6 @@
|
|
|
55
55
|
]
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
|
-
"scripts": {
|
|
59
|
-
"test": "node --import tsx --test test/patch.spec.mjs test/docs.spec.mjs test/tool-reference.spec.mjs test/manifests.spec.mjs test/client-face.spec.mjs test/config.spec.mjs test/netlogic.spec.mjs",
|
|
60
|
-
"docs:tools": "tsx scripts/gen-tool-reference.ts",
|
|
61
|
-
"docs:check": "tsx scripts/gen-tool-reference.ts --check",
|
|
62
|
-
"netlogic:sync": "node scripts/sync-netlogic.mjs",
|
|
63
|
-
"build:client": "node scripts/build-client.mjs",
|
|
64
|
-
"assemble": "node scripts/assemble.mjs",
|
|
65
|
-
"prepack": "node scripts/build-client.mjs && node scripts/assemble.mjs"
|
|
66
|
-
},
|
|
67
58
|
"dependencies": {
|
|
68
59
|
"fast-xml-parser": "5.11.1",
|
|
69
60
|
"fast-xml-validator": "1.4.2",
|
|
@@ -103,5 +94,13 @@
|
|
|
103
94
|
"./mwi/skill": "./vendor/mwi/lib/skill.js",
|
|
104
95
|
"./mwi/verify": "./vendor/mwi/lib/verify.js",
|
|
105
96
|
"./mwi/edit": "./vendor/mwi/lib/edit.js"
|
|
97
|
+
},
|
|
98
|
+
"scripts": {
|
|
99
|
+
"test": "node --import tsx --test test/patch.spec.mjs test/docs.spec.mjs test/tool-reference.spec.mjs test/manifests.spec.mjs test/client-face.spec.mjs test/config.spec.mjs test/netlogic.spec.mjs",
|
|
100
|
+
"docs:tools": "tsx scripts/gen-tool-reference.ts",
|
|
101
|
+
"docs:check": "tsx scripts/gen-tool-reference.ts --check",
|
|
102
|
+
"netlogic:sync": "node scripts/sync-netlogic.mjs",
|
|
103
|
+
"build:client": "node scripts/build-client.mjs",
|
|
104
|
+
"assemble": "node scripts/assemble.mjs"
|
|
106
105
|
}
|
|
107
|
-
}
|
|
106
|
+
}
|
package/vendor/l5x/SKILL.md
CHANGED
|
@@ -56,12 +56,12 @@ this is a backup on request ("back up this project"). Build it as a copy plus
|
|
|
56
56
|
|
|
57
57
|
## Live reads
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
`l5x-live` reads declared scalar tags over EtherNet/IP with no Studio, FactoryTalk Linx or SDK. If `poll_live_tags` is unavailable, say live reads are not enabled here.
|
|
60
60
|
|
|
61
|
-
- `poll_live_tags` takes an explicit IPv4 address, a CPU slot and 1 to 16 declared
|
|
61
|
+
- `poll_live_tags` takes an explicit IPv4 address, a CPU slot and 1 to 16 declared scalars, and returns timestamped sweeps, quality and controller identity.
|
|
62
62
|
- `start_plc_trend` samples the same way as a session-owned job the chart can follow; stop it through the job controls.
|
|
63
63
|
- These are read-only. Never write controller data, force tags, toggle bits or edit online.
|
|
64
|
-
- Report `live_logic_matches_export: "unverified"`:
|
|
64
|
+
- Report `live_logic_matches_export: "unverified"`: a read proves a value at a moment, not that the controller runs the export.
|
|
65
65
|
|
|
66
66
|
## Reporting
|
|
67
67
|
|
|
@@ -81,18 +81,38 @@ The `l5x-live` entry reads declared scalar tags straight from a controller over
|
|
|
81
81
|
The `l5x-studio` entry adds offline SDK work; it may be disabled. Call `studio_sdk_status` before using it.
|
|
82
82
|
|
|
83
83
|
- `export_acd_to_l5x` writes one new full L5X from an ACD. No controller contact.
|
|
84
|
-
- `verify_offline_l5x` imports a full L5X into a new offline ACD and builds it. Build needs project revision 37
|
|
85
|
-
- `build_acd_from_draft` imports one changed RLL or ST routine into a new ACD copy, builds
|
|
84
|
+
- `verify_offline_l5x` imports a full L5X into a new offline ACD and builds it. Build needs project revision 37+; `probe: true` tries a lower one and reports the SDK error. An L5X from `export_acd_to_l5x` may be refused as "no changes".
|
|
85
|
+
- `build_acd_from_draft` imports one changed RLL or ST routine into a new ACD copy, builds and exports it. The baseline must be an L5X exported from that ACD in this chat; neither file may change.
|
|
86
86
|
- `studio_review_evidence` checks program, routine and rung or line names and verbatim quotes before you report findings.
|
|
87
|
-
- `controller_approval_status`
|
|
87
|
+
- `controller_approval_status` says whether this session can ask a human. `capture_controller_snapshot`, `change_controller_mode` and `download_project` need per-call approval of the exact target and proceed only on `allowed-once`; `download_project` takes a `verification_id` from a passed build in this chat.
|
|
88
88
|
- `go_online`, `read_controller_mode` and `read_live_tag` are read-only and need no approval. Never write controller data, force tags, toggle bits or edit online.
|
|
89
89
|
|
|
90
90
|
## Editing
|
|
91
91
|
|
|
92
92
|
Editing uses the `draft_*` family. It may be disabled in this profile; if a draft tool is unavailable, say editing is not enabled here rather than trying another tool.
|
|
93
93
|
|
|
94
|
-
- One operation per call: `draft_rung`, `draft_st`, `draft_routine`, `draft_tag`, `draft_tag_description`, `draft_udt_member`, `draft_udt_description`.
|
|
94
|
+
- One operation per call: `draft_rung`, `draft_rung_comment`, `draft_st`, `draft_routine`, `draft_tag`, `draft_tag_description`, `draft_udt_member`, `draft_udt_description`.
|
|
95
95
|
- `draft_validate` prepares the accumulated draft against the project and returns its hash, diff summary and check findings. Read the findings before applying.
|
|
96
96
|
- `draft_apply` writes the draft to ONE new `.L5X` path. It never overwrites an existing file.
|
|
97
97
|
- After applying, reopen the written file with `open_project` to review it.
|
|
98
98
|
- Drafts belong to this chat. Another chat starts with none, and an applied draft is cleared.
|
|
99
|
+
|
|
100
|
+
## Generate
|
|
101
|
+
|
|
102
|
+
Write ladder through the composer, not by inventing NeutralText.
|
|
103
|
+
|
|
104
|
+
- `list_instructions` gives the mnemonic, category and operand slots with their kinds; read it before composing.
|
|
105
|
+
- `compose_rung` builds one rung from a tree (`spec_json`) or a pattern (`start_stop_latch`, `fault_latch`, `ton_delay`, `interlock`), resolves every operand, type-checks each slot and parses its own output; anything unknown or mistyped is refused before staging.
|
|
106
|
+
- Pass `program`, `routine`, `mode` and `rung` to stage it (plus `comment`); without them it returns text only.
|
|
107
|
+
- `fault_latch` stages two rungs at `rung` and `rung + 1`; rung numbers are not renumbered, so pick free ones.
|
|
108
|
+
|
|
109
|
+
## Documentation
|
|
110
|
+
|
|
111
|
+
`document_project` writes a handover bundle into a NEW folder and never touches the export:
|
|
112
|
+
|
|
113
|
+
- `PROJECT.md` — controller, revision, tasks, programs, counts;
|
|
114
|
+
- `io.md` / `io.csv` — modules and module-data tags;
|
|
115
|
+
- `tags.csv` and `tags-studio.csv` — every declared tag, and the `Tag Name,Description` shape Studio imports;
|
|
116
|
+
- `rungs/<program>.md` — each rung's number, comment, NeutralText, instructions and resolved tags.
|
|
117
|
+
|
|
118
|
+
The bundle is structure and citations, not prose: write the narrative yourself and use `draft_rung_comment` / `draft_tag_description` when it belongs in the project. No C&E, FAT/SAT or runtime proof.
|
|
@@ -5,6 +5,7 @@ type Operation = {
|
|
|
5
5
|
readonly routine: string;
|
|
6
6
|
readonly rung: number;
|
|
7
7
|
readonly text: string;
|
|
8
|
+
readonly comment?: string;
|
|
8
9
|
} | {
|
|
9
10
|
readonly operation: 'delete_rung';
|
|
10
11
|
readonly program: string;
|
|
@@ -17,6 +18,13 @@ type Operation = {
|
|
|
17
18
|
readonly rung: number;
|
|
18
19
|
readonly text: string;
|
|
19
20
|
readonly before_rung?: number;
|
|
21
|
+
readonly comment?: string;
|
|
22
|
+
} | {
|
|
23
|
+
readonly operation: 'set_rung_comment';
|
|
24
|
+
readonly program: string;
|
|
25
|
+
readonly routine: string;
|
|
26
|
+
readonly rung: number;
|
|
27
|
+
readonly comment: string;
|
|
20
28
|
} | {
|
|
21
29
|
readonly operation: 'replace_st';
|
|
22
30
|
readonly program: string;
|
|
@@ -59,7 +67,7 @@ type Operation = {
|
|
|
59
67
|
readonly description: string;
|
|
60
68
|
};
|
|
61
69
|
/** Compact contract returned with validation errors and embedded in tool descriptions. */
|
|
62
|
-
export declare const CHANGE_SET_HELP = "Operations (each also needs \"operation\"):\nreplace_rung {program,routine,rung,text}\ninsert_rung {program,routine,rung,text,before_rung?}\ndelete_rung {program,routine,rung}\nreplace_st {program,routine,code}\nadd_routine {program,name,language:\"RLL\"|\"ST\",code}\nadd_tag {scope,name,data_type,description,value? scalar, dimensions? \"4 2\", external_access? \"Read/Write\"|\"Read Only\"|\"None\"}\nset_tag_description {scope,name,description}\nadd_udt_member {udt,name,data_type,description}\nset_udt_description {udt,description}\nset_udt_member_description {udt,member,description}\nIdentifiers are at most 40 characters. Example: {\"version\":1,\"operations\":[{\"operation\":\"add_tag\",\"scope\":\"controller\",\"name\":\"SP_Start\",\"data_type\":\"REAL\",\"value\":80,\"description\":\"Start threshold\"}]}";
|
|
70
|
+
export declare const CHANGE_SET_HELP = "Operations (each also needs \"operation\"):\nreplace_rung {program,routine,rung,text,comment?}\ninsert_rung {program,routine,rung,text,before_rung?,comment?}\ndelete_rung {program,routine,rung}\nset_rung_comment {program,routine,rung,comment}\nreplace_st {program,routine,code}\nadd_routine {program,name,language:\"RLL\"|\"ST\",code}\nadd_tag {scope,name,data_type,description,value? scalar, dimensions? \"4 2\", external_access? \"Read/Write\"|\"Read Only\"|\"None\"}\nset_tag_description {scope,name,description}\nadd_udt_member {udt,name,data_type,description}\nset_udt_description {udt,description}\nset_udt_member_description {udt,member,description}\nIdentifiers are at most 40 characters. Example: {\"version\":1,\"operations\":[{\"operation\":\"add_tag\",\"scope\":\"controller\",\"name\":\"SP_Start\",\"data_type\":\"REAL\",\"value\":80,\"description\":\"Start threshold\"}]}";
|
|
63
71
|
/** Limits are resolved by the plugin's configuration before tools call this module. */
|
|
64
72
|
export interface ChangeSetLimits {
|
|
65
73
|
readonly operations: number;
|
|
@@ -9,12 +9,13 @@ import { uniqueRegion, xmlRegions } from "./xml-regions.js";
|
|
|
9
9
|
/** Scalar types the plugin can create with a literal initial value. */
|
|
10
10
|
const SCALAR_TYPES = new Set(['BOOL', 'SINT', 'INT', 'DINT', 'LINT', 'USINT', 'UINT', 'UDINT', 'ULINT', 'REAL', 'LREAL']);
|
|
11
11
|
/** Operation names accepted by a version-1 change set. */
|
|
12
|
-
const SUPPORTED_OPERATIONS = ['replace_rung', 'insert_rung', 'delete_rung', 'replace_st', 'add_routine', 'add_tag', 'set_tag_description', 'add_udt_member', 'set_udt_description', 'set_udt_member_description'];
|
|
12
|
+
const SUPPORTED_OPERATIONS = ['replace_rung', 'insert_rung', 'delete_rung', 'set_rung_comment', 'replace_st', 'add_routine', 'add_tag', 'set_tag_description', 'add_udt_member', 'set_udt_description', 'set_udt_member_description'];
|
|
13
13
|
/** Compact contract returned with validation errors and embedded in tool descriptions. */
|
|
14
14
|
export const CHANGE_SET_HELP = `Operations (each also needs "operation"):
|
|
15
|
-
replace_rung {program,routine,rung,text}
|
|
16
|
-
insert_rung {program,routine,rung,text,before_rung?}
|
|
15
|
+
replace_rung {program,routine,rung,text,comment?}
|
|
16
|
+
insert_rung {program,routine,rung,text,before_rung?,comment?}
|
|
17
17
|
delete_rung {program,routine,rung}
|
|
18
|
+
set_rung_comment {program,routine,rung,comment}
|
|
18
19
|
replace_st {program,routine,code}
|
|
19
20
|
add_routine {program,name,language:"RLL"|"ST",code}
|
|
20
21
|
add_tag {scope,name,data_type,description,value? scalar, dimensions? "4 2", external_access? "Read/Write"|"Read Only"|"None"}
|
|
@@ -104,17 +105,21 @@ function parseOne(value, declaredTypes) {
|
|
|
104
105
|
case 'replace_rung':
|
|
105
106
|
case 'insert_rung':
|
|
106
107
|
case 'delete_rung': {
|
|
107
|
-
fields(row, row.operation === 'delete_rung' ? ['operation', 'program', 'routine', 'rung'] : row.operation === 'insert_rung' ? ['operation', 'program', 'routine', 'rung', 'text', 'before_rung'] : ['operation', 'program', 'routine', 'rung', 'text']);
|
|
108
|
+
fields(row, row.operation === 'delete_rung' ? ['operation', 'program', 'routine', 'rung'] : row.operation === 'insert_rung' ? ['operation', 'program', 'routine', 'rung', 'text', 'before_rung', 'comment'] : ['operation', 'program', 'routine', 'rung', 'text', 'comment']);
|
|
108
109
|
const selected = { program: identifier(row, 'program'), routine: identifier(row, 'routine'), rung: integer(row, 'rung') };
|
|
109
110
|
if (row.operation === 'delete_rung')
|
|
110
111
|
return { operation: row.operation, ...selected };
|
|
111
112
|
const source = text(row, 'text');
|
|
112
113
|
if (parseLadder(source).issues.length > 0)
|
|
113
114
|
throw new EngineeringError('INVALID_LADDER', 'Rung contains malformed or unsupported NeutralText structure');
|
|
115
|
+
const comment = row.comment === undefined ? {} : { comment: text(row, 'comment') };
|
|
114
116
|
if (row.operation === 'replace_rung')
|
|
115
|
-
return { operation: row.operation, ...selected, text: source };
|
|
116
|
-
return { operation: row.operation, ...selected, text: source, ...(row.before_rung === undefined ? {} : { before_rung: integer(row, 'before_rung') }) };
|
|
117
|
+
return { operation: row.operation, ...selected, text: source, ...comment };
|
|
118
|
+
return { operation: row.operation, ...selected, text: source, ...comment, ...(row.before_rung === undefined ? {} : { before_rung: integer(row, 'before_rung') }) };
|
|
117
119
|
}
|
|
120
|
+
case 'set_rung_comment':
|
|
121
|
+
fields(row, ['operation', 'program', 'routine', 'rung', 'comment']);
|
|
122
|
+
return { operation: row.operation, program: identifier(row, 'program'), routine: identifier(row, 'routine'), rung: integer(row, 'rung'), comment: text(row, 'comment') };
|
|
118
123
|
case 'replace_st':
|
|
119
124
|
fields(row, ['operation', 'program', 'routine', 'code']);
|
|
120
125
|
return { operation: row.operation, program: identifier(row, 'program'), routine: identifier(row, 'routine'), code: text(row, 'code') };
|
|
@@ -314,7 +319,7 @@ function applyOperation(xml, operation, context) {
|
|
|
314
319
|
if (operation.operation === 'insert_rung') {
|
|
315
320
|
if (targets.length !== 0)
|
|
316
321
|
throw new EngineeringError('NAME_COLLISION', 'Rung number already exists; no automatic renumbering is performed');
|
|
317
|
-
const newRung = `<Rung Number="${operation.rung}" Type="N"
|
|
322
|
+
const newRung = `<Rung Number="${operation.rung}" Type="N">${commentXml(operation.comment)}<Text>${cdata(operation.text)}</Text></Rung>`;
|
|
318
323
|
if (operation.before_rung === undefined)
|
|
319
324
|
return insert(xml, content, newRung);
|
|
320
325
|
const before = rungs.filter(rung => Number(rung.attributes.Number) === operation.before_rung);
|
|
@@ -327,9 +332,29 @@ function applyOperation(xml, operation, context) {
|
|
|
327
332
|
const target = targets[0];
|
|
328
333
|
if (operation.operation === 'delete_rung')
|
|
329
334
|
return replace(xml, target.start, target.end, '');
|
|
335
|
+
if (operation.operation === 'set_rung_comment') {
|
|
336
|
+
return replace(xml, target.start, target.end, rungWith(target, retainedText(xml, target), operation.comment));
|
|
337
|
+
}
|
|
338
|
+
if (operation.comment !== undefined) {
|
|
339
|
+
return replace(xml, target.start, target.end, rungWith(target, `<Text>${cdata(operation.text)}</Text>`, operation.comment));
|
|
340
|
+
}
|
|
330
341
|
const contentText = uniqueRegion(target.children, 'Text');
|
|
331
342
|
return replace(xml, contentText.start, contentText.end, `<Text>${cdata(operation.text)}</Text>`);
|
|
332
343
|
}
|
|
344
|
+
/** A comment element, or nothing when the comment is cleared. */
|
|
345
|
+
function commentXml(comment) {
|
|
346
|
+
return comment === undefined || comment === '' ? '' : `<Comment>${cdata(comment)}</Comment>`;
|
|
347
|
+
}
|
|
348
|
+
/** The rung's existing `<Text>` element, verbatim, for a comment-only edit. */
|
|
349
|
+
function retainedText(xml, rung) {
|
|
350
|
+
const text = rung.children.find(child => child.kind === 'Text');
|
|
351
|
+
return text === undefined ? '<Text><![CDATA[]]></Text>' : xml.slice(text.start, text.end);
|
|
352
|
+
}
|
|
353
|
+
/** Rebuild one rung element with a comment and a text element. */
|
|
354
|
+
function rungWith(rung, text, comment) {
|
|
355
|
+
const type = rung.attributes.Type ?? 'N';
|
|
356
|
+
return `<Rung Number="${rung.attributes.Number}" Type="${type}">${commentXml(comment)}${text}</Rung>`;
|
|
357
|
+
}
|
|
333
358
|
/** Every type name a change may reference: scalars plus declared types. */
|
|
334
359
|
function declaredTypeNames(project) {
|
|
335
360
|
const names = new Set([...SCALAR_TYPES].map(name => name.toLowerCase()));
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the handover documentation bundle for one export.
|
|
3
|
+
*
|
|
4
|
+
* Everything here is derived from the parsed project: the generator provides the
|
|
5
|
+
* structure and the citations, and the narrative prose stays the caller's job.
|
|
6
|
+
* That split is deliberate — a generated narrative would be an unsourced claim,
|
|
7
|
+
* while a rung with its number, comment, text and referenced tags is evidence a
|
|
8
|
+
* reviewer can check in one click.
|
|
9
|
+
*
|
|
10
|
+
* The builder is pure: it returns a map of relative path to text and writes
|
|
11
|
+
* nothing. The tool decides where the folder goes.
|
|
12
|
+
*
|
|
13
|
+
* @module dsh-engineering-l5x/engine/documentation
|
|
14
|
+
*/
|
|
15
|
+
import type { ProjectSnapshot } from '../session.ts';
|
|
16
|
+
/** One documentation part a caller can ask for. */
|
|
17
|
+
export type DocumentPart = 'project' | 'io' | 'tags' | 'rungs';
|
|
18
|
+
/** Every part, in the order the files are produced. */
|
|
19
|
+
export declare const DOCUMENT_PARTS: readonly DocumentPart[];
|
|
20
|
+
/** What one generation produced. */
|
|
21
|
+
export interface DocumentBundle {
|
|
22
|
+
/** Relative path to file text. */
|
|
23
|
+
readonly files: ReadonlyMap<string, string>;
|
|
24
|
+
/** Counts a caller can compare with project_overview. */
|
|
25
|
+
counts: {
|
|
26
|
+
programs: number;
|
|
27
|
+
tasks: number;
|
|
28
|
+
routines: number;
|
|
29
|
+
rungs: number;
|
|
30
|
+
comments: number;
|
|
31
|
+
tags: number;
|
|
32
|
+
modules: number;
|
|
33
|
+
};
|
|
34
|
+
/** Programs and routines the filters excluded. */
|
|
35
|
+
readonly excluded: {
|
|
36
|
+
readonly programs: readonly string[];
|
|
37
|
+
readonly routines: readonly string[];
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/** Options for one generation. */
|
|
41
|
+
export interface DocumentOptions {
|
|
42
|
+
/** Parts to produce; defaults to all. */
|
|
43
|
+
readonly include?: readonly DocumentPart[];
|
|
44
|
+
/** Restrict to these programs. */
|
|
45
|
+
readonly programs?: readonly string[];
|
|
46
|
+
/** Restrict to these routine names. */
|
|
47
|
+
readonly routines?: readonly string[];
|
|
48
|
+
/** Most rungs per generated file before a continuation file is written. */
|
|
49
|
+
readonly rungsPerFile?: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Build the documentation bundle.
|
|
53
|
+
*
|
|
54
|
+
* @param project - Open export snapshot.
|
|
55
|
+
* @param options - Parts, filters and file split.
|
|
56
|
+
* @returns Files to write, counts, and what the filters excluded.
|
|
57
|
+
*/
|
|
58
|
+
export declare function buildDocumentation(project: ProjectSnapshot, options?: DocumentOptions): DocumentBundle;
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the handover documentation bundle for one export.
|
|
3
|
+
*
|
|
4
|
+
* Everything here is derived from the parsed project: the generator provides the
|
|
5
|
+
* structure and the citations, and the narrative prose stays the caller's job.
|
|
6
|
+
* That split is deliberate — a generated narrative would be an unsourced claim,
|
|
7
|
+
* while a rung with its number, comment, text and referenced tags is evidence a
|
|
8
|
+
* reviewer can check in one click.
|
|
9
|
+
*
|
|
10
|
+
* The builder is pure: it returns a map of relative path to text and writes
|
|
11
|
+
* nothing. The tool decides where the folder goes.
|
|
12
|
+
*
|
|
13
|
+
* @module dsh-engineering-l5x/engine/documentation
|
|
14
|
+
*/
|
|
15
|
+
import { L5xError } from "../core/errors.js";
|
|
16
|
+
import { getRoutine, listRoutines } from "../model/routines.js";
|
|
17
|
+
import { aliasesOf } from "./configuration.js";
|
|
18
|
+
import { parseLadder } from "./logic-syntax.js";
|
|
19
|
+
import { resolveTag } from "./tag-resolution.js";
|
|
20
|
+
/** Every part, in the order the files are produced. */
|
|
21
|
+
export const DOCUMENT_PARTS = ['project', 'io', 'tags', 'rungs'];
|
|
22
|
+
/** CSV cell with quoting when the value needs it. */
|
|
23
|
+
function cell(value) {
|
|
24
|
+
const text = value === undefined || value === null ? '' : String(value);
|
|
25
|
+
return /[",\n\r]/u.test(text) ? `"${text.replaceAll('"', '""')}"` : text;
|
|
26
|
+
}
|
|
27
|
+
/** One CSV line. */
|
|
28
|
+
function line(...values) {
|
|
29
|
+
return `${values.map(cell).join(',')}\n`;
|
|
30
|
+
}
|
|
31
|
+
/** A markdown table row. */
|
|
32
|
+
function mdRow(...values) {
|
|
33
|
+
return `| ${values.map(value => String(value ?? '').replaceAll('|', '\\|').replaceAll('\n', ' ')).join(' | ')} |\n`;
|
|
34
|
+
}
|
|
35
|
+
/** Every instruction name in one rung, branches included. */
|
|
36
|
+
function instructionsOf(nodes, out = new Set()) {
|
|
37
|
+
for (const node of nodes) {
|
|
38
|
+
if (node.kind === 'instruction')
|
|
39
|
+
out.add(node.name.toUpperCase());
|
|
40
|
+
else
|
|
41
|
+
for (const path of node.paths)
|
|
42
|
+
instructionsOf(path, out);
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
/** Tags a rung mentions, resolved through the export; instruction names excluded. */
|
|
47
|
+
function tagsOf(document, rung) {
|
|
48
|
+
const parsed = parseLadder(rung.text);
|
|
49
|
+
const instructions = instructionsOf(parsed.nodes);
|
|
50
|
+
for (const aoi of document.aois)
|
|
51
|
+
instructions.add(aoi.name.toUpperCase());
|
|
52
|
+
const found = new Set();
|
|
53
|
+
for (const match of rung.text.matchAll(/[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z0-9_]+|\[[^\]]*\])*/gu)) {
|
|
54
|
+
const text = match[0];
|
|
55
|
+
if (instructions.has(text.toUpperCase()))
|
|
56
|
+
continue;
|
|
57
|
+
const resolution = resolveTag(document, 'controller', text);
|
|
58
|
+
if (resolution.resolved)
|
|
59
|
+
found.add(resolution.canonical ?? text);
|
|
60
|
+
}
|
|
61
|
+
return [...found];
|
|
62
|
+
}
|
|
63
|
+
/** A tag's alias target, for the CSV only. */
|
|
64
|
+
function aliasTarget(document, tag) {
|
|
65
|
+
return aliasesOf(document).get(`${tag.scope}::${tag.name}`) ?? '';
|
|
66
|
+
}
|
|
67
|
+
/** The tags CSV every declared tag appears in. */
|
|
68
|
+
function tagsCsv(document) {
|
|
69
|
+
let text = line('scope', 'name', 'data_type', 'description', 'alias_for', 'dimensions', 'external_access');
|
|
70
|
+
for (const tag of document.tags) {
|
|
71
|
+
const record = tag;
|
|
72
|
+
text += line(tag.scope, tag.name, tag.dataType, tag.description ?? '', aliasTarget(document, tag), record.dimensions ?? '', tag.externalAccess ?? '');
|
|
73
|
+
}
|
|
74
|
+
return text;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The Studio import shape: `Tag Name,Description`.
|
|
78
|
+
*
|
|
79
|
+
* A program-scoped tag is written `Program:Name` so a duplicate name across two
|
|
80
|
+
* programs cannot silently overwrite one of them on import. Verify the template
|
|
81
|
+
* against the installed Studio help before relying on it for a bulk import.
|
|
82
|
+
*/
|
|
83
|
+
function tagsStudioCsv(document) {
|
|
84
|
+
let text = line('Tag Name', 'Description');
|
|
85
|
+
for (const tag of document.tags) {
|
|
86
|
+
const name = tag.scope === 'controller' ? tag.name : `${tag.scope}:${tag.name}`;
|
|
87
|
+
text += line(name, tag.description ?? '');
|
|
88
|
+
}
|
|
89
|
+
return text;
|
|
90
|
+
}
|
|
91
|
+
/** The I/O list: modules and the tags that look like module data. */
|
|
92
|
+
function ioFiles(document) {
|
|
93
|
+
const io = document.tags.filter(tag => tag.name.includes(':'));
|
|
94
|
+
let markdown = '# I/O list\n\n';
|
|
95
|
+
markdown += `${document.modules.length} module(s); ${io.length} tag(s) look like module data (a colon in the name).\n\n`;
|
|
96
|
+
markdown += '| Module | Catalog | Slot | Parent | Inhibited | Description |\n|---|---|---|---|---|---|\n';
|
|
97
|
+
for (const module of document.modules) {
|
|
98
|
+
markdown += mdRow(module.name, module.catalogNumber, module.slot ?? '', module.parentModule, module.inhibited === true, module.description ?? '');
|
|
99
|
+
}
|
|
100
|
+
markdown += `\nModule-data tags: ${io.map(tag => tag.name).join(', ') || 'none'}.\n`;
|
|
101
|
+
let csv = line('name', 'catalog_number', 'slot', 'parent_module', 'inhibited', 'description');
|
|
102
|
+
for (const module of document.modules)
|
|
103
|
+
csv += line(module.name, module.catalogNumber, module.slot ?? '', module.parentModule, module.inhibited === true, module.description ?? '');
|
|
104
|
+
return { markdown, csv };
|
|
105
|
+
}
|
|
106
|
+
/** The project summary: identity, tasks, programs, counts, coverage. */
|
|
107
|
+
function projectMarkdown(project, counts) {
|
|
108
|
+
const document = project.document;
|
|
109
|
+
const { controller } = document;
|
|
110
|
+
let text = `# ${controller.name} project documentation\n\n`;
|
|
111
|
+
text += `Generated from \`${project.path}\` (sha256 \`${project.sha256.slice(0, 16)}…\`) at ${new Date().toISOString()}.\n\n`;
|
|
112
|
+
text += `- Processor: ${controller.processorType}\n- Revision: ${document.controller.majorRev}.${document.controller.minorRev}\n`;
|
|
113
|
+
text += `- Export: ${project.exportKind}; parser verification: ${project.verification}\n`;
|
|
114
|
+
text += `- Programs: ${counts.programs}; tasks: ${counts.tasks}; routines: ${counts.routines}; rungs: ${counts.rungs} (${counts.comments} with comments); tags: ${counts.tags}; modules: ${counts.modules}\n\n`;
|
|
115
|
+
text += '## Tasks\n\n| Task | Type | Rate (ms) | Priority | Programs |\n|---|---|---|---|---|\n';
|
|
116
|
+
for (const task of document.tasks)
|
|
117
|
+
text += mdRow(task.name, task.type, task.rate, task.priority, task.programs.join(', '));
|
|
118
|
+
text += '\n## Programs\n\n| Program | Main routine | Routines | Description |\n|---|---|---|---|\n';
|
|
119
|
+
for (const program of document.programs) {
|
|
120
|
+
const routines = listRoutines(document, program.name);
|
|
121
|
+
text += mdRow(program.name, program.mainRoutine, routines.length, program.description);
|
|
122
|
+
}
|
|
123
|
+
text += '\n## Coverage\n\nThis document is generated from the saved export. It does not prove construction of the program,';
|
|
124
|
+
text += ' compiled behaviour, runtime behaviour, or anything outside the export (HMI, produced/consumed tags, driver consumers).\n';
|
|
125
|
+
return text;
|
|
126
|
+
}
|
|
127
|
+
/** Rung skeletons, one markdown file per program (and continuation). */
|
|
128
|
+
function rungFiles(project, options) {
|
|
129
|
+
const files = new Map();
|
|
130
|
+
const document = project.document;
|
|
131
|
+
const programs = options.programs ?? document.programs.map(program => program.name);
|
|
132
|
+
for (const programName of programs) {
|
|
133
|
+
const program = document.programs.find(entry => entry.name === programName);
|
|
134
|
+
if (program === undefined)
|
|
135
|
+
continue;
|
|
136
|
+
let section = `# ${programName} — rung documentation\n\nProgram main routine: ${program.mainRoutine || 'not declared'}. ${program.description || 'No program description.'}\n`;
|
|
137
|
+
let part = 1;
|
|
138
|
+
let inFile = 0;
|
|
139
|
+
let headingWritten = false;
|
|
140
|
+
for (const info of listRoutines(document, programName)) {
|
|
141
|
+
if (options.routines !== undefined && !options.routines.includes(info.name))
|
|
142
|
+
continue;
|
|
143
|
+
const routine = getRoutine(document, programName, info.name);
|
|
144
|
+
if (routine === undefined || routine.body.type !== 'RLL')
|
|
145
|
+
continue;
|
|
146
|
+
section += `\n## ${info.name}\n\n${info.description || 'No routine description.'}\n`;
|
|
147
|
+
for (const rung of routine.body.rungs) {
|
|
148
|
+
const instructions = [...instructionsOf(parseLadder(rung.text).nodes)].join(', ');
|
|
149
|
+
const tags = tagsOf(document, rung);
|
|
150
|
+
section += `\n### Rung ${rung.number}\n\n`;
|
|
151
|
+
if (rung.comment !== undefined)
|
|
152
|
+
section += `**Comment:** ${rung.comment.replaceAll('\n', '\n> ')}\n\n`;
|
|
153
|
+
section += `\`\`\`\n${rung.text}\n\`\`\`\n\n`;
|
|
154
|
+
section += `Instructions: ${instructions || 'none parsed'}.\n`;
|
|
155
|
+
if (tags.length > 0)
|
|
156
|
+
section += `Tags: ${tags.join(', ')}.\n`;
|
|
157
|
+
inFile += 1;
|
|
158
|
+
if (inFile >= options.perFile) {
|
|
159
|
+
files.set(part === 1 ? `rungs/${programName}.md` : `rungs/${programName}-${part}.md`, section);
|
|
160
|
+
part += 1;
|
|
161
|
+
inFile = 0;
|
|
162
|
+
headingWritten = true;
|
|
163
|
+
section = `# ${programName} — rung documentation (continued)\n`;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (inFile > 0 || !headingWritten)
|
|
168
|
+
files.set(part === 1 ? `rungs/${programName}.md` : `rungs/${programName}-${part}.md`, section);
|
|
169
|
+
}
|
|
170
|
+
return files;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Build the documentation bundle.
|
|
174
|
+
*
|
|
175
|
+
* @param project - Open export snapshot.
|
|
176
|
+
* @param options - Parts, filters and file split.
|
|
177
|
+
* @returns Files to write, counts, and what the filters excluded.
|
|
178
|
+
*/
|
|
179
|
+
export function buildDocumentation(project, options = {}) {
|
|
180
|
+
const document = project.document;
|
|
181
|
+
const include = new Set(options.include ?? DOCUMENT_PARTS);
|
|
182
|
+
const programs = options.programs === undefined ? undefined : [...options.programs];
|
|
183
|
+
const routines = options.routines === undefined ? undefined : [...options.routines];
|
|
184
|
+
if (programs !== undefined) {
|
|
185
|
+
const unknown = programs.filter(name => !document.programs.some(program => program.name === name));
|
|
186
|
+
if (unknown.length > 0)
|
|
187
|
+
throw new L5xError('COMPONENT_NOT_FOUND', `No program named ${unknown.join(', ')}.`, 'Call list_components kind="program" for the declared names.', document.programs.map(program => program.name).slice(0, 5));
|
|
188
|
+
}
|
|
189
|
+
const counts = {
|
|
190
|
+
programs: programs?.length ?? document.programs.length,
|
|
191
|
+
tasks: document.tasks.length,
|
|
192
|
+
routines: 0,
|
|
193
|
+
rungs: 0,
|
|
194
|
+
comments: 0,
|
|
195
|
+
tags: document.tags.length,
|
|
196
|
+
modules: document.modules.length,
|
|
197
|
+
};
|
|
198
|
+
for (const program of document.programs) {
|
|
199
|
+
if (programs !== undefined && !programs.includes(program.name))
|
|
200
|
+
continue;
|
|
201
|
+
for (const routine of listRoutines(document, program.name)) {
|
|
202
|
+
if (routines !== undefined && !routines.includes(routine.name))
|
|
203
|
+
continue;
|
|
204
|
+
counts.routines += 1;
|
|
205
|
+
const body = getRoutine(document, program.name, routine.name);
|
|
206
|
+
if (body !== undefined && body.body.type === 'RLL') {
|
|
207
|
+
counts.rungs += body.body.rungs.length;
|
|
208
|
+
counts.comments += body.body.rungs.filter(rung => rung.comment !== undefined).length;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const files = new Map();
|
|
213
|
+
if (include.has('project'))
|
|
214
|
+
files.set('PROJECT.md', projectMarkdown(project, counts));
|
|
215
|
+
if (include.has('io')) {
|
|
216
|
+
const io = ioFiles(document);
|
|
217
|
+
files.set('io.md', io.markdown);
|
|
218
|
+
files.set('io.csv', io.csv);
|
|
219
|
+
}
|
|
220
|
+
if (include.has('tags')) {
|
|
221
|
+
files.set('tags.csv', tagsCsv(document));
|
|
222
|
+
files.set('tags-studio.csv', tagsStudioCsv(document));
|
|
223
|
+
}
|
|
224
|
+
if (include.has('rungs')) {
|
|
225
|
+
const perFile = Math.max(1, options.rungsPerFile ?? 200);
|
|
226
|
+
for (const [path, text] of rungFiles(project, { programs, routines, perFile }))
|
|
227
|
+
files.set(path, text);
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
files,
|
|
231
|
+
counts,
|
|
232
|
+
excluded: {
|
|
233
|
+
programs: programs === undefined ? [] : document.programs.map(program => program.name).filter(name => !programs.includes(name)),
|
|
234
|
+
routines: document.routines.map(routine => routine.name).filter(name => routines !== undefined && !routines.includes(name)),
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The instruction catalog the ladder composer validates against.
|
|
3
|
+
*
|
|
4
|
+
* Logix has no instruction dictionary inside an L5X export, so a generated rung
|
|
5
|
+
* could previously name any identifier and still parse. This table is the
|
|
6
|
+
* contract: an instruction, its operand slots and the kind each slot accepts.
|
|
7
|
+
*
|
|
8
|
+
* The set covers what engineering programs actually use — measured against a
|
|
9
|
+
* 1279-tag, 860-rung project — rather than every instruction the vendor ships.
|
|
10
|
+
* An unknown name is refused with the nearest catalog names; an AOI declared by
|
|
11
|
+
* the project is accepted separately, because its pins live in the export.
|
|
12
|
+
*
|
|
13
|
+
* @module dsh-engineering-l5x/engine/instructions
|
|
14
|
+
*/
|
|
15
|
+
/** What one operand slot accepts. */
|
|
16
|
+
export type OperandKind = 'BOOL' | 'NUMBER' | 'ANY' | 'TIMER' | 'COUNTER';
|
|
17
|
+
/** One operand slot. */
|
|
18
|
+
export interface InstructionOperand {
|
|
19
|
+
/** Slot name as the programming manual presents it. */
|
|
20
|
+
readonly name: string;
|
|
21
|
+
/** What the slot accepts. */
|
|
22
|
+
readonly kind: OperandKind;
|
|
23
|
+
/** True when the instruction accepts the slot but does not require it. */
|
|
24
|
+
readonly optional?: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** One catalogued instruction. */
|
|
27
|
+
export interface InstructionInfo {
|
|
28
|
+
/** Instruction mnemonic, upper case. */
|
|
29
|
+
readonly name: string;
|
|
30
|
+
/** Grouping shown by the listing tool. */
|
|
31
|
+
readonly category: string;
|
|
32
|
+
/** One line on what the instruction does. */
|
|
33
|
+
readonly summary: string;
|
|
34
|
+
/** Operand slots in written order. */
|
|
35
|
+
readonly operands: readonly InstructionOperand[];
|
|
36
|
+
}
|
|
37
|
+
/** Scalar data types the composer treats as numbers. */
|
|
38
|
+
export declare const NUMERIC_TYPES: ReadonlySet<string>;
|
|
39
|
+
/** Timer data types. */
|
|
40
|
+
export declare const TIMER_TYPES: ReadonlySet<string>;
|
|
41
|
+
/** Counter data types. */
|
|
42
|
+
export declare const COUNTER_TYPES: ReadonlySet<string>;
|
|
43
|
+
/** The catalog, in category order. */
|
|
44
|
+
export declare const INSTRUCTIONS: readonly InstructionInfo[];
|
|
45
|
+
/** The catalog entry for one mnemonic, following the alias table. */
|
|
46
|
+
export declare function instructionByName(name: string): InstructionInfo | undefined;
|
|
47
|
+
/** The catalog name a caller should use for a mnemonic. */
|
|
48
|
+
export declare function canonicalInstruction(name: string): string;
|
|
49
|
+
/** Up to `limit` catalog names closest to one unknown mnemonic. */
|
|
50
|
+
export declare function nearestInstructions(name: string, limit?: number): readonly string[];
|