Skip to content

Commit 4b70178

Browse files
authored
ci: generate docs from the contract source (#44)
1 parent b845ef3 commit 4b70178

File tree

4 files changed

+306
-1
lines changed

4 files changed

+306
-1
lines changed

.github/workflows/generated.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Generated Files are Updated
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- "**"
9+
pull_request:
10+
branches:
11+
- "**"
12+
paths:
13+
- "**"
14+
types:
15+
- synchronize
16+
- opened
17+
- reopened
18+
- ready_for_review
19+
20+
defaults:
21+
run:
22+
working-directory: .
23+
24+
jobs:
25+
generate:
26+
runs-on: ubuntu-latest
27+
steps:
28+
- name: Checkout code
29+
uses: actions/checkout@v4
30+
31+
- name: Setup Node.js
32+
uses: actions/setup-node@v4
33+
with:
34+
node-version: "21.1.0"
35+
registry-url: "https://registry.npmjs.org"
36+
37+
- name: Generate docs
38+
run: |
39+
export LC_ALL=C
40+
yarn docs
41+
npx prettier -c . --write
42+
43+
- name: Check for changes
44+
run: |
45+
if git diff --exit-code --ignore-space-change --ignore-all-space --ignore-cr-at-eol -- docs; then
46+
echo "Generated docs are up-to-date."
47+
else
48+
echo "::error::Generated docs are not up-to-date. Please run 'yarn docs' locally and commit any changes."
49+
exit 1
50+
fi

docs/gateway.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# TON Gateway Docs
2+
3+
## gateway.fc
4+
5+
### Constants
6+
7+
- **op::internal::donate** = 100
8+
- **op::internal::deposit** = 101
9+
- **op::internal::deposit_and_call** = 102
10+
- **op::external::withdraw** = 200
11+
- **op::authority::set_deposits_enabled** = 201
12+
- **op::authority::update_tss** = 202
13+
- **op::authority::update_code** = 203
14+
- **op::authority::update_authority** = 204
15+
16+
### `handle_deposit`
17+
18+
```func
19+
() handle_deposit(int amount, slice in_msg_body) impure inline {
20+
```
21+
22+
Deposit TON to the gateway and specify the EVM recipient on ZetaChain
23+
24+
### `handle_set_deposits_enabled`
25+
26+
```func
27+
() handle_set_deposits_enabled(slice sender, slice message) impure inline {
28+
```
29+
30+
Enables or disables deposits.
31+
32+
### `handle_update_tss`
33+
34+
```func
35+
() handle_update_tss(slice sender, slice message) impure inline {
36+
```
37+
38+
Updates the TSS address. WARNING! Execute with extra caution.
39+
Wrong TSS address leads to loss of funds.
40+
41+
### `handle_update_code`
42+
43+
```func
44+
() handle_update_code(slice sender, slice message) impure inline {
45+
```
46+
47+
Updated the code of the contract
48+
Handle_code_update (cell new_code)
49+
50+
### `recv_internal`
51+
52+
```func
53+
() recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure {
54+
```
55+
56+
Input for all internal messages
57+
58+
### `handle_withdrawal`
59+
60+
```func
61+
() handle_withdrawal(slice payload) impure inline {
62+
```
63+
64+
Withdraws assets to the recipient
65+
66+
Handle_withdrawal (MsgAddr recipient, Coins amount, int seqno)
67+
68+
### `recv_external`
69+
70+
```func
71+
() recv_external(slice message) impure {
72+
```
73+
74+
Entry point for all external messages

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"build": "tsc && blueprint build",
99
"prettier": "prettier -c .",
1010
"prettier-fix": "prettier --write -c .",
11-
"test": "jest --verbose"
11+
"test": "jest --verbose",
12+
"docs": "sh ./scripts/docs.sh"
1213
},
1314
"main": "dist/index.js",
1415
"files": [

scripts/docs.sh

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
#!/bin/bash
2+
3+
# —— 1. Locale guard —─────────────────────────────────────────────────────────
4+
# Enforcing a "C" locale guarantees reproducible sort order and decimal
5+
# separators. (Some CI images default to UTF-8 locales which may break awk.)
6+
export LC_ALL=C
7+
export LANG=C
8+
9+
# —— 2. CLI arguments with sensible fallbacks —───────────────────────────────
10+
INPUT_FILE=${1:-contracts/gateway.fc} # Default contract path (for devs)
11+
OUTPUT_FILE=${2:-docs/gateway.md} # Where to write the final docs
12+
13+
# Ensure the output directory exists so we don’t die on a missing path.
14+
mkdir -p "$(dirname "$OUTPUT_FILE")"
15+
16+
# —— 3. Work in a temp file so we never leave half-baked docs behind —────────
17+
TMP_FILE=$(mktemp) # Final markdown lives here until complete
18+
FILE_TMP=$(mktemp) # Intermediate file for awk output
19+
20+
###############################################################################
21+
# 4. Markdown preamble #
22+
###############################################################################
23+
{
24+
echo "# TON Gateway Docs"
25+
echo
26+
} > "$TMP_FILE"
27+
28+
###############################################################################
29+
# 5. AWK pass - the heavy lifter #
30+
# * Written to be POSIX-awk compatible (no /\s/, \+, gensub, etc.). #
31+
# * Inline comments are sprinkled liberally to clarify the logic. #
32+
###############################################################################
33+
34+
awk '
35+
############################################################################
36+
# Utility helpers (trim) - POSIX-compliant implementations #
37+
############################################################################
38+
function ltrim(s) { sub(/^[[:space:]]+/, "", s); return s }
39+
function rtrim(s) { sub(/[[:space:]]+$/, "", s); return s }
40+
function trim(s) { return rtrim(ltrim(s)) }
41+
42+
############################################################################
43+
# Detect section-header comment lines we do *not* want to treat as doc text #
44+
############################################################################
45+
function is_section_comment(line) {
46+
return line ~ /={3,}/ || line ~ /^(Sizes|GAS|OP|EXTERNAL|INTERNAL|PARSING|GETTERS|TL-B|AUTH)/
47+
}
48+
49+
############################################################################
50+
# Extract function name from a FunC definition line #
51+
############################################################################
52+
function extract_func_name(line, copy) {
53+
copy = line
54+
sub(/^[[:space:]]+/, "", copy) # Leading WS
55+
# If the line starts with "() func_name(" - strip the unit sigil.
56+
if (copy ~ /^\(\)[[:space:]]*[A-Za-z0-9_]+[[:space:]]*\(/)
57+
sub(/^\(\)[[:space:]]*/, "", copy)
58+
match(copy, /^([A-Za-z0-9_]+)[[:space:]]*\(/)
59+
return substr(copy, RSTART, RLENGTH - 1)
60+
}
61+
62+
############################################################################
63+
# Identify lines that are *actual* function definitions (not if/while etc.) #
64+
############################################################################
65+
function is_function_definition(line) {
66+
pat = "^[[:space:]]*(\\(\\))?[[:space:]]*[A-Za-z0-9_]+[[:space:]]*\\([^)]*\\)[[:space:]]*(impure)?[[:space:]]*(inline|inline_ref)?[[:space:]]*(method_id)?[[:space:]]*\\{";
67+
ctl = "^[[:space:]]*(if|while|repeat)[[:space:]]*\\(";
68+
return (line ~ pat) && !(line ~ ctl)
69+
}
70+
71+
############################################################################
72+
# Public API filter - only expose handle_* + recv_* #
73+
############################################################################
74+
function want_function(name) { return name ~ /^(handle_|recv_)/ }
75+
76+
############################################################################
77+
# BEGIN block - initialise state #
78+
############################################################################
79+
BEGIN {
80+
collecting_comment = 0 # Are we in a block of leading ";;" lines?
81+
comment = "" # Accumulated comment text
82+
const_header_printed = 0 # Printed the "## Constants" header yet?
83+
in_const_block = 0 # Are we in a block of constants?
84+
}
85+
86+
############################################################################
87+
# 1) Capture consecutive ";; <text>" lines #
88+
############################################################################
89+
/^[[:space:]]*;;/ {
90+
line = substr($0, index($0, ";;") + 2) # Strip the marker
91+
if (!is_section_comment(line)) {
92+
# Normalise capitalisation a tiny bit → "foo bar" → "Foo bar"
93+
text = trim(line)
94+
text = toupper(substr(text,1,1)) substr(text,2)
95+
comment = (comment ? comment "\n" : "") text
96+
collecting_comment = 1
97+
}
98+
next
99+
}
100+
101+
############################################################################
102+
# 2) Function defs - emit md if we *just* captured a comment #
103+
############################################################################
104+
{
105+
if (is_function_definition($0)) {
106+
if (in_const_block) {
107+
print ""
108+
in_const_block = 0
109+
}
110+
fname = extract_func_name($0)
111+
if (want_function(fname) && collecting_comment && comment) {
112+
print "### `" fname "`\n" # H3 header
113+
print "```func" # Code fence start
114+
print $0 # The definition line itself
115+
print "```\n" # Code fence end
116+
print comment "\n" # The doc string
117+
}
118+
collecting_comment = comment = "" # Reset for next round
119+
next
120+
}
121+
}
122+
123+
############################################################################
124+
# 3) Constant extraction - opcode & error ids #
125+
############################################################################
126+
/^[[:space:]]*const[[:space:]]+[A-Za-z0-9_:]+[[:space:]]*=/ {
127+
# Example line: const op::internal::deposit = 101;
128+
129+
# 3.1. Chop off the leading "const" keyword
130+
line = $0
131+
sub(/^[[:space:]]*const[[:space:]]+/, "", line)
132+
133+
# 3.2. Split on the first "=" to isolate LHS and RHS
134+
split(line, parts, "=")
135+
identifier = trim(parts[1])
136+
value_part = trim(parts[2])
137+
138+
# 3.3. Remove trailing semicolon and inline comments from RHS
139+
sub(/;.*/, "", value_part)
140+
value = trim(value_part)
141+
142+
# 3.4. Only emit op:: and error:: groups - the rest is internal noise
143+
if (identifier ~ /^op::/ || identifier ~ /^error::/) {
144+
if (!const_header_printed) {
145+
print "### Constants\n" # One-time section header
146+
const_header_printed = 1
147+
}
148+
print "- **" identifier "** = " value # • **op::blah** = 123
149+
in_const_block = 1
150+
}
151+
next
152+
}
153+
154+
############################################################################
155+
# 4) Reset comment collection on any plain line #
156+
############################################################################
157+
{
158+
collecting_comment = 0; comment = ""
159+
}
160+
' "$INPUT_FILE" > "$FILE_TMP"
161+
162+
###############################################################################
163+
# 6. Append AWK output to the top-level markdown only if something was found #
164+
###############################################################################
165+
if [ -s "$FILE_TMP" ]; then
166+
{
167+
echo "## $(basename "$INPUT_FILE")"
168+
echo
169+
cat "$FILE_TMP"
170+
} >> "$TMP_FILE"
171+
fi
172+
173+
rm "$FILE_TMP" # No longer needed
174+
175+
###############################################################################
176+
# 7. Strip CRLFs, trailing blank lines, and atomically move into place #
177+
###############################################################################
178+
tr -d '\r' < "$TMP_FILE" | \
179+
sed -e :a -e '/^\n*$/{$d;N;ba' -e '}'> "$OUTPUT_FILE"
180+
rm "$TMP_FILE"

0 commit comments

Comments
 (0)