object_goreflect.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. package goja
  2. import (
  3. "fmt"
  4. "go/ast"
  5. "reflect"
  6. "strings"
  7. "github.com/dop251/goja/parser"
  8. "github.com/dop251/goja/unistring"
  9. )
  10. // JsonEncodable allows custom JSON encoding by JSON.stringify()
  11. // Note that if the returned value itself also implements JsonEncodable, it won't have any effect.
  12. type JsonEncodable interface {
  13. JsonEncodable() interface{}
  14. }
  15. // FieldNameMapper provides custom mapping between Go and JavaScript property names.
  16. type FieldNameMapper interface {
  17. // FieldName returns a JavaScript name for the given struct field in the given type.
  18. // If this method returns "" the field becomes hidden.
  19. FieldName(t reflect.Type, f reflect.StructField) string
  20. // MethodName returns a JavaScript name for the given method in the given type.
  21. // If this method returns "" the method becomes hidden.
  22. MethodName(t reflect.Type, m reflect.Method) string
  23. }
  24. type tagFieldNameMapper struct {
  25. tagName string
  26. uncapMethods bool
  27. }
  28. func (tfm tagFieldNameMapper) FieldName(_ reflect.Type, f reflect.StructField) string {
  29. tag := f.Tag.Get(tfm.tagName)
  30. if idx := strings.IndexByte(tag, ','); idx != -1 {
  31. tag = tag[:idx]
  32. }
  33. if parser.IsIdentifier(tag) {
  34. return tag
  35. }
  36. return ""
  37. }
  38. func uncapitalize(s string) string {
  39. return strings.ToLower(s[0:1]) + s[1:]
  40. }
  41. func (tfm tagFieldNameMapper) MethodName(_ reflect.Type, m reflect.Method) string {
  42. if tfm.uncapMethods {
  43. return uncapitalize(m.Name)
  44. }
  45. return m.Name
  46. }
  47. type uncapFieldNameMapper struct {
  48. }
  49. func (u uncapFieldNameMapper) FieldName(_ reflect.Type, f reflect.StructField) string {
  50. return uncapitalize(f.Name)
  51. }
  52. func (u uncapFieldNameMapper) MethodName(_ reflect.Type, m reflect.Method) string {
  53. return uncapitalize(m.Name)
  54. }
  55. type reflectFieldInfo struct {
  56. Index []int
  57. Anonymous bool
  58. }
  59. type reflectFieldsInfo struct {
  60. Fields map[string]reflectFieldInfo
  61. Names []string
  62. }
  63. type reflectMethodsInfo struct {
  64. Methods map[string]int
  65. Names []string
  66. }
  67. type reflectValueWrapper interface {
  68. esValue() Value
  69. reflectValue() reflect.Value
  70. setReflectValue(reflect.Value)
  71. }
  72. func isContainer(k reflect.Kind) bool {
  73. switch k {
  74. case reflect.Struct, reflect.Slice, reflect.Array:
  75. return true
  76. }
  77. return false
  78. }
  79. func copyReflectValueWrapper(w reflectValueWrapper) {
  80. v := w.reflectValue()
  81. c := reflect.New(v.Type()).Elem()
  82. c.Set(v)
  83. w.setReflectValue(c)
  84. }
  85. type objectGoReflect struct {
  86. baseObject
  87. origValue, fieldsValue reflect.Value
  88. fieldsInfo *reflectFieldsInfo
  89. methodsInfo *reflectMethodsInfo
  90. methodsValue reflect.Value
  91. valueCache map[string]reflectValueWrapper
  92. toString, valueOf func() Value
  93. toJson func() interface{}
  94. }
  95. func (o *objectGoReflect) init() {
  96. o.baseObject.init()
  97. switch o.fieldsValue.Kind() {
  98. case reflect.Bool:
  99. o.class = classBoolean
  100. o.prototype = o.val.runtime.global.BooleanPrototype
  101. o.toString = o._toStringBool
  102. o.valueOf = o._valueOfBool
  103. case reflect.String:
  104. o.class = classString
  105. o.prototype = o.val.runtime.global.StringPrototype
  106. o.toString = o._toStringString
  107. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  108. o.class = classNumber
  109. o.prototype = o.val.runtime.global.NumberPrototype
  110. o.valueOf = o._valueOfInt
  111. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
  112. o.class = classNumber
  113. o.prototype = o.val.runtime.global.NumberPrototype
  114. o.valueOf = o._valueOfUint
  115. case reflect.Float32, reflect.Float64:
  116. o.class = classNumber
  117. o.prototype = o.val.runtime.global.NumberPrototype
  118. o.valueOf = o._valueOfFloat
  119. default:
  120. o.class = classObject
  121. o.prototype = o.val.runtime.global.ObjectPrototype
  122. }
  123. if o.fieldsValue.Kind() == reflect.Struct {
  124. o.fieldsInfo = o.val.runtime.fieldsInfo(o.fieldsValue.Type())
  125. }
  126. var methodsType reflect.Type
  127. // Always use pointer type for non-interface values to be able to access both methods defined on
  128. // the literal type and on the pointer.
  129. if o.fieldsValue.Kind() != reflect.Interface {
  130. methodsType = reflect.PointerTo(o.fieldsValue.Type())
  131. } else {
  132. methodsType = o.fieldsValue.Type()
  133. }
  134. o.methodsInfo = o.val.runtime.methodsInfo(methodsType)
  135. // Container values and values that have at least one method defined on the pointer type
  136. // need to be addressable.
  137. if !o.origValue.CanAddr() && (isContainer(o.origValue.Kind()) || len(o.methodsInfo.Names) > 0) {
  138. value := reflect.New(o.origValue.Type()).Elem()
  139. value.Set(o.origValue)
  140. o.origValue = value
  141. if value.Kind() != reflect.Ptr {
  142. o.fieldsValue = value
  143. }
  144. }
  145. o.extensible = true
  146. switch o.origValue.Interface().(type) {
  147. case fmt.Stringer:
  148. o.toString = o._toStringStringer
  149. case error:
  150. o.toString = o._toStringError
  151. }
  152. if o.toString != nil || o.valueOf != nil {
  153. o.baseObject._putProp("toString", o.val.runtime.newNativeFunc(o.toStringFunc, nil, "toString", nil, 0), true, false, true)
  154. o.baseObject._putProp("valueOf", o.val.runtime.newNativeFunc(o.valueOfFunc, nil, "valueOf", nil, 0), true, false, true)
  155. }
  156. if len(o.methodsInfo.Names) > 0 && o.fieldsValue.Kind() != reflect.Interface {
  157. o.methodsValue = o.fieldsValue.Addr()
  158. } else {
  159. o.methodsValue = o.fieldsValue
  160. }
  161. if j, ok := o.origValue.Interface().(JsonEncodable); ok {
  162. o.toJson = j.JsonEncodable
  163. }
  164. }
  165. func (o *objectGoReflect) toStringFunc(FunctionCall) Value {
  166. return o.toPrimitiveString()
  167. }
  168. func (o *objectGoReflect) valueOfFunc(FunctionCall) Value {
  169. return o.toPrimitiveNumber()
  170. }
  171. func (o *objectGoReflect) getStr(name unistring.String, receiver Value) Value {
  172. if v := o._get(name.String()); v != nil {
  173. return v
  174. }
  175. return o.baseObject.getStr(name, receiver)
  176. }
  177. func (o *objectGoReflect) _getField(jsName string) reflect.Value {
  178. if o.fieldsInfo != nil {
  179. if info, exists := o.fieldsInfo.Fields[jsName]; exists {
  180. return o.fieldsValue.FieldByIndex(info.Index)
  181. }
  182. }
  183. return reflect.Value{}
  184. }
  185. func (o *objectGoReflect) _getMethod(jsName string) reflect.Value {
  186. if o.methodsInfo != nil {
  187. if idx, exists := o.methodsInfo.Methods[jsName]; exists {
  188. return o.methodsValue.Method(idx)
  189. }
  190. }
  191. return reflect.Value{}
  192. }
  193. func (o *objectGoReflect) elemToValue(ev reflect.Value) (Value, reflectValueWrapper) {
  194. if isContainer(ev.Kind()) {
  195. if ev.Type() == reflectTypeArray {
  196. a := o.val.runtime.newObjectGoSlice(ev.Addr().Interface().(*[]interface{}))
  197. return a.val, a
  198. }
  199. ret := o.val.runtime.reflectValueToValue(ev)
  200. if obj, ok := ret.(*Object); ok {
  201. if w, ok := obj.self.(reflectValueWrapper); ok {
  202. return ret, w
  203. }
  204. }
  205. panic("reflectValueToValue() returned a value which is not a reflectValueWrapper")
  206. }
  207. for ev.Kind() == reflect.Interface {
  208. ev = ev.Elem()
  209. }
  210. if ev.Kind() == reflect.Invalid {
  211. return _null, nil
  212. }
  213. return o.val.runtime.ToValue(ev.Interface()), nil
  214. }
  215. func (o *objectGoReflect) _getFieldValue(name string) Value {
  216. if v := o.valueCache[name]; v != nil {
  217. return v.esValue()
  218. }
  219. if v := o._getField(name); v.IsValid() {
  220. res, w := o.elemToValue(v)
  221. if w != nil {
  222. if o.valueCache == nil {
  223. o.valueCache = make(map[string]reflectValueWrapper)
  224. }
  225. o.valueCache[name] = w
  226. }
  227. return res
  228. }
  229. return nil
  230. }
  231. func (o *objectGoReflect) _get(name string) Value {
  232. if o.fieldsValue.Kind() == reflect.Struct {
  233. if ret := o._getFieldValue(name); ret != nil {
  234. return ret
  235. }
  236. }
  237. if v := o._getMethod(name); v.IsValid() {
  238. return o.val.runtime.reflectValueToValue(v)
  239. }
  240. return nil
  241. }
  242. func (o *objectGoReflect) getOwnPropStr(name unistring.String) Value {
  243. n := name.String()
  244. if o.fieldsValue.Kind() == reflect.Struct {
  245. if v := o._getFieldValue(n); v != nil {
  246. return &valueProperty{
  247. value: v,
  248. writable: true,
  249. enumerable: true,
  250. }
  251. }
  252. }
  253. if v := o._getMethod(n); v.IsValid() {
  254. return &valueProperty{
  255. value: o.val.runtime.reflectValueToValue(v),
  256. enumerable: true,
  257. }
  258. }
  259. return nil
  260. }
  261. func (o *objectGoReflect) setOwnStr(name unistring.String, val Value, throw bool) bool {
  262. has, ok := o._put(name.String(), val, throw)
  263. if !has {
  264. if res, ok := o._setForeignStr(name, nil, val, o.val, throw); !ok {
  265. o.val.runtime.typeErrorResult(throw, "Cannot assign to property %s of a host object", name)
  266. return false
  267. } else {
  268. return res
  269. }
  270. }
  271. return ok
  272. }
  273. func (o *objectGoReflect) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) {
  274. return o._setForeignStr(name, trueValIfPresent(o._has(name.String())), val, receiver, throw)
  275. }
  276. func (o *objectGoReflect) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) {
  277. return o._setForeignIdx(idx, nil, val, receiver, throw)
  278. }
  279. func (o *objectGoReflect) _put(name string, val Value, throw bool) (has, ok bool) {
  280. if o.fieldsValue.Kind() == reflect.Struct {
  281. if v := o._getField(name); v.IsValid() {
  282. cached := o.valueCache[name]
  283. if cached != nil {
  284. copyReflectValueWrapper(cached)
  285. }
  286. err := o.val.runtime.toReflectValue(val, v, &objectExportCtx{})
  287. if err != nil {
  288. if cached != nil {
  289. cached.setReflectValue(v)
  290. }
  291. o.val.runtime.typeErrorResult(throw, "Go struct conversion error: %v", err)
  292. return true, false
  293. }
  294. if cached != nil {
  295. delete(o.valueCache, name)
  296. }
  297. return true, true
  298. }
  299. }
  300. return false, false
  301. }
  302. func (o *objectGoReflect) _putProp(name unistring.String, value Value, writable, enumerable, configurable bool) Value {
  303. if _, ok := o._put(name.String(), value, false); ok {
  304. return value
  305. }
  306. return o.baseObject._putProp(name, value, writable, enumerable, configurable)
  307. }
  308. func (r *Runtime) checkHostObjectPropertyDescr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
  309. if descr.Getter != nil || descr.Setter != nil {
  310. r.typeErrorResult(throw, "Host objects do not support accessor properties")
  311. return false
  312. }
  313. if descr.Writable == FLAG_FALSE {
  314. r.typeErrorResult(throw, "Host object field %s cannot be made read-only", name)
  315. return false
  316. }
  317. if descr.Configurable == FLAG_TRUE {
  318. r.typeErrorResult(throw, "Host object field %s cannot be made configurable", name)
  319. return false
  320. }
  321. return true
  322. }
  323. func (o *objectGoReflect) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool {
  324. if o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) {
  325. n := name.String()
  326. if has, ok := o._put(n, descr.Value, throw); !has {
  327. o.val.runtime.typeErrorResult(throw, "Cannot define property '%s' on a host object", n)
  328. return false
  329. } else {
  330. return ok
  331. }
  332. }
  333. return false
  334. }
  335. func (o *objectGoReflect) _has(name string) bool {
  336. if o.fieldsValue.Kind() == reflect.Struct {
  337. if v := o._getField(name); v.IsValid() {
  338. return true
  339. }
  340. }
  341. if v := o._getMethod(name); v.IsValid() {
  342. return true
  343. }
  344. return false
  345. }
  346. func (o *objectGoReflect) hasOwnPropertyStr(name unistring.String) bool {
  347. return o._has(name.String())
  348. }
  349. func (o *objectGoReflect) _valueOfInt() Value {
  350. return intToValue(o.fieldsValue.Int())
  351. }
  352. func (o *objectGoReflect) _valueOfUint() Value {
  353. return intToValue(int64(o.fieldsValue.Uint()))
  354. }
  355. func (o *objectGoReflect) _valueOfBool() Value {
  356. if o.fieldsValue.Bool() {
  357. return valueTrue
  358. } else {
  359. return valueFalse
  360. }
  361. }
  362. func (o *objectGoReflect) _valueOfFloat() Value {
  363. return floatToValue(o.fieldsValue.Float())
  364. }
  365. func (o *objectGoReflect) _toStringStringer() Value {
  366. return newStringValue(o.origValue.Interface().(fmt.Stringer).String())
  367. }
  368. func (o *objectGoReflect) _toStringString() Value {
  369. return newStringValue(o.fieldsValue.String())
  370. }
  371. func (o *objectGoReflect) _toStringBool() Value {
  372. if o.fieldsValue.Bool() {
  373. return stringTrue
  374. } else {
  375. return stringFalse
  376. }
  377. }
  378. func (o *objectGoReflect) _toStringError() Value {
  379. return newStringValue(o.origValue.Interface().(error).Error())
  380. }
  381. func (o *objectGoReflect) toPrimitiveNumber() Value {
  382. if o.valueOf != nil {
  383. return o.valueOf()
  384. }
  385. if o.toString != nil {
  386. return o.toString()
  387. }
  388. return o.baseObject.toPrimitiveNumber()
  389. }
  390. func (o *objectGoReflect) toPrimitiveString() Value {
  391. if o.toString != nil {
  392. return o.toString()
  393. }
  394. if o.valueOf != nil {
  395. return o.valueOf().toString()
  396. }
  397. return o.baseObject.toPrimitiveString()
  398. }
  399. func (o *objectGoReflect) toPrimitive() Value {
  400. if o.valueOf != nil {
  401. return o.valueOf()
  402. }
  403. if o.toString != nil {
  404. return o.toString()
  405. }
  406. return o.baseObject.toPrimitive()
  407. }
  408. func (o *objectGoReflect) deleteStr(name unistring.String, throw bool) bool {
  409. n := name.String()
  410. if o._has(n) {
  411. o.val.runtime.typeErrorResult(throw, "Cannot delete property %s from a Go type", n)
  412. return false
  413. }
  414. return o.baseObject.deleteStr(name, throw)
  415. }
  416. type goreflectPropIter struct {
  417. o *objectGoReflect
  418. idx int
  419. }
  420. func (i *goreflectPropIter) nextField() (propIterItem, iterNextFunc) {
  421. names := i.o.fieldsInfo.Names
  422. if i.idx < len(names) {
  423. name := names[i.idx]
  424. i.idx++
  425. return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.nextField
  426. }
  427. i.idx = 0
  428. return i.nextMethod()
  429. }
  430. func (i *goreflectPropIter) nextMethod() (propIterItem, iterNextFunc) {
  431. names := i.o.methodsInfo.Names
  432. if i.idx < len(names) {
  433. name := names[i.idx]
  434. i.idx++
  435. return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.nextMethod
  436. }
  437. return propIterItem{}, nil
  438. }
  439. func (o *objectGoReflect) iterateStringKeys() iterNextFunc {
  440. r := &goreflectPropIter{
  441. o: o,
  442. }
  443. if o.fieldsInfo != nil {
  444. return r.nextField
  445. }
  446. return r.nextMethod
  447. }
  448. func (o *objectGoReflect) stringKeys(_ bool, accum []Value) []Value {
  449. // all own keys are enumerable
  450. if o.fieldsInfo != nil {
  451. for _, name := range o.fieldsInfo.Names {
  452. accum = append(accum, newStringValue(name))
  453. }
  454. }
  455. for _, name := range o.methodsInfo.Names {
  456. accum = append(accum, newStringValue(name))
  457. }
  458. return accum
  459. }
  460. func (o *objectGoReflect) export(*objectExportCtx) interface{} {
  461. return o.origValue.Interface()
  462. }
  463. func (o *objectGoReflect) exportType() reflect.Type {
  464. return o.origValue.Type()
  465. }
  466. func (o *objectGoReflect) equal(other objectImpl) bool {
  467. if other, ok := other.(*objectGoReflect); ok {
  468. k1, k2 := o.fieldsValue.Kind(), other.fieldsValue.Kind()
  469. if k1 == k2 {
  470. if isContainer(k1) {
  471. return o.fieldsValue == other.fieldsValue
  472. }
  473. return o.fieldsValue.Interface() == other.fieldsValue.Interface()
  474. }
  475. }
  476. return false
  477. }
  478. func (o *objectGoReflect) reflectValue() reflect.Value {
  479. return o.fieldsValue
  480. }
  481. func (o *objectGoReflect) setReflectValue(v reflect.Value) {
  482. o.fieldsValue = v
  483. o.origValue = v
  484. o.methodsValue = v.Addr()
  485. }
  486. func (o *objectGoReflect) esValue() Value {
  487. return o.val
  488. }
  489. func (r *Runtime) buildFieldInfo(t reflect.Type, index []int, info *reflectFieldsInfo) {
  490. n := t.NumField()
  491. for i := 0; i < n; i++ {
  492. field := t.Field(i)
  493. name := field.Name
  494. if !ast.IsExported(name) {
  495. continue
  496. }
  497. if r.fieldNameMapper != nil {
  498. name = r.fieldNameMapper.FieldName(t, field)
  499. }
  500. if name != "" {
  501. if inf, exists := info.Fields[name]; !exists {
  502. info.Names = append(info.Names, name)
  503. } else {
  504. if len(inf.Index) <= len(index) {
  505. continue
  506. }
  507. }
  508. }
  509. if name != "" || field.Anonymous {
  510. idx := make([]int, len(index)+1)
  511. copy(idx, index)
  512. idx[len(idx)-1] = i
  513. if name != "" {
  514. info.Fields[name] = reflectFieldInfo{
  515. Index: idx,
  516. Anonymous: field.Anonymous,
  517. }
  518. }
  519. if field.Anonymous {
  520. typ := field.Type
  521. for typ.Kind() == reflect.Ptr {
  522. typ = typ.Elem()
  523. }
  524. if typ.Kind() == reflect.Struct {
  525. r.buildFieldInfo(typ, idx, info)
  526. }
  527. }
  528. }
  529. }
  530. }
  531. var emptyMethodsInfo = reflectMethodsInfo{}
  532. func (r *Runtime) buildMethodsInfo(t reflect.Type) (info *reflectMethodsInfo) {
  533. n := t.NumMethod()
  534. if n == 0 {
  535. return &emptyMethodsInfo
  536. }
  537. info = new(reflectMethodsInfo)
  538. info.Methods = make(map[string]int, n)
  539. info.Names = make([]string, 0, n)
  540. for i := 0; i < n; i++ {
  541. method := t.Method(i)
  542. name := method.Name
  543. if !ast.IsExported(name) {
  544. continue
  545. }
  546. if r.fieldNameMapper != nil {
  547. name = r.fieldNameMapper.MethodName(t, method)
  548. if name == "" {
  549. continue
  550. }
  551. }
  552. if _, exists := info.Methods[name]; !exists {
  553. info.Names = append(info.Names, name)
  554. }
  555. info.Methods[name] = i
  556. }
  557. return
  558. }
  559. func (r *Runtime) buildFieldsInfo(t reflect.Type) (info *reflectFieldsInfo) {
  560. info = new(reflectFieldsInfo)
  561. n := t.NumField()
  562. info.Fields = make(map[string]reflectFieldInfo, n)
  563. info.Names = make([]string, 0, n)
  564. r.buildFieldInfo(t, nil, info)
  565. return
  566. }
  567. func (r *Runtime) fieldsInfo(t reflect.Type) (info *reflectFieldsInfo) {
  568. var exists bool
  569. if info, exists = r.fieldsInfoCache[t]; !exists {
  570. info = r.buildFieldsInfo(t)
  571. if r.fieldsInfoCache == nil {
  572. r.fieldsInfoCache = make(map[reflect.Type]*reflectFieldsInfo)
  573. }
  574. r.fieldsInfoCache[t] = info
  575. }
  576. return
  577. }
  578. func (r *Runtime) methodsInfo(t reflect.Type) (info *reflectMethodsInfo) {
  579. var exists bool
  580. if info, exists = r.methodsInfoCache[t]; !exists {
  581. info = r.buildMethodsInfo(t)
  582. if r.methodsInfoCache == nil {
  583. r.methodsInfoCache = make(map[reflect.Type]*reflectMethodsInfo)
  584. }
  585. r.methodsInfoCache[t] = info
  586. }
  587. return
  588. }
  589. // SetFieldNameMapper sets a custom field name mapper for Go types. It can be called at any time, however
  590. // the mapping for any given value is fixed at the point of creation.
  591. // Setting this to nil restores the default behaviour which is all exported fields and methods are mapped to their
  592. // original unchanged names.
  593. func (r *Runtime) SetFieldNameMapper(mapper FieldNameMapper) {
  594. r.fieldNameMapper = mapper
  595. r.fieldsInfoCache = nil
  596. r.methodsInfoCache = nil
  597. }
  598. // TagFieldNameMapper returns a FieldNameMapper that uses the given tagName for struct fields and optionally
  599. // uncapitalises (making the first letter lower case) method names.
  600. // The common tag value syntax is supported (name[,options]), however options are ignored.
  601. // Setting name to anything other than a valid ECMAScript identifier makes the field hidden.
  602. func TagFieldNameMapper(tagName string, uncapMethods bool) FieldNameMapper {
  603. return tagFieldNameMapper{
  604. tagName: tagName,
  605. uncapMethods: uncapMethods,
  606. }
  607. }
  608. // UncapFieldNameMapper returns a FieldNameMapper that uncapitalises struct field and method names
  609. // making the first letter lower case.
  610. func UncapFieldNameMapper() FieldNameMapper {
  611. return uncapFieldNameMapper{}
  612. }