create-prefix-transform-stream.js 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. /**
  2. * @module create-prefix-transform-stream
  3. * @author Toru Nagashima
  4. * @copyright 2016 Toru Nagashima. All rights reserved.
  5. * See LICENSE file in root directory for full license.
  6. */
  7. 'use strict'
  8. // ------------------------------------------------------------------------------
  9. // Requirements
  10. // ------------------------------------------------------------------------------
  11. const stream = require('stream')
  12. // ------------------------------------------------------------------------------
  13. // Helpers
  14. // ------------------------------------------------------------------------------
  15. const ALL_BR = /\n/g
  16. /**
  17. * The transform stream to insert a specific prefix.
  18. *
  19. * Several streams can exist for the same output stream.
  20. * This stream will insert the prefix if the last output came from other instance.
  21. * To do that, this stream is using a shared state object.
  22. *
  23. * @private
  24. */
  25. class PrefixTransform extends stream.Transform {
  26. /**
  27. * @param {string} prefix - A prefix text to be inserted.
  28. * @param {object} state - A state object.
  29. * @param {string} state.lastPrefix - The last prefix which is printed.
  30. * @param {boolean} state.lastIsLinebreak -The flag to check whether the last output is a line break or not.
  31. */
  32. constructor (prefix, state) {
  33. super()
  34. this.prefix = prefix
  35. this.state = state
  36. }
  37. /**
  38. * Transforms the output chunk.
  39. *
  40. * @param {string|Buffer} chunk - A chunk to be transformed.
  41. * @param {string} _encoding - The encoding of the chunk.
  42. * @param {function} callback - A callback function that is called when done.
  43. * @returns {void}
  44. */
  45. _transform (chunk, _encoding, callback) {
  46. const prefix = this.prefix
  47. const nPrefix = `\n${prefix}`
  48. const state = this.state
  49. const firstPrefix =
  50. state.lastIsLinebreak
  51. ? prefix
  52. : (state.lastPrefix !== prefix)
  53. ? '\n'
  54. : ''
  55. const prefixed = `${firstPrefix}${chunk}`.replace(ALL_BR, nPrefix)
  56. const index = prefixed.indexOf(prefix, Math.max(0, prefixed.length - prefix.length))
  57. state.lastPrefix = prefix
  58. state.lastIsLinebreak = (index !== -1)
  59. callback(null, (index !== -1) ? prefixed.slice(0, index) : prefixed)
  60. }
  61. }
  62. // ------------------------------------------------------------------------------
  63. // Public API
  64. // ------------------------------------------------------------------------------
  65. /**
  66. * Create a transform stream to insert the specific prefix.
  67. *
  68. * Several streams can exist for the same output stream.
  69. * This stream will insert the prefix if the last output came from other instance.
  70. * To do that, this stream is using a shared state object.
  71. *
  72. * @param {string} prefix - A prefix text to be inserted.
  73. * @param {object} state - A state object.
  74. * @param {string} state.lastPrefix - The last prefix which is printed.
  75. * @param {boolean} state.lastIsLinebreak -The flag to check whether the last output is a line break or not.
  76. * @returns {stream.Transform} The created transform stream.
  77. */
  78. module.exports = function createPrefixTransform (prefix, state) {
  79. return new PrefixTransform(prefix, state)
  80. }