macros.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. package macro
  2. import (
  3. "strconv"
  4. "strings"
  5. "github.com/kataras/iris/macro/interpreter/ast"
  6. )
  7. var (
  8. // String type
  9. // Allows anything (single path segment, as everything except the `Path`).
  10. // Its functions can be used by the rest of the macros and param types whenever not available function by name is used.
  11. // Because of its "master" boolean value to true (third parameter).
  12. String = NewMacro("string", "", true, false, nil).
  13. RegisterFunc("regexp", MustRegexp).
  14. // checks if param value starts with the 'prefix' arg
  15. RegisterFunc("prefix", func(prefix string) func(string) bool {
  16. return func(paramValue string) bool {
  17. return strings.HasPrefix(paramValue, prefix)
  18. }
  19. }).
  20. // checks if param value ends with the 'suffix' arg
  21. RegisterFunc("suffix", func(suffix string) func(string) bool {
  22. return func(paramValue string) bool {
  23. return strings.HasSuffix(paramValue, suffix)
  24. }
  25. }).
  26. // checks if param value contains the 's' arg
  27. RegisterFunc("contains", func(s string) func(string) bool {
  28. return func(paramValue string) bool {
  29. return strings.Contains(paramValue, s)
  30. }
  31. }).
  32. // checks if param value's length is at least 'min'
  33. RegisterFunc("min", func(min int) func(string) bool {
  34. return func(paramValue string) bool {
  35. return len(paramValue) >= min
  36. }
  37. }).
  38. // checks if param value's length is not bigger than 'max'
  39. RegisterFunc("max", func(max int) func(string) bool {
  40. return func(paramValue string) bool {
  41. return max >= len(paramValue)
  42. }
  43. })
  44. simpleNumberEval = MustRegexp("^-?[0-9]+$")
  45. // Int or number type
  46. // both positive and negative numbers, actual value can be min-max int64 or min-max int32 depends on the arch.
  47. // If x64: -9223372036854775808 to 9223372036854775807.
  48. // If x32: -2147483648 to 2147483647 and etc..
  49. Int = NewMacro("int", "number", false, false, func(paramValue string) (interface{}, bool) {
  50. if !simpleNumberEval(paramValue) {
  51. return nil, false
  52. }
  53. v, err := strconv.Atoi(paramValue)
  54. if err != nil {
  55. return nil, false
  56. }
  57. return v, true
  58. }).
  59. // checks if the param value's int representation is
  60. // bigger or equal than 'min'
  61. RegisterFunc("min", func(min int) func(int) bool {
  62. return func(paramValue int) bool {
  63. return paramValue >= min
  64. }
  65. }).
  66. // checks if the param value's int representation is
  67. // smaller or equal than 'max'.
  68. RegisterFunc("max", func(max int) func(int) bool {
  69. return func(paramValue int) bool {
  70. return paramValue <= max
  71. }
  72. }).
  73. // checks if the param value's int representation is
  74. // between min and max, including 'min' and 'max'.
  75. RegisterFunc("range", func(min, max int) func(int) bool {
  76. return func(paramValue int) bool {
  77. return !(paramValue < min || paramValue > max)
  78. }
  79. })
  80. // Int8 type
  81. // -128 to 127.
  82. Int8 = NewMacro("int8", "", false, false, func(paramValue string) (interface{}, bool) {
  83. if !simpleNumberEval(paramValue) {
  84. return nil, false
  85. }
  86. v, err := strconv.ParseInt(paramValue, 10, 8)
  87. if err != nil {
  88. return nil, false
  89. }
  90. return int8(v), true
  91. }).
  92. RegisterFunc("min", func(min int8) func(int8) bool {
  93. return func(paramValue int8) bool {
  94. return paramValue >= min
  95. }
  96. }).
  97. RegisterFunc("max", func(max int8) func(int8) bool {
  98. return func(paramValue int8) bool {
  99. return paramValue <= max
  100. }
  101. }).
  102. RegisterFunc("range", func(min, max int8) func(int8) bool {
  103. return func(paramValue int8) bool {
  104. return !(paramValue < min || paramValue > max)
  105. }
  106. })
  107. // Int16 type
  108. // -32768 to 32767.
  109. Int16 = NewMacro("int16", "", false, false, func(paramValue string) (interface{}, bool) {
  110. if !simpleNumberEval(paramValue) {
  111. return nil, false
  112. }
  113. v, err := strconv.ParseInt(paramValue, 10, 16)
  114. if err != nil {
  115. return nil, false
  116. }
  117. return int16(v), true
  118. }).
  119. RegisterFunc("min", func(min int16) func(int16) bool {
  120. return func(paramValue int16) bool {
  121. return paramValue >= min
  122. }
  123. }).
  124. RegisterFunc("max", func(max int16) func(int16) bool {
  125. return func(paramValue int16) bool {
  126. return paramValue <= max
  127. }
  128. }).
  129. RegisterFunc("range", func(min, max int16) func(int16) bool {
  130. return func(paramValue int16) bool {
  131. return !(paramValue < min || paramValue > max)
  132. }
  133. })
  134. // Int32 type
  135. // -2147483648 to 2147483647.
  136. Int32 = NewMacro("int32", "", false, false, func(paramValue string) (interface{}, bool) {
  137. if !simpleNumberEval(paramValue) {
  138. return nil, false
  139. }
  140. v, err := strconv.ParseInt(paramValue, 10, 32)
  141. if err != nil {
  142. return nil, false
  143. }
  144. return int32(v), true
  145. }).
  146. RegisterFunc("min", func(min int32) func(int32) bool {
  147. return func(paramValue int32) bool {
  148. return paramValue >= min
  149. }
  150. }).
  151. RegisterFunc("max", func(max int32) func(int32) bool {
  152. return func(paramValue int32) bool {
  153. return paramValue <= max
  154. }
  155. }).
  156. RegisterFunc("range", func(min, max int32) func(int32) bool {
  157. return func(paramValue int32) bool {
  158. return !(paramValue < min || paramValue > max)
  159. }
  160. })
  161. // Int64 as int64 type
  162. // -9223372036854775808 to 9223372036854775807.
  163. Int64 = NewMacro("int64", "long", false, false, func(paramValue string) (interface{}, bool) {
  164. if !simpleNumberEval(paramValue) {
  165. return nil, false
  166. }
  167. v, err := strconv.ParseInt(paramValue, 10, 64)
  168. if err != nil { // if err == strconv.ErrRange...
  169. return nil, false
  170. }
  171. return v, true
  172. }).
  173. // checks if the param value's int64 representation is
  174. // bigger or equal than 'min'.
  175. RegisterFunc("min", func(min int64) func(int64) bool {
  176. return func(paramValue int64) bool {
  177. return paramValue >= min
  178. }
  179. }).
  180. // checks if the param value's int64 representation is
  181. // smaller or equal than 'max'.
  182. RegisterFunc("max", func(max int64) func(int64) bool {
  183. return func(paramValue int64) bool {
  184. return paramValue <= max
  185. }
  186. }).
  187. // checks if the param value's int64 representation is
  188. // between min and max, including 'min' and 'max'.
  189. RegisterFunc("range", func(min, max int64) func(int64) bool {
  190. return func(paramValue int64) bool {
  191. return !(paramValue < min || paramValue > max)
  192. }
  193. })
  194. // Uint as uint type
  195. // actual value can be min-max uint64 or min-max uint32 depends on the arch.
  196. // If x64: 0 to 18446744073709551615.
  197. // If x32: 0 to 4294967295 and etc.
  198. Uint = NewMacro("uint", "", false, false, func(paramValue string) (interface{}, bool) {
  199. v, err := strconv.ParseUint(paramValue, 10, strconv.IntSize) // 32,64...
  200. if err != nil {
  201. return nil, false
  202. }
  203. return uint(v), true
  204. }).
  205. // checks if the param value's int representation is
  206. // bigger or equal than 'min'
  207. RegisterFunc("min", func(min uint) func(uint) bool {
  208. return func(paramValue uint) bool {
  209. return paramValue >= min
  210. }
  211. }).
  212. // checks if the param value's int representation is
  213. // smaller or equal than 'max'.
  214. RegisterFunc("max", func(max uint) func(uint) bool {
  215. return func(paramValue uint) bool {
  216. return paramValue <= max
  217. }
  218. }).
  219. // checks if the param value's int representation is
  220. // between min and max, including 'min' and 'max'.
  221. RegisterFunc("range", func(min, max uint) func(uint) bool {
  222. return func(paramValue uint) bool {
  223. return !(paramValue < min || paramValue > max)
  224. }
  225. })
  226. uint8Eval = MustRegexp("^([0-9]|[1-8][0-9]|9[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$")
  227. // Uint8 as uint8 type
  228. // 0 to 255.
  229. Uint8 = NewMacro("uint8", "", false, false, func(paramValue string) (interface{}, bool) {
  230. if !uint8Eval(paramValue) {
  231. return nil, false
  232. }
  233. v, err := strconv.ParseUint(paramValue, 10, 8)
  234. if err != nil {
  235. return nil, false
  236. }
  237. return uint8(v), true
  238. }).
  239. // checks if the param value's uint8 representation is
  240. // bigger or equal than 'min'.
  241. RegisterFunc("min", func(min uint8) func(uint8) bool {
  242. return func(paramValue uint8) bool {
  243. return paramValue >= min
  244. }
  245. }).
  246. // checks if the param value's uint8 representation is
  247. // smaller or equal than 'max'.
  248. RegisterFunc("max", func(max uint8) func(uint8) bool {
  249. return func(paramValue uint8) bool {
  250. return paramValue <= max
  251. }
  252. }).
  253. // checks if the param value's uint8 representation is
  254. // between min and max, including 'min' and 'max'.
  255. RegisterFunc("range", func(min, max uint8) func(uint8) bool {
  256. return func(paramValue uint8) bool {
  257. return !(paramValue < min || paramValue > max)
  258. }
  259. })
  260. // Uint16 as uint16 type
  261. // 0 to 65535.
  262. Uint16 = NewMacro("uint16", "", false, false, func(paramValue string) (interface{}, bool) {
  263. v, err := strconv.ParseUint(paramValue, 10, 16)
  264. if err != nil {
  265. return nil, false
  266. }
  267. return uint16(v), true
  268. }).
  269. RegisterFunc("min", func(min uint16) func(uint16) bool {
  270. return func(paramValue uint16) bool {
  271. return paramValue >= min
  272. }
  273. }).
  274. RegisterFunc("max", func(max uint16) func(uint16) bool {
  275. return func(paramValue uint16) bool {
  276. return paramValue <= max
  277. }
  278. }).
  279. RegisterFunc("range", func(min, max uint16) func(uint16) bool {
  280. return func(paramValue uint16) bool {
  281. return !(paramValue < min || paramValue > max)
  282. }
  283. })
  284. // Uint32 as uint32 type
  285. // 0 to 4294967295.
  286. Uint32 = NewMacro("uint32", "", false, false, func(paramValue string) (interface{}, bool) {
  287. v, err := strconv.ParseUint(paramValue, 10, 32)
  288. if err != nil {
  289. return nil, false
  290. }
  291. return uint32(v), true
  292. }).
  293. RegisterFunc("min", func(min uint32) func(uint32) bool {
  294. return func(paramValue uint32) bool {
  295. return paramValue >= min
  296. }
  297. }).
  298. RegisterFunc("max", func(max uint32) func(uint32) bool {
  299. return func(paramValue uint32) bool {
  300. return paramValue <= max
  301. }
  302. }).
  303. RegisterFunc("range", func(min, max uint32) func(uint32) bool {
  304. return func(paramValue uint32) bool {
  305. return !(paramValue < min || paramValue > max)
  306. }
  307. })
  308. // Uint64 as uint64 type
  309. // 0 to 18446744073709551615.
  310. Uint64 = NewMacro("uint64", "", false, false, func(paramValue string) (interface{}, bool) {
  311. v, err := strconv.ParseUint(paramValue, 10, 64)
  312. if err != nil {
  313. return nil, false
  314. }
  315. return v, true
  316. }).
  317. // checks if the param value's uint64 representation is
  318. // bigger or equal than 'min'.
  319. RegisterFunc("min", func(min uint64) func(uint64) bool {
  320. return func(paramValue uint64) bool {
  321. return paramValue >= min
  322. }
  323. }).
  324. // checks if the param value's uint64 representation is
  325. // smaller or equal than 'max'.
  326. RegisterFunc("max", func(max uint64) func(uint64) bool {
  327. return func(paramValue uint64) bool {
  328. return paramValue <= max
  329. }
  330. }).
  331. // checks if the param value's uint64 representation is
  332. // between min and max, including 'min' and 'max'.
  333. RegisterFunc("range", func(min, max uint64) func(uint64) bool {
  334. return func(paramValue uint64) bool {
  335. return !(paramValue < min || paramValue > max)
  336. }
  337. })
  338. // Bool or boolean as bool type
  339. // a string which is "1" or "t" or "T" or "TRUE" or "true" or "True"
  340. // or "0" or "f" or "F" or "FALSE" or "false" or "False".
  341. Bool = NewMacro("bool", "boolean", false, false, func(paramValue string) (interface{}, bool) {
  342. // a simple if statement is faster than regex ^(true|false|True|False|t|0|f|FALSE|TRUE)$
  343. // in this case.
  344. v, err := strconv.ParseBool(paramValue)
  345. if err != nil {
  346. return nil, false
  347. }
  348. return v, true
  349. })
  350. alphabeticalEval = MustRegexp("^[a-zA-Z ]+$")
  351. // Alphabetical letter type
  352. // letters only (upper or lowercase)
  353. Alphabetical = NewMacro("alphabetical", "", false, false, func(paramValue string) (interface{}, bool) {
  354. if !alphabeticalEval(paramValue) {
  355. return nil, false
  356. }
  357. return paramValue, true
  358. })
  359. fileEval = MustRegexp("^[a-zA-Z0-9_.-]*$")
  360. // File type
  361. // letters (upper or lowercase)
  362. // numbers (0-9)
  363. // underscore (_)
  364. // dash (-)
  365. // point (.)
  366. // no spaces! or other character
  367. File = NewMacro("file", "", false, false, func(paramValue string) (interface{}, bool) {
  368. if !fileEval(paramValue) {
  369. return nil, false
  370. }
  371. return paramValue, true
  372. })
  373. // Path type
  374. // anything, should be the last part
  375. //
  376. // It allows everything, we have String and Path as different
  377. // types because I want to give the opportunity to the user
  378. // to organise the macro functions based on wildcard or single dynamic named path parameter.
  379. // Should be living in the latest path segment of a route path.
  380. Path = NewMacro("path", "", false, true, nil)
  381. // Defaults contains the defaults macro and parameters types for the router.
  382. //
  383. // Read https://github.com/kataras/iris/tree/master/_examples/routing/macros for more details.
  384. Defaults = &Macros{
  385. String,
  386. Int,
  387. Int8,
  388. Int16,
  389. Int32,
  390. Int64,
  391. Uint,
  392. Uint8,
  393. Uint16,
  394. Uint32,
  395. Uint64,
  396. Bool,
  397. Alphabetical,
  398. File,
  399. Path,
  400. }
  401. )
  402. // Macros is just a type of a slice of *Macro
  403. // which is responsible to register and search for macros based on the indent(parameter type).
  404. type Macros []*Macro
  405. // Register registers a custom Macro.
  406. // The "indent" should not be empty and should be unique, it is the parameter type's name, i.e "string".
  407. // The "alias" is optionally and it should be unique, it is the alias of the parameter type.
  408. // "isMaster" and "isTrailing" is for default parameter type and wildcard respectfully.
  409. // The "evaluator" is the function that is converted to an Iris handler which is executed every time
  410. // before the main chain of a route's handlers that contains this macro of the specific parameter type.
  411. //
  412. // Read https://github.com/kataras/iris/tree/master/_examples/routing/macros for more details.
  413. func (ms *Macros) Register(indent, alias string, isMaster, isTrailing bool, evaluator ParamEvaluator) *Macro {
  414. macro := NewMacro(indent, alias, isMaster, isTrailing, evaluator)
  415. if ms.register(macro) {
  416. return macro
  417. }
  418. return nil
  419. }
  420. func (ms *Macros) register(macro *Macro) bool {
  421. if macro.Indent() == "" {
  422. return false
  423. }
  424. cp := *ms
  425. for _, m := range cp {
  426. // can't add more than one with the same ast characteristics.
  427. if macro.Indent() == m.Indent() {
  428. return false
  429. }
  430. if alias := macro.Alias(); alias != "" {
  431. if alias == m.Alias() || alias == m.Indent() {
  432. return false
  433. }
  434. }
  435. if macro.Master() && m.Master() {
  436. return false
  437. }
  438. }
  439. cp = append(cp, macro)
  440. *ms = cp
  441. return true
  442. }
  443. // Unregister removes a macro and its parameter type from the list.
  444. func (ms *Macros) Unregister(indent string) bool {
  445. cp := *ms
  446. for i, m := range cp {
  447. if m.Indent() == indent {
  448. copy(cp[i:], cp[i+1:])
  449. cp[len(cp)-1] = nil
  450. cp = cp[:len(cp)-1]
  451. *ms = cp
  452. return true
  453. }
  454. }
  455. return false
  456. }
  457. // Lookup returns the responsible macro for a parameter type, it can return nil.
  458. func (ms *Macros) Lookup(pt ast.ParamType) *Macro {
  459. if m := ms.Get(pt.Indent()); m != nil {
  460. return m
  461. }
  462. if alias, has := ast.HasAlias(pt); has {
  463. if m := ms.Get(alias); m != nil {
  464. return m
  465. }
  466. }
  467. return nil
  468. }
  469. // Get returns the responsible macro for a parameter type, it can return nil.
  470. func (ms *Macros) Get(indentOrAlias string) *Macro {
  471. if indentOrAlias == "" {
  472. return nil
  473. }
  474. for _, m := range *ms {
  475. if m.Indent() == indentOrAlias {
  476. return m
  477. }
  478. if m.Alias() == indentOrAlias {
  479. return m
  480. }
  481. }
  482. return nil
  483. }
  484. // GetMaster returns the default macro and its parameter type,
  485. // by default it will return the `String` macro which is responsible for the "string" parameter type.
  486. func (ms *Macros) GetMaster() *Macro {
  487. for _, m := range *ms {
  488. if m.Master() {
  489. return m
  490. }
  491. }
  492. return nil
  493. }
  494. // GetTrailings returns the macros that have support for wildcards parameter types.
  495. // By default it will return the `Path` macro which is responsible for the "path" parameter type.
  496. func (ms *Macros) GetTrailings() (macros []*Macro) {
  497. for _, m := range *ms {
  498. if m.Trailing() {
  499. macros = append(macros, m)
  500. }
  501. }
  502. return
  503. }