@voxgig/sdkgen 0.45.0 → 1.1.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/bin/voxgig-sdkgen +1 -1
- package/package.json +3 -3
- package/project/.sdk/src/cmp/go/Entity_go.ts +2 -2
- package/project/.sdk/src/cmp/go/Main_go.ts +8 -4
- package/project/.sdk/src/cmp/go/Package_go.ts +2 -2
- package/project/.sdk/src/cmp/go/ReadmeExplanation_go.ts +2 -2
- package/project/.sdk/src/cmp/go/ReadmeHowto_go.ts +2 -2
- package/project/.sdk/src/cmp/go/ReadmeInstall_go.ts +2 -2
- package/project/.sdk/src/cmp/go/ReadmeModel_go.ts +2 -2
- package/project/.sdk/src/cmp/go/ReadmeQuick_go.ts +2 -2
- package/project/.sdk/src/cmp/go/ReadmeTopQuick_go.ts +2 -2
- package/project/.sdk/src/cmp/go/ReadmeTopTest_go.ts +2 -2
- package/project/.sdk/src/cmp/go/TestDirect_go.ts +204 -33
- package/project/.sdk/src/cmp/go/TestEntity_go.ts +37 -6
- package/project/.sdk/src/cmp/go/Test_go.ts +2 -2
- package/project/.sdk/src/cmp/go/fragment/Main.fragment.go +21 -4
- package/project/.sdk/src/cmp/lua/Package_lua.ts +9 -2
- package/project/.sdk/src/cmp/lua/TestDirect_lua.ts +154 -21
- package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +25 -1
- package/project/.sdk/src/cmp/lua/fragment/Main.fragment.lua +20 -4
- package/project/.sdk/src/cmp/php/Package_php.ts +7 -1
- package/project/.sdk/src/cmp/php/TestDirect_php.ts +153 -20
- package/project/.sdk/src/cmp/php/TestEntity_php.ts +25 -1
- package/project/.sdk/src/cmp/php/fragment/Main.fragment.php +17 -3
- package/project/.sdk/src/cmp/py/Package_py.ts +8 -1
- package/project/.sdk/src/cmp/py/TestDirect_py.ts +146 -19
- package/project/.sdk/src/cmp/py/TestEntity_py.ts +25 -1
- package/project/.sdk/src/cmp/py/fragment/Main.fragment.py +19 -4
- package/project/.sdk/src/cmp/rb/Package_rb.ts +9 -2
- package/project/.sdk/src/cmp/rb/TestDirect_rb.ts +154 -21
- package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +25 -1
- package/project/.sdk/src/cmp/rb/fragment/Main.fragment.rb +19 -3
- package/project/.sdk/src/cmp/ts/Package_ts.ts +1 -1
- package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +145 -22
- package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +59 -1
- package/project/.sdk/src/cmp/ts/fragment/Direct.test.fragment.ts +8 -1
- package/project/.sdk/src/cmp/ts/fragment/Entity.test.fragment.ts +8 -2
- package/project/.sdk/src/cmp/ts/fragment/Main.fragment.ts +21 -1
- package/project/.sdk/tm/go/feature/test_feature.go +56 -3
- package/project/.sdk/tm/go/test/runner_test.go +106 -6
- package/project/.sdk/tm/go/test/sdk-test-control.json +19 -0
- package/project/.sdk/tm/go/utility/fetcher.go +10 -0
- package/project/.sdk/tm/go/utility/make_url.go +12 -0
- package/project/.sdk/tm/lua/feature/test_feature.lua +46 -3
- package/project/.sdk/tm/lua/test/runner.lua +74 -0
- package/project/.sdk/tm/lua/test/sdk-test-control.json +19 -0
- package/project/.sdk/tm/lua/utility/fetcher.lua +13 -0
- package/project/.sdk/tm/lua/utility/make_url.lua +16 -0
- package/project/.sdk/tm/php/feature/TestFeature.php +192 -43
- package/project/.sdk/tm/php/test/Runner.php +62 -0
- package/project/.sdk/tm/php/test/sdk-test-control.json +19 -0
- package/project/.sdk/tm/php/utility/Fetcher.php +132 -9
- package/project/.sdk/tm/php/utility/MakeUrl.php +16 -0
- package/project/.sdk/tm/py/feature/test_feature.py +39 -3
- package/project/.sdk/tm/py/test/runner.py +60 -0
- package/project/.sdk/tm/py/test/sdk-test-control.json +19 -0
- package/project/.sdk/tm/py/utility/fetcher.py +13 -0
- package/project/.sdk/tm/py/utility/make_url.py +13 -0
- package/project/.sdk/tm/rb/feature/test_feature.rb +37 -3
- package/project/.sdk/tm/rb/test/runner.rb +46 -0
- package/project/.sdk/tm/rb/test/sdk-test-control.json +19 -0
- package/project/.sdk/tm/rb/utility/fetcher.rb +49 -28
- package/project/.sdk/tm/rb/utility/make_url.rb +16 -0
- package/project/.sdk/tm/ts/test/sdk-test-control.json +19 -0
- package/project/.sdk/tm/ts/test/utility.ts +120 -2
|
@@ -71,12 +71,112 @@ func envOverride(m map[string]any) map[string]any {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
type entityTestSetup struct {
|
|
74
|
-
client
|
|
75
|
-
data
|
|
76
|
-
idmap
|
|
77
|
-
env
|
|
78
|
-
explain
|
|
79
|
-
|
|
74
|
+
client *sdk.ProjectNameSDK
|
|
75
|
+
data map[string]any
|
|
76
|
+
idmap map[string]any
|
|
77
|
+
env map[string]any
|
|
78
|
+
explain bool
|
|
79
|
+
live bool
|
|
80
|
+
syntheticOnly bool
|
|
81
|
+
now int64
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
var (
|
|
85
|
+
cachedTestControl map[string]any
|
|
86
|
+
cachedTestControlOnce sync.Once
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
// loadTestControl reads sdk-test-control.json from this test dir; caches
|
|
90
|
+
// after first read. Returns an empty-skip default if the file is missing
|
|
91
|
+
// or invalid so tests never crash on a bad config.
|
|
92
|
+
func loadTestControl() map[string]any {
|
|
93
|
+
cachedTestControlOnce.Do(func() {
|
|
94
|
+
_, filename, _, _ := runtime.Caller(0)
|
|
95
|
+
dir := filepath.Dir(filename)
|
|
96
|
+
ctrlPath := filepath.Join(dir, "sdk-test-control.json")
|
|
97
|
+
def := map[string]any{
|
|
98
|
+
"version": 1,
|
|
99
|
+
"test": map[string]any{"skip": map[string]any{
|
|
100
|
+
"live": map[string]any{"direct": []any{}, "entityOp": []any{}},
|
|
101
|
+
"unit": map[string]any{"direct": []any{}, "entityOp": []any{}},
|
|
102
|
+
}},
|
|
103
|
+
}
|
|
104
|
+
data, err := os.ReadFile(ctrlPath)
|
|
105
|
+
if err != nil {
|
|
106
|
+
cachedTestControl = def
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
var parsed map[string]any
|
|
110
|
+
if err := json.Unmarshal(data, &parsed); err != nil {
|
|
111
|
+
cachedTestControl = def
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
cachedTestControl = parsed
|
|
115
|
+
})
|
|
116
|
+
return cachedTestControl
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// isControlSkipped checks sdk-test-control.json for a skip entry.
|
|
120
|
+
// Returns (skip, reason).
|
|
121
|
+
func isControlSkipped(kind, name, mode string) (bool, string) {
|
|
122
|
+
ctrl := loadTestControl()
|
|
123
|
+
test, _ := ctrl["test"].(map[string]any)
|
|
124
|
+
if test == nil {
|
|
125
|
+
return false, ""
|
|
126
|
+
}
|
|
127
|
+
skip, _ := test["skip"].(map[string]any)
|
|
128
|
+
if skip == nil {
|
|
129
|
+
return false, ""
|
|
130
|
+
}
|
|
131
|
+
modeMap, _ := skip[mode].(map[string]any)
|
|
132
|
+
if modeMap == nil {
|
|
133
|
+
return false, ""
|
|
134
|
+
}
|
|
135
|
+
items, _ := modeMap[kind].([]any)
|
|
136
|
+
for _, raw := range items {
|
|
137
|
+
item, _ := raw.(map[string]any)
|
|
138
|
+
if item == nil {
|
|
139
|
+
continue
|
|
140
|
+
}
|
|
141
|
+
reason, _ := item["reason"].(string)
|
|
142
|
+
if kind == "direct" {
|
|
143
|
+
if t, _ := item["test"].(string); t == name {
|
|
144
|
+
return true, reason
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if kind == "entityOp" {
|
|
148
|
+
ent, _ := item["entity"].(string)
|
|
149
|
+
op, _ := item["op"].(string)
|
|
150
|
+
if ent+"."+op == name {
|
|
151
|
+
return true, reason
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return false, ""
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// liveDelayMs returns the configured per-test live delay in ms; default 500.
|
|
159
|
+
func liveDelayMs() int {
|
|
160
|
+
ctrl := loadTestControl()
|
|
161
|
+
test, _ := ctrl["test"].(map[string]any)
|
|
162
|
+
if test == nil {
|
|
163
|
+
return 500
|
|
164
|
+
}
|
|
165
|
+
live, _ := test["live"].(map[string]any)
|
|
166
|
+
if live == nil {
|
|
167
|
+
return 500
|
|
168
|
+
}
|
|
169
|
+
switch v := live["delayMs"].(type) {
|
|
170
|
+
case float64:
|
|
171
|
+
if v >= 0 {
|
|
172
|
+
return int(v)
|
|
173
|
+
}
|
|
174
|
+
case int:
|
|
175
|
+
if v >= 0 {
|
|
176
|
+
return v
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return 500
|
|
80
180
|
}
|
|
81
181
|
|
|
82
182
|
var cachedTestSpec map[string]any
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"_doc": "Per-SDK test control. Lists tests/operations to skip in unit and live modes; tunes per-test pacing. Edit by hand. Loaded by go test runner.",
|
|
4
|
+
"test": {
|
|
5
|
+
"skip": {
|
|
6
|
+
"live": {
|
|
7
|
+
"direct": [],
|
|
8
|
+
"entityOp": []
|
|
9
|
+
},
|
|
10
|
+
"unit": {
|
|
11
|
+
"direct": [],
|
|
12
|
+
"entityOp": []
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"live": {
|
|
16
|
+
"delayMs": 500
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -27,13 +27,23 @@ func defaultHTTPFetch(fullurl string, fetchdef map[string]any) (map[string]any,
|
|
|
27
27
|
return nil, err
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
hasUA := false
|
|
30
31
|
if headers, ok := fetchdef["headers"].(map[string]any); ok {
|
|
31
32
|
for k, v := range headers {
|
|
32
33
|
if sv, ok := v.(string); ok {
|
|
34
|
+
if strings.EqualFold(k, "user-agent") {
|
|
35
|
+
hasUA = true
|
|
36
|
+
}
|
|
33
37
|
req.Header.Set(k, sv)
|
|
34
38
|
}
|
|
35
39
|
}
|
|
36
40
|
}
|
|
41
|
+
// Default User-Agent — Go's net/http defaults to "Go-http-client/1.1"
|
|
42
|
+
// which some CDNs block. Use a Mozilla-shaped UA unless the caller
|
|
43
|
+
// already set one.
|
|
44
|
+
if !hasUA {
|
|
45
|
+
req.Header.Set("User-Agent", "Mozilla/5.0 (compatible; ProjectNameSDK/1.0)")
|
|
46
|
+
}
|
|
37
47
|
|
|
38
48
|
resp, err := http.DefaultClient.Do(req)
|
|
39
49
|
if err != nil {
|
|
@@ -35,6 +35,18 @@ func makeUrlUtil(ctx *core.Context) (string, error) {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
// Append query string from spec.Query.
|
|
39
|
+
qsep := "?"
|
|
40
|
+
for _, item := range vs.Items(spec.Query) {
|
|
41
|
+
key, _ := item[0].(string)
|
|
42
|
+
val := item[1]
|
|
43
|
+
if val != nil {
|
|
44
|
+
url += qsep + vs.EscUrl(key) + "=" + vs.EscUrl(vs.Stringify(val))
|
|
45
|
+
qsep = "&"
|
|
46
|
+
resmatch[key] = val
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
38
50
|
result.Resmatch = resmatch
|
|
39
51
|
|
|
40
52
|
return url, nil
|
|
@@ -62,8 +62,27 @@ function TestFeature:init(ctx, options)
|
|
|
62
62
|
entmap = {}
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
+
-- For single-entity ops (load, remove) with an empty explicit match, fall
|
|
66
|
+
-- back to the id the entity client already knows from a prior create/load
|
|
67
|
+
-- (in fctx.match / fctx.data). Mirrors the TS mock where param() resolves
|
|
68
|
+
-- the id from that accumulated state.
|
|
69
|
+
local function resolve_match(explicit)
|
|
70
|
+
if type(explicit) == "table" and next(explicit) ~= nil then
|
|
71
|
+
return explicit
|
|
72
|
+
end
|
|
73
|
+
local function id_of(src)
|
|
74
|
+
if src == nil then return nil end
|
|
75
|
+
local v = vs.getprop(src, "id")
|
|
76
|
+
if v ~= nil and v ~= "__UNDEFINED__" then return v end
|
|
77
|
+
return nil
|
|
78
|
+
end
|
|
79
|
+
local v = id_of(fctx.match) or id_of(fctx.data)
|
|
80
|
+
if v ~= nil then return { id = v } end
|
|
81
|
+
return {}
|
|
82
|
+
end
|
|
83
|
+
|
|
65
84
|
if op.name == "load" then
|
|
66
|
-
local args = test_self:build_args(fctx, op, fctx.reqmatch)
|
|
85
|
+
local args = test_self:build_args(fctx, op, resolve_match(fctx.reqmatch))
|
|
67
86
|
local found = vs.select(entmap, args)
|
|
68
87
|
local ent = vs.getelem(found, 0)
|
|
69
88
|
if ent == nil then
|
|
@@ -88,9 +107,33 @@ function TestFeature:init(ctx, options)
|
|
|
88
107
|
return respond(200, out, nil)
|
|
89
108
|
|
|
90
109
|
elseif op.name == "update" then
|
|
91
|
-
|
|
110
|
+
-- Match the existing entity by id only (or its alias). reqdata also
|
|
111
|
+
-- contains the new field values, which would otherwise cause select
|
|
112
|
+
-- to filter out the entity we want to update. When reqdata has no id,
|
|
113
|
+
-- fall back to the id the entity client carries from a prior
|
|
114
|
+
-- create/load (in fctx.match / fctx.data), mirroring the TS mock
|
|
115
|
+
-- where param(ctx,'id') resolves from accumulated state.
|
|
116
|
+
local update_match = {}
|
|
117
|
+
if type(fctx.reqdata) == "table" then
|
|
118
|
+
if fctx.reqdata["id"] ~= nil then update_match["id"] = fctx.reqdata["id"] end
|
|
119
|
+
if op.alias_map ~= nil then
|
|
120
|
+
local alias_id = vs.getprop(op.alias_map, "id")
|
|
121
|
+
if alias_id ~= nil and fctx.reqdata[alias_id] ~= nil then
|
|
122
|
+
update_match[alias_id] = fctx.reqdata[alias_id]
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
if next(update_match) == nil then
|
|
127
|
+
update_match = resolve_match({})
|
|
128
|
+
end
|
|
129
|
+
local args = test_self:build_args(fctx, op, update_match)
|
|
92
130
|
local found = vs.select(entmap, args)
|
|
93
131
|
local ent = vs.getelem(found, 0)
|
|
132
|
+
if ent == nil and type(entmap) == "table" then
|
|
133
|
+
for _, e in pairs(entmap) do
|
|
134
|
+
if type(e) == "table" then ent = e; break end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
94
137
|
if ent == nil then
|
|
95
138
|
return respond(404, nil, { statusText = "Not found" })
|
|
96
139
|
end
|
|
@@ -107,7 +150,7 @@ function TestFeature:init(ctx, options)
|
|
|
107
150
|
return respond(200, out, nil)
|
|
108
151
|
|
|
109
152
|
elseif op.name == "remove" then
|
|
110
|
-
local args = test_self:build_args(fctx, op, fctx.reqmatch)
|
|
153
|
+
local args = test_self:build_args(fctx, op, resolve_match(fctx.reqmatch))
|
|
111
154
|
local found = vs.select(entmap, args)
|
|
112
155
|
local ent = vs.getelem(found, 0)
|
|
113
156
|
if ent == nil then
|
|
@@ -83,4 +83,78 @@ function runner.entity_list_to_data(list)
|
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
|
|
86
|
+
-- Load sdk-test-control.json from this test dir; cache. Returns an
|
|
87
|
+
-- empty-skip default if the file is missing or invalid.
|
|
88
|
+
runner._test_control = nil
|
|
89
|
+
|
|
90
|
+
function runner.load_test_control()
|
|
91
|
+
if runner._test_control ~= nil then
|
|
92
|
+
return runner._test_control
|
|
93
|
+
end
|
|
94
|
+
local this_dir = debug.getinfo(1, "S").source:match("^@(.+/)") or "./"
|
|
95
|
+
local ctrl_path = this_dir .. "sdk-test-control.json"
|
|
96
|
+
local f = io.open(ctrl_path, "r")
|
|
97
|
+
if f == nil then
|
|
98
|
+
runner._test_control = {
|
|
99
|
+
version = 1,
|
|
100
|
+
test = {
|
|
101
|
+
skip = {
|
|
102
|
+
live = { direct = {}, entityOp = {} },
|
|
103
|
+
unit = { direct = {}, entityOp = {} },
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
}
|
|
107
|
+
return runner._test_control
|
|
108
|
+
end
|
|
109
|
+
local content = f:read("*a")
|
|
110
|
+
f:close()
|
|
111
|
+
local parsed = json.decode(content)
|
|
112
|
+
if parsed == nil then
|
|
113
|
+
runner._test_control = {
|
|
114
|
+
version = 1,
|
|
115
|
+
test = {
|
|
116
|
+
skip = {
|
|
117
|
+
live = { direct = {}, entityOp = {} },
|
|
118
|
+
unit = { direct = {}, entityOp = {} },
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
}
|
|
122
|
+
else
|
|
123
|
+
runner._test_control = parsed
|
|
124
|
+
end
|
|
125
|
+
return runner._test_control
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
-- Check sdk-test-control.json for a skip entry. Returns (skip, reason).
|
|
130
|
+
function runner.is_control_skipped(kind, name, mode)
|
|
131
|
+
local ctrl = runner.load_test_control()
|
|
132
|
+
local skip = (((ctrl.test or {}).skip or {})[mode] or {})
|
|
133
|
+
local items = skip[kind] or {}
|
|
134
|
+
for _, item in ipairs(items) do
|
|
135
|
+
if kind == "direct" and item.test == name then
|
|
136
|
+
return true, item.reason
|
|
137
|
+
end
|
|
138
|
+
if kind == "entityOp" then
|
|
139
|
+
local key = (item.entity or "") .. "." .. (item.op or "")
|
|
140
|
+
if key == name then
|
|
141
|
+
return true, item.reason
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
return false, nil
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
-- Per-test live pacing delay (ms); default 500.
|
|
150
|
+
function runner.live_delay_ms()
|
|
151
|
+
local ctrl = runner.load_test_control()
|
|
152
|
+
local v = ((ctrl.test or {}).live or {}).delayMs
|
|
153
|
+
if type(v) == "number" and v >= 0 then
|
|
154
|
+
return v
|
|
155
|
+
end
|
|
156
|
+
return 500
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
|
|
86
160
|
return runner
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"_doc": "Per-SDK test control. Lists tests/operations to skip in unit and live modes; tunes per-test pacing. Edit by hand. Loaded by lua test runner.",
|
|
4
|
+
"test": {
|
|
5
|
+
"skip": {
|
|
6
|
+
"live": {
|
|
7
|
+
"direct": [],
|
|
8
|
+
"entityOp": []
|
|
9
|
+
},
|
|
10
|
+
"unit": {
|
|
11
|
+
"direct": [],
|
|
12
|
+
"entityOp": []
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"live": {
|
|
16
|
+
"delayMs": 500
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -25,6 +25,19 @@ local function default_http_fetch(fullurl, fetchdef)
|
|
|
25
25
|
headers["content-length"] = tostring(#body_str)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
-- Default User-Agent — many CDNs reject requests with no UA. Set a
|
|
29
|
+
-- Mozilla-shaped UA unless the caller already set one.
|
|
30
|
+
local has_ua = false
|
|
31
|
+
for k, _ in pairs(headers) do
|
|
32
|
+
if string.lower(k) == "user-agent" then
|
|
33
|
+
has_ua = true
|
|
34
|
+
break
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
if not has_ua then
|
|
38
|
+
headers["User-Agent"] = "Mozilla/5.0 (compatible; ProjectNameSDK/1.0)"
|
|
39
|
+
end
|
|
40
|
+
|
|
28
41
|
local response_body = {}
|
|
29
42
|
local res, code, response_headers = http.request({
|
|
30
43
|
url = fullurl,
|
|
@@ -38,6 +38,22 @@ local function make_url_util(ctx)
|
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
-- Append query string from spec.query.
|
|
42
|
+
local qsep = "?"
|
|
43
|
+
local query_items = vs.items(spec.query)
|
|
44
|
+
if query_items ~= nil then
|
|
45
|
+
for _, item in ipairs(query_items) do
|
|
46
|
+
local key = item[1]
|
|
47
|
+
local val = item[2]
|
|
48
|
+
if val ~= nil and type(key) == "string" then
|
|
49
|
+
local val_str = type(val) == "string" and val or tostring(val)
|
|
50
|
+
url = url .. qsep .. vs.escurl(key) .. "=" .. vs.escurl(val_str)
|
|
51
|
+
qsep = "&"
|
|
52
|
+
resmatch[key] = val
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
41
57
|
result.resmatch = resmatch
|
|
42
58
|
|
|
43
59
|
return url, nil
|