validate-code-name-strict.js 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. /**
  2. * Module dependencies
  3. */
  4. var X_INVALID_CHARACTERS_IN_ECMA51_VARNAME = require('./X_INVALID_CHARACTERS_IN_ECMA51_VARNAME');
  5. var X_INVALID_FIRST_CHARACTER = require('./X_INVALID_FIRST_CHARACTER');
  6. /**
  7. * Strictly validate a string as the "code name" for an input or exit.
  8. *
  9. * @param {String} codeName
  10. * The source string to check.
  11. *
  12. * @returns {String?} [reason]
  13. * If `codeName` is not a valid input or exit code name, then this returns a reason string.
  14. * Otherwise, it returns `undefined`.
  15. *
  16. * Note: The "reason string" returned will always be in a format such that it can
  17. * be concatenated onto the end of something like "Hey that's not ok, because it {{…}}."
  18. * It will not have ending punctuation.
  19. */
  20. module.exports = function validateCodeNameStrict(codeName){
  21. // Verify that `codeName` is a non-empty string.
  22. if (!codeName || typeof codeName !== 'string') {
  23. return 'must be a non-empty string';
  24. }//•
  25. // Verify that `codeName` doesn't have any invalid characters.
  26. if (codeName.match(X_INVALID_CHARACTERS_IN_ECMA51_VARNAME)){
  27. return 'contains invalid characters';
  28. }//•
  29. // Verify `codeName` doesn't start with a character which is not a letter, "_", or "$".
  30. // (NOTE: ECMA5.1 is actually more permissive than this, i.e. you can use weird
  31. // unicode characters, but we're preventing that here. Because... cm'on, really?)
  32. if (codeName.match(X_INVALID_FIRST_CHARACTER)){
  33. return 'starts with an invalid character';
  34. }//•
  35. // Check to make sure this isn't anything particularly nasty.
  36. if (
  37. // • Deferred methods:
  38. codeName === 'exec' ||
  39. codeName === 'then' ||
  40. codeName === 'catch' ||
  41. codeName === 'toPromise' ||
  42. // • the standard JavaScript object flora:
  43. codeName === '__defineGetter__' ||
  44. codeName === '__defineSetter__' ||
  45. codeName === '__lookupGetter__' ||
  46. codeName === '__lookupSetter__' ||
  47. codeName === '__proto__' ||
  48. codeName === 'constructor' ||
  49. codeName === 'hasOwnProperty' ||
  50. codeName === 'isPrototypeOf' ||
  51. codeName === 'propertyIsEnumerable' ||
  52. codeName === 'toLocaleString' ||
  53. codeName === 'toString' ||
  54. codeName === 'valueOf' ||
  55. // • and things that are just going to end up being a really bad idea:
  56. // (or at the very least, which shouldn't be defined this way)
  57. codeName === 'prototype' ||
  58. codeName === 'toJSON' ||
  59. codeName === 'inspect'
  60. ) {
  61. return 'potentially collides with a reserved name in JavaScript (or this package)';
  62. }//•
  63. if (codeName === 'inputs' || codeName === 'exits') {
  64. return 'is potentially very confusing';
  65. }//•
  66. // Finally, one last check that's bitten several folks on GitHub in the past:
  67. if (codeName === 'length') {
  68. return 'could potentially cause your code to encounter hard-to-catch bugs related to array ducktyping';
  69. }//•
  70. // Otherwise, all's well.
  71. };