pre_commit_hooks/validate_TODO.js
/**
 * Ensure that all TODOs are in the correct format
 *
 * @returns non-zero when any changed file
 */
Ensure that all TODOs are in the correct format
@returns non-zero when any changed file
Ensure that all TODOs are in the correct format @returns non - zero when any changed file
function main() {
  const showAll = process.argv.includes(SHOW_ALL);
  const files = process.argv.slice(1).filter((arg) => arg !== SHOW_ALL);
  let filesChanged = false;
  const changeSummary = [];
  files.forEach((file) => {
    let status; 
    try {
      const todoRegex =
        /((\/\/|\*)[ \t]*TODO)[:\-—]?[ \t]*\(?[ \t]*(https?:\/\/\S+(?<!([:\-—)])))[ \t]*\)?[ \t]*(:|[-—]+[ \t])?[ \t]*(.*?)[ \t]*(\*\/)?$/gm;
      const contents = fs.readFileSync(file).toString('utf-8');
      let matches = todoRegex.exec(contents);
      let replaced = contents;
      let offset = 0;
      while (matches) {
        const TODO_INDEX = 1;
        const LINK_INDEX = 3;
        const COMMENT_INDEX = 6;
        const CLOSE_COMMENT_INDEX = 7;
        const swappedTodo = [
          `${matches[TODO_INDEX]}:`,
          matches[LINK_INDEX],
          `${
            matches[COMMENT_INDEX].replace(/[-—]/g, '').trim()
              ? `- ${matches[COMMENT_INDEX]}`
              : ''
          }`,
          matches[CLOSE_COMMENT_INDEX],
        ]
          .filter((part) => part)
          .join(' ');
        replaced =
          replaced.substring(0, matches.index + offset) +
          swappedTodo +
          replaced.substring(matches.index + matches[0].length + offset);
        offset += swappedTodo.length - matches[0].length;
        matches = todoRegex.exec(contents);
      }
      if (contents !== replaced) {
        filesChanged = true;
        status = 'Changed';
        fs.writeFileSync(file, replaced);
      }
    } catch (e) {
      status = `Error: ${e.message}`;
      console.error(`Error evaluating "${file}":`, e);
    } finally {
      if (status || showAll) {
        changeSummary.push({ file, status });
      }
    }
  });
  if (filesChanged) {
    console.table(changeSummary);
  }
  return filesChanged ? 1 : 0;
}
function main ( ) { const showAll = process . argv . includes ( SHOW_ALL ) ; const files = process . argv . slice ( 1 ) . filter ( ( arg ) => arg !== SHOW_ALL ) ; let filesChanged = false ; const changeSummary = [ ] ; files . forEach ( ( file ) => { let status ; try { const todoRegex = / ((\/\/|\*)[ \t]*TODO)[:\-—]?[ \t]*\(?[ \t]*(https?:\/\/\S+(?<!([:\-—)])))[ \t]*\)?[ \t]*(:|[-—]+[ \t])?[ \t]*(.*?)[ \t]*(\*\/)?$/gm; const contents = fs . readFileSync ( file ) . toString ( 'utf-8' ) ; let matches = todoRegex . exec ( contents ) ; let replaced = contents ; let offset = 0 ; while ( matches ) { const TODO_INDEX = 1 ; const LINK_INDEX = 3 ; const COMMENT_INDEX = 6 ; const CLOSE_COMMENT_INDEX = 7 ; const swappedTodo = [ ` ${ matches [ TODO_INDEX ] } ` , matches [ LINK_INDEX ] , ` ${ matches [ COMMENT_INDEX ] . replace ( / [-—]/g , ' ). t r im() ? ` ${ matches [ COMMENT_INDEX ] } ` : '' } ` , matches [ CLOSE_COMMENT_INDEX ] , ] . filter ( ( part ) => part ) . join ( ' ' ) ; replaced = replaced . substring ( 0 , matches . index + offset ) + swappedTodo + replaced . substring ( matches . index + matches [ 0 ] . length + offset ) ; offset += swappedTodo . length - matches [ 0 ] . length ; matches = todoRegex . exec ( contents ) ; } if ( contents !== replaced ) { filesChanged = true ; status = 'Changed' ; fs . writeFileSync ( file , replaced ) ; } } catch ( e ) { status = ` ${ e . message } ` ; console . error ( ` ${ file } ` , e ) ; } finally { if ( status || showAll ) { changeSummary . push ( { file , status } ) ; } } } ) ; if ( filesChanged ) { console . table ( changeSummary ) ; } return filesChanged ? 1 : 0 ; }
Ensure that all TODOs are in the correct format
 @returns non-zero when any changed file
Ensure that all TODOs are in the correct format @returns non - zero when any changed file
// get the files passed in from pre-commit // leave status undefined in skip case for better color highlighting // finds todos in non-standard formats // eslint-disable-next-line max-len // keep track of the indices as they change // indexes corresponding to parts of the regex // update the offset with the change in length // return non-zero if anything changed