utils.tsx 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import {LocationRange} from 'pegjs';
  2. import {Token, TokenConverter, TokenResult} from './parser';
  3. /**
  4. * Utility function to visit every Token node within an AST tree and apply
  5. * a transform to those nodes.
  6. */
  7. export function treeTransformer(
  8. tree: TokenResult<Token>[],
  9. transform: (token: TokenResult<Token>) => any
  10. ) {
  11. const nodeVisitor = (token: TokenResult<Token>) => {
  12. switch (token.type) {
  13. case Token.Filter:
  14. return transform({
  15. ...token,
  16. key: nodeVisitor(token.key),
  17. value: nodeVisitor(token.value),
  18. });
  19. case Token.KeyExplicitTag:
  20. return transform({
  21. ...token,
  22. key: nodeVisitor(token.key),
  23. });
  24. case Token.KeyAggregate:
  25. return transform({
  26. ...token,
  27. name: nodeVisitor(token.name),
  28. args: token.args ? nodeVisitor(token.args) : token.args,
  29. argsSpaceBefore: nodeVisitor(token.argsSpaceBefore),
  30. argsSpaceAfter: nodeVisitor(token.argsSpaceAfter),
  31. });
  32. case Token.LogicGroup:
  33. return transform({
  34. ...token,
  35. inner: token.inner.map(nodeVisitor),
  36. });
  37. case Token.KeyAggregateArgs:
  38. return transform({
  39. ...token,
  40. args: token.args.map(v => ({...v, value: nodeVisitor(v.value)})),
  41. });
  42. case Token.ValueNumberList:
  43. case Token.ValueTextList:
  44. return transform({
  45. ...token,
  46. // TODO(ts): Not sure why `v` cannot be inferred here
  47. items: token.items.map((v: any) => ({...v, value: nodeVisitor(v.value)})),
  48. });
  49. default:
  50. return transform(token);
  51. }
  52. };
  53. return tree.map(nodeVisitor);
  54. }
  55. type GetKeyNameOpts = {
  56. /**
  57. * Include arguments in aggregate key names
  58. */
  59. aggregateWithArgs?: boolean;
  60. };
  61. /**
  62. * Utility to get the string name of any type of key.
  63. */
  64. export const getKeyName = (
  65. key: ReturnType<
  66. TokenConverter['tokenKeySimple' | 'tokenKeyExplicitTag' | 'tokenKeyAggregate']
  67. >,
  68. options: GetKeyNameOpts = {}
  69. ) => {
  70. const {aggregateWithArgs} = options;
  71. switch (key.type) {
  72. case Token.KeySimple:
  73. return key.value;
  74. case Token.KeyExplicitTag:
  75. return key.key.value;
  76. case Token.KeyAggregate:
  77. return aggregateWithArgs
  78. ? `${key.name.value}(${key.args ? key.args.text : ''})`
  79. : key.name.value;
  80. default:
  81. return '';
  82. }
  83. };
  84. export function isWithinToken(node: {location: LocationRange}, position: number) {
  85. return position >= node.location.start.offset && position <= node.location.end.offset;
  86. }