@@ -55,8 +55,8 @@ var sax = require('sax')
5555 * - generator {String}
5656 * - categories {Array}
5757 *
58- * @param { Object } options
59- * @api public
58+ * @this {FeedParserInstance}
59+ * @param { import('../../index').Options } [options]
6060 */
6161function FeedParser ( options ) {
6262 if ( ! ( this instanceof FeedParser ) ) return new FeedParser ( options ) ;
@@ -72,9 +72,13 @@ function FeedParser (options) {
7272 if ( ! ( 'normalize' in this . options ) ) this . options . normalize = true ;
7373 if ( ! ( 'addmeta' in this . options ) ) this . options . addmeta = true ;
7474 if ( ! ( 'resume_saxerror' in this . options ) ) this . options . resume_saxerror = true ;
75+ // MAX_BUFFER_LENGTH is not part of the public API of sax, but we need to be
76+ // able to handle nodes that are larger than the 64K default
7577 if ( 'MAX_BUFFER_LENGTH' in this . options ) {
78+ // @ts -expect-error - private API of sax
7679 sax . MAX_BUFFER_LENGTH = this . options . MAX_BUFFER_LENGTH ; // set to Infinity to have unlimited buffers
7780 } else {
81+ // @ts -expect-error
7882 sax . MAX_BUFFER_LENGTH = 16 * 1024 * 1024 ; // 16M versus the 64K default
7983 }
8084 if ( this . options . feedurl ) this . xmlbase . unshift ( { '#name' : 'xml' , '#' : this . options . feedurl } ) ;
@@ -96,6 +100,7 @@ util.inherits(FeedParser, TransformStream);
96100 *
97101 * Initializes the class-variables
98102 */
103+ /** @this {FeedParserInstance} */
99104FeedParser . prototype . init = function ( ) {
100105 this . meta = {
101106 '#ns' : [ ] ,
@@ -113,6 +118,7 @@ FeedParser.prototype.init = function (){
113118 this . errors = [ ] ;
114119} ;
115120
121+ /** @this {FeedParserInstance} */
116122FeedParser . prototype . handleEnd = function ( ) {
117123 // We made it to the end without throwing, but let's make sure we were actually
118124 // parsing a feed
@@ -123,26 +129,33 @@ FeedParser.prototype.handleEnd = function (){
123129 this . push ( null ) ;
124130} ;
125131
132+ /** @this {FeedParserInstance} */
126133FeedParser . prototype . handleSaxError = function ( e ) {
127134 this . emit ( 'error' , e ) ;
128135 if ( this . options . resume_saxerror ) {
129136 this . resumeSaxError ( ) ;
130137 }
131138} ;
132139
140+ /** @this {FeedParserInstance} */
133141FeedParser . prototype . resumeSaxError = function ( ) {
134142 if ( this . stream . _parser ) {
135143 this . stream . _parser . error = null ;
136144 this . stream . _parser . resume ( ) ;
137145 }
138146} ;
139147
148+ /** @this {FeedParserInstance} */
140149FeedParser . prototype . handleError = function ( e ) {
141150 this . emit ( 'error' , e ) ;
142151} ;
143152
144153// parses the xml declaration, which looks like:
145154// <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
155+ /**
156+ * @this {FeedParserInstance}
157+ * @param {SaxProcessingInstruction } node
158+ */
146159FeedParser . prototype . handleProcessingInstruction = function ( node ) {
147160 if ( node . name === 'xml' ) {
148161 this . meta [ '#xml' ] = node . body . trim ( ) . split ( / \s + / ) . reduce ( function ( map , attr ) {
@@ -155,6 +168,10 @@ FeedParser.prototype.handleProcessingInstruction = function (node) {
155168 }
156169} ;
157170
171+ /**
172+ * @this {FeedParserInstance}
173+ * @param {import('sax').QualifiedTag } node
174+ */
158175FeedParser . prototype . handleOpenTag = function ( node ) {
159176 var n = { } ;
160177 n [ '#name' ] = node . name ; // Avoid namespace collissions later...
@@ -204,6 +221,7 @@ FeedParser.prototype.handleOpenTag = function (node){
204221 this . stack . unshift ( n ) ;
205222} ;
206223
224+ /** @this {FeedParserInstance} */
207225FeedParser . prototype . handleCloseTag = function ( el ) {
208226 var node = {
209227 '#name' : el ,
@@ -355,6 +373,10 @@ FeedParser.prototype.handleCloseTag = function (el){
355373 }
356374} ;
357375
376+ /**
377+ * @this {FeedParserInstance}
378+ * @param {string } text
379+ */
358380FeedParser . prototype . handleText = function ( text ) {
359381 if ( this . in_xhtml ) {
360382 this . xhtml [ '#' ] += text ;
@@ -369,6 +391,12 @@ FeedParser.prototype.handleText = function (text){
369391 }
370392} ;
371393
394+ /**
395+ * @this {FeedParserInstance}
396+ * @param {Object.<string, import('sax').QualifiedAttribute> } attrs
397+ * @param {string } el
398+ * @returns {Object.<string, string> }
399+ */
372400FeedParser . prototype . handleAttributes = function handleAttributes ( attrs , el ) {
373401 /*
374402 * Using the sax.js option { xmlns: true }
@@ -382,14 +410,14 @@ FeedParser.prototype.handleAttributes = function handleAttributes (attrs, el) {
382410 */
383411
384412 var basepath = ''
385- , simplifiedAttributes = { }
413+ , simplifiedAttributes = /** @type { Object.<string, string> } */ ( { } )
386414 ;
387415
388416 if ( this . xmlbase && this . xmlbase . length ) {
389417 basepath = this . xmlbase [ 0 ] [ '#' ] ;
390418 }
391419
392- Object . keys ( attrs ) . forEach ( function ( key ) {
420+ Object . keys ( attrs ) . forEach ( /** @this {FeedParserInstance} */ function ( key ) {
393421 var attr = attrs [ key ]
394422 , ns = { }
395423 , prefix = ''
@@ -425,6 +453,13 @@ FeedParser.prototype.handleAttributes = function handleAttributes (attrs, el) {
425453 return simplifiedAttributes ;
426454} ;
427455
456+ /**
457+ * @this {FeedParserInstance}
458+ * @param {ParsedNode } node
459+ * @param {import('../../index').Type } type
460+ * @param {import('../../index').Options } options
461+ * @returns {Object }
462+ */
428463FeedParser . prototype . handleMeta = function handleMeta ( node , type , options ) {
429464 if ( ! type || ! node ) return { } ;
430465
@@ -772,6 +807,13 @@ FeedParser.prototype.handleMeta = function handleMeta (node, type, options) {
772807 return meta ;
773808} ;
774809
810+ /**
811+ * @this {FeedParserInstance}
812+ * @param {ParsedNode } node
813+ * @param {import('../../index').Type } type
814+ * @param {import('../../index').Options } options
815+ * @returns {Object }
816+ */
775817FeedParser . prototype . handleItem = function handleItem ( node , type , options ) {
776818 if ( ! type || ! node ) return { } ;
777819
@@ -830,7 +872,7 @@ FeedParser.prototype.handleItem = function handleItem (node, type, options){
830872 if ( link [ '@' ] [ 'rel' ] == 'self' && ! item . link ) item . link = link [ '@' ] [ 'href' ] ;
831873 if ( link [ '@' ] [ 'rel' ] == 'replies' ) item . comments = link [ '@' ] [ 'href' ] ;
832874 if ( link [ '@' ] [ 'rel' ] == 'enclosure' ) {
833- enclosure = { } ;
875+ enclosure = /** @type { import('../../index').Enclosure } */ ( { } ) ;
834876 enclosure . url = link [ '@' ] [ 'href' ] ;
835877 enclosure . type = _ . get ( link [ '@' ] , 'type' ) ;
836878 enclosure . length = _ . get ( link [ '@' ] , 'length' ) ;
@@ -853,7 +895,7 @@ FeedParser.prototype.handleItem = function handleItem (node, type, options){
853895 if ( el [ '@' ] [ 'rel' ] == 'self' && ! item . link ) item . link = el [ '@' ] [ 'href' ] ;
854896 if ( el [ '@' ] [ 'rel' ] == 'replies' ) item . comments = el [ '@' ] [ 'href' ] ;
855897 if ( el [ '@' ] [ 'rel' ] == 'enclosure' ) {
856- enclosure = { } ;
898+ enclosure = /** @type { import('../../index').Enclosure } */ ( { } ) ;
857899 enclosure . url = el [ '@' ] [ 'href' ] ;
858900 enclosure . type = _ . get ( el [ '@' ] , 'type' ) ;
859901 enclosure . length = _ . get ( el [ '@' ] , 'length' ) ;
@@ -932,7 +974,7 @@ FeedParser.prototype.handleItem = function handleItem (node, type, options){
932974 case ( 'enclosure' ) :
933975 if ( Array . isArray ( el ) ) {
934976 el . forEach ( function ( enc ) {
935- enclosure = { } ;
977+ enclosure = /** @type { import('../../index').Enclosure } */ ( { } ) ;
936978 enclosure . url = _ . get ( enc [ '@' ] , 'url' ) ;
937979 enclosure . type = _ . get ( enc [ '@' ] , 'type' ) ;
938980 enclosure . length = _ . get ( enc [ '@' ] , 'length' ) ;
@@ -943,7 +985,7 @@ FeedParser.prototype.handleItem = function handleItem (node, type, options){
943985 }
944986 } ) ;
945987 } else {
946- enclosure = { } ;
988+ enclosure = /** @type { import('../../index').Enclosure } */ ( { } ) ;
947989 enclosure . url = _ . get ( el [ '@' ] , 'url' ) ;
948990 enclosure . type = _ . get ( el [ '@' ] , 'type' ) ;
949991 enclosure . length = _ . get ( el [ '@' ] , 'length' ) ;
@@ -958,7 +1000,7 @@ FeedParser.prototype.handleItem = function handleItem (node, type, options){
9581000 var optionalAttributes = [ 'bitrate' , 'framerate' , 'samplingrate' , 'duration' , 'height' , 'width' ] ;
9591001 if ( Array . isArray ( el ) ) {
9601002 el . forEach ( function ( enc ) {
961- enclosure = { } ;
1003+ enclosure = /** @type { import('../../index').Enclosure } */ ( { } ) ;
9621004 enclosure . url = _ . get ( enc [ '@' ] , 'url' ) ;
9631005 enclosure . type = _ . get ( enc [ '@' ] , 'type' ) || _ . get ( enc [ '@' ] , 'medium' ) ;
9641006 enclosure . length = _ . get ( enc [ '@' ] , 'filesize' ) ;
@@ -976,7 +1018,7 @@ FeedParser.prototype.handleItem = function handleItem (node, type, options){
9761018 }
9771019 } ) ;
9781020 } else {
979- enclosure = { } ;
1021+ enclosure = /** @type { import('../../index').Enclosure } */ ( { } ) ;
9801022 enclosure . url = _ . get ( el [ '@' ] , 'url' ) ;
9811023 enclosure . type = _ . get ( el [ '@' ] , 'type' ) || _ . get ( el [ '@' ] , 'medium' ) ;
9821024 enclosure . length = _ . get ( el [ '@' ] , 'filesize' ) ;
@@ -1112,6 +1154,7 @@ FeedParser.prototype.handleItem = function handleItem (node, type, options){
11121154} ;
11131155
11141156// Naive Stream API
1157+ /** @this {FeedParserInstance} */
11151158FeedParser . prototype . _transform = function ( data , encoding , done ) {
11161159 try {
11171160 this . stream . write ( data ) ;
@@ -1123,6 +1166,7 @@ FeedParser.prototype._transform = function (data, encoding, done) {
11231166 }
11241167} ;
11251168
1169+ /** @this {FeedParserInstance} */
11261170FeedParser . prototype . _flush = function ( done ) {
11271171 try {
11281172 this . stream . end ( ) ;
@@ -1133,4 +1177,64 @@ FeedParser.prototype._flush = function (done) {
11331177 }
11341178} ;
11351179
1180+ /**
1181+ * @typedef {Object } ParsedNode
1182+ * The internal accumulator object that handleOpenTag builds and pushes onto
1183+ * this.stack. Keys accumulate as child elements are parsed. String keys
1184+ * '#name', '#prefix', '#local', '#uri' hold element namespace info; '@' holds
1185+ * simplified attributes; '#' holds text content. Named keys hold child element
1186+ * values which may be strings, nested ParsedNodes, or arrays of either.
1187+ */
1188+
1189+ /**
1190+ * @typedef {Object } XmlBaseEntry
1191+ * An entry in the this.xmlbase stack. The '#name' key holds the element name
1192+ * that established the base URL; the '#' key holds the xml:base URL value.
1193+ */
1194+
1195+ /**
1196+ * @typedef {Object } SaxProcessingInstruction
1197+ * Payload of the sax 'processinginstruction' event.
1198+ * @property {string } name - Processing instruction target, e.g. "xml"
1199+ * @property {string } body - The rest of the processing instruction content
1200+ */
1201+
1202+ /**
1203+ * @typedef {Object } AddressParserResult
1204+ * Shape of each item returned by the addressparser module.
1205+ * @property {string } [name]
1206+ * @property {string } [address]
1207+ */
1208+
1209+ /**
1210+ * @typedef {Object } FeedParserState
1211+ * Instance properties set up by FeedParser.prototype.init and the constructor.
1212+ * @property {Object } meta - Parsed feed metadata; shape evolves during parsing
1213+ * @property {import('../../index').Options } options
1214+ * @property {Object.<string, string> } _namespaces
1215+ * @property {boolean } _emitted_meta
1216+ * @property {Array.<ParsedNode> } stack
1217+ * @property {Array.<XmlBaseEntry> } xmlbase
1218+ * @property {boolean } in_xhtml
1219+ * @property {Object } xhtml
1220+ * @property {Error[] } errors
1221+ * @property {import('sax').SAXStream } stream - The underlying sax stream
1222+ * @property {function(): void } init
1223+ * @property {function(): void } handleEnd
1224+ * @property {function(Error): void } handleSaxError
1225+ * @property {function(): void } resumeSaxError
1226+ * @property {function(Error): void } handleError
1227+ * @property {function(SaxProcessingInstruction): void } handleProcessingInstruction
1228+ * @property {function(import('sax').QualifiedTag): void } handleOpenTag
1229+ * @property {function(string): void } handleCloseTag
1230+ * @property {function(string): void } handleText
1231+ * @property {function(Object.<string, import('sax').QualifiedAttribute>, string): Object.<string, string> } handleAttributes
1232+ * @property {function(ParsedNode, import('../../index').Type, import('../../index').Options): Object } handleMeta
1233+ * @property {function(ParsedNode, import('../../index').Type, import('../../index').Options): Object } handleItem
1234+ */
1235+
1236+ /**
1237+ * @typedef {import('readable-stream').Transform & FeedParserState } FeedParserInstance
1238+ */
1239+
11361240exports = module . exports = FeedParser ;
0 commit comments