MediaWiki  master
MWDoxygenFilter.php
Go to the documentation of this file.
1 <?php
48 class MWDoxygenFilter {
53  public static function filter( $source ) {
54  $tokens = token_get_all( $source );
55  $buffer = null;
56  $output = '';
57  foreach ( $tokens as $token ) {
58  if ( is_string( $token ) ) {
59  if ( $buffer !== null && $token === ';' ) {
60  // If we still have a buffer and the statement has ended,
61  // flush it and move on.
62  $output .= $buffer['raw'];
63  $buffer = null;
64  }
65  $output .= $token;
66  continue;
67  }
68  list( $id, $content ) = $token;
69  switch ( $id ) {
70  case T_DOC_COMMENT:
71  // Escape slashes so that references to namespaces are not
72  // wrongly interpreted as a Doxygen "\command".
73  $content = addcslashes( $content, '\\' );
74  // Look for instances of "@var SomeType".
75  if ( preg_match( '#@var\s+\S+#s', $content ) ) {
76  $buffer = [ 'raw' => $content, 'desc' => null, 'type' => null, 'name' => null ];
77  $buffer['desc'] = preg_replace_callback(
78  // Strip "@var SomeType" part, but remember the type and optional name
79  '#@var\s+(\S+)(\s+)?(\S+)?#s',
80  static function ( $matches ) use ( &$buffer ) {
81  $buffer['type'] = $matches[1];
82  $buffer['name'] = $matches[3] ?? null;
83  return ( $matches[2] ?? '' ) . ( $matches[3] ?? '' );
84  },
85  $content
86  );
87  } else {
88  $output .= $content;
89  }
90  break;
91 
92  case T_VARIABLE:
93  // Doxygen requires class members to be documented in one of two ways:
94  //
95  // 1. Fully qualified:
96  // /** @var SomeType $name Description here. */
97  //
98  // These result in the creation of a new virtual node called $name
99  // with the specified type and description. The real code doesn't
100  // even need to exist in this case.
101  //
102  // 2. Contextual:
103  // /** Description here. */
104  // private SomeType? $name;
105  //
106  // In MediaWiki, we are mostly like #1 but without the name repeated:
107  // /** @var SomeType Description here. */
108  // private $name;
109  //
110  // These emit a warning in Doxygen because they are missing a variable name.
111  // Convert these to the "Contextual" kind by stripping ""@var", injecting
112  // type into the code, and leaving the description in-place.
113  if ( $buffer !== null ) {
114  if ( $buffer['name'] === $content ) {
115  // Fully qualitied "@var" comment, leave as-is.
116  $output .= $buffer['raw'];
117  $output .= $content;
118  } else {
119  // MW-style "@var" comment. Keep only the description and transplant
120  // the type into the code.
121  $output .= $buffer['desc'];
122  $output .= "{$buffer['type']} $content";
123  }
124  $buffer = null;
125  } else {
126  $output .= $content;
127  }
128  break;
129 
130  default:
131  if ( $buffer !== null ) {
132  $buffer['raw'] .= $content;
133  $buffer['desc'] .= $content;
134  } else {
135  $output .= $content;
136  }
137  break;
138  }
139  }
140  return $output;
141  }
142 }
$matches
$source
$content
Definition: router.php:76