added all files to project

This commit is contained in:
2022-03-10 10:36:59 +01:00
parent 09dd957b33
commit 46a936d7de
25351 changed files with 3883356 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
/// <reference types="node" />
import { Writable } from 'stream';
export default class FeedMe extends Writable {
private _buffer;
private _parser;
/**
* Creates an instance of a parser. Parser can be JSON/XML.
*
* @param {boolean} buffer If true, feed will be buffered into memory
* and can be retrieved using `parser.done()` on the `end` event.
* @constructor
*/
constructor(buffer?: boolean);
_proxyEvents(): void;
/**
* @param {Buffer} data
*/
_write(data: Buffer, encoding: BufferEncoding, callback: (err?: Error | null) => void): void;
_final(callback: (err?: Error | null) => void): void;
done(): import("./parser").Feed | undefined;
}
export { Feed, FeedItem, FeedObject } from './parser';
+69
View File
@@ -0,0 +1,69 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const stream_1 = require("stream");
const xmlfeedparser_1 = __importDefault(require("./xmlfeedparser"));
const jsonfeedparser_1 = __importDefault(require("./jsonfeedparser"));
class FeedMe extends stream_1.Writable {
/**
* Creates an instance of a parser. Parser can be JSON/XML.
*
* @param {boolean} buffer If true, feed will be buffered into memory
* and can be retrieved using `parser.done()` on the `end` event.
* @constructor
*/
constructor(buffer = false) {
super();
this._buffer = buffer;
}
_proxyEvents() {
const parserEmit = this._parser.parser.emit;
this._parser.parser.emit = (event, ...args) => {
parserEmit.apply(this._parser.parser, [event, ...args]);
if (event !== 'error') {
return this.emit(event, ...args);
}
return true;
};
this._parser.parser.on('error', this.emit.bind(this, 'error'));
}
/**
* @param {Buffer} data
*/
_write(data, encoding, callback) {
const str = data.toString();
// First find out what type of feed this is.
if (!this._parser) {
if (/^\s*</.test(str)) {
this._parser = new xmlfeedparser_1.default(this._buffer);
this._proxyEvents();
}
else if (/^\s*[{[]/.test(str)) {
this._parser = new jsonfeedparser_1.default(this._buffer);
this.emit('type', 'json');
this._proxyEvents();
}
else {
callback(new Error('Not a correctly formatted feed'));
return;
}
}
this._parser.write(data, encoding, callback);
}
_final(callback) {
if (this._parser) {
this._parser.end(callback);
}
else {
callback(null);
}
}
done() {
return this._parser.done();
}
}
exports.default = FeedMe;
module.exports = FeedMe;
//# sourceMappingURL=feedme.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"feedme.js","sourceRoot":"","sources":["../src/feedme.ts"],"names":[],"mappings":";;;;;AAAA,mCAAkC;AAElC,oEAA4C;AAC5C,sEAA8C;AAG9C,MAAqB,MAAO,SAAQ,iBAAQ;IAI1C;;;;;;OAMG;IACH,YAAY,MAAM,GAAG,KAAK;QACxB,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACxB,CAAC;IAED,YAAY;QACV,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC;QAC5C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,KAAsB,EAAE,GAAG,IAAW,EAAW,EAAE;YAC7E,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;YACxD,IAAI,KAAK,KAAK,OAAO,EAAE;gBACrB,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC;aAClC;YACD,OAAO,IAAI,CAAC;QACd,CAAC,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IACjE,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,IAAY,EAAE,QAAwB,EAAE,QAAsC;QACnF,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;QAE5B,4CAA4C;QAC5C,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;YACjB,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;gBACrB,IAAI,CAAC,OAAO,GAAG,IAAI,uBAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAC/C,IAAI,CAAC,YAAY,EAAE,CAAC;aAErB;iBAAM,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;gBAC/B,IAAI,CAAC,OAAO,GAAG,IAAI,wBAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAChD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAC1B,IAAI,CAAC,YAAY,EAAE,CAAC;aAErB;iBAAM;gBACL,QAAQ,CAAC,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC,CAAC;gBACtD,OAAO;aACR;SACF;QAED,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED,MAAM,CAAC,QAAsC;QAC3C,IAAI,IAAI,CAAC,OAAO,EAAE;YAChB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;SAC5B;aAAM;YACL,QAAQ,CAAC,IAAI,CAAC,CAAC;SAChB;IACH,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IAC7B,CAAC;CACF;AAjED,yBAiEC;AAID,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC"}
+19
View File
@@ -0,0 +1,19 @@
/// <reference types="node" />
import { Writable } from 'stream';
import { Parser, Feed } from './parser';
/**
* Parses a JSON feed.
*
* @param {boolean} buffer If true, will buffer entire object.
* @return {CStream}
*/
export default class JSONFeedParser extends Writable implements Parser {
_buffer: boolean;
parser: Writable;
private _currObj;
private _currKey;
constructor(buffer: boolean);
_write(chunk: Buffer, encoding: BufferEncoding, callback: (err?: Error | null) => void): void;
_final(callback: (err?: Error | null) => void): void;
done(): Feed | undefined;
}
+178
View File
@@ -0,0 +1,178 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const stream_1 = require("stream");
const clarinet_1 = __importDefault(require("clarinet"));
/**
* Gets rid of unnecessary keys in an object
* and if the only keys in an object are `$t` or `$t` and `type`
* it makes the whole object the value of `$t`
* otherwise it renames `$t` to `text` for consistency.
*
* @param {Object}
* @returns {Object}
*/
const cleanObject = (obj) => {
if (obj.$t !== undefined) {
let keysLength = Object.keys(obj).length;
if (keysLength === 1 || (keysLength === 2 && obj.type !== undefined)) {
return obj.$t;
}
else {
obj.text = obj.$t;
delete obj.$t;
}
}
return obj;
};
/**
* Parses a JSON feed.
*
* @param {boolean} buffer If true, will buffer entire object.
* @return {CStream}
*/
class JSONFeedParser extends stream_1.Writable {
constructor(buffer) {
super();
this._buffer = buffer;
const parser = this.parser = clarinet_1.default.createStream();
const stack = [];
this._currObj = {};
this._currKey = 'feed';
let inArray = false;
let feedJustFound = false;
// Look feed object in case this is a json encoded atom feed.
// Place these underlying keys onto the root object.
const findfeed = (key) => {
if (key === 'feed') {
feedJustFound = true;
parser.removeListener('openobject', findfeed);
parser.removeListener('key', findfeed);
}
};
const onvalue = (value) => {
feedJustFound = false;
this._currObj[this._currKey] = value;
if (stack.length === 1) {
parser.emit(this._currKey, value);
if (!buffer) {
delete this._currObj[this._currKey];
}
}
if (inArray) {
this._currKey++;
}
};
const onopenobject = (key) => {
if (feedJustFound) {
feedJustFound = false;
this._currKey = key;
return;
}
let obj = this._currObj[this._currKey] = {};
stack.push({
obj: this._currObj,
key: this._currKey,
arr: inArray,
});
this._currObj = obj;
this._currKey = key;
inArray = false;
};
const onkey = (key) => { this._currKey = key; };
const oncloseobject = () => {
let parent = stack.pop();
if (!parent) {
return;
}
this._currObj = parent.obj;
this._currKey = parent.key;
inArray = parent.arr;
// Clean object.
const currObj = this._currObj;
currObj[this._currKey] = cleanObject(currObj[this._currKey]);
// Emit key in feed if curr is parent.
if (stack.length === 1) {
parser.emit(`${this._currKey}`, currObj[this._currKey]);
if (!buffer) {
delete currObj[this._currKey];
}
// Or parent is array.
}
else if (inArray) {
const currArr = currObj;
if (stack.length === 2) {
let key = stack[1].key;
let event = key === 'entry' || key === 'items' ?
'item' : stack[1].key;
let data = currArr[this._currKey];
parser.emit(event, data);
if (!buffer) {
currArr.splice(this._currKey, 1);
}
}
if (stack.length > 2 || buffer) {
this._currKey++;
}
}
};
const onopenarray = () => {
feedJustFound = false;
let obj = this._currObj[this._currKey] = [];
stack.push({
obj: this._currObj,
key: this._currKey,
arr: inArray,
});
this._currObj = obj;
this._currKey = 0;
inArray = true;
};
const onclosearray = () => {
let parent = stack.pop();
this._currObj = parent.obj;
this._currKey = parent.key;
inArray = parent.arr;
if (stack.length === 1) {
if (!buffer) {
delete this._currObj[this._currKey];
}
}
else if (inArray) {
this._currKey++;
}
};
parser.on('openobject', findfeed);
parser.on('key', findfeed);
parser.on('value', onvalue);
parser.on('openobject', onopenobject);
parser.on('key', onkey);
parser.on('closeobject', oncloseobject);
parser.on('openarray', onopenarray);
parser.on('closearray', onclosearray);
}
_write(chunk, encoding, callback) {
this.parser.write(chunk, encoding);
callback(null);
}
_final(callback) {
this.parser.end();
callback(null);
}
done() {
if (!this._buffer) {
return;
}
let root = this._currObj[this._currKey];
root.type = 'json';
if (Array.isArray(root.entry)) {
root.items = root.entry;
}
delete root.entry;
return root;
}
}
exports.default = JSONFeedParser;
//# sourceMappingURL=jsonfeedparser.js.map
File diff suppressed because one or more lines are too long
+18
View File
@@ -0,0 +1,18 @@
/// <reference types="node" />
import { Writable } from 'stream';
export declare type FeedObject = string | {
[key: string]: string | boolean | null | FeedObject | FeedObject[];
};
export declare type FeedItem = {
[key: string]: FeedObject;
};
export declare type Feed = {
type: string;
items: FeedItem[];
[key: string]: FeedObject | FeedObject[];
};
export interface Parser extends Writable {
_buffer: boolean;
parser: Writable;
done(): Feed | undefined;
}
+3
View File
@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=parser.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":""}
+19
View File
@@ -0,0 +1,19 @@
/// <reference types="node" />
import { Writable } from 'stream';
import { Parser, Feed } from './parser';
/**
* Parses an RSS/Atom feed.
*
* @param {boolean} buffer If true, will buffer entire object.
* @return {sax.Stream}
*/
export default class XMLFeedParser extends Writable implements Parser {
_buffer: boolean;
parser: Writable;
private _root;
private _obj;
constructor(buffer: boolean);
_write(chunk: Buffer, encoding: BufferEncoding, callback: (err?: Error | null) => void): void;
_final(callback: (err?: Error | null) => void): void;
done(): Feed | undefined;
}
+193
View File
@@ -0,0 +1,193 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const stream_1 = require("stream");
const sax_1 = __importDefault(require("sax"));
/**
* If this object has text, and there is no other children,
* or the only other key is type, make the object the text.
*
* @param {Object} obj
* @returns {Object}
*/
const cleanObj = (obj) => {
let keys = Object.keys(obj).length;
if (obj.text != null) {
// If this tag has text, trim it.
obj.text = trimIndent(obj.text);
if (keys === 1 || (keys === 2 && obj.type != null)) {
return obj.text;
}
}
else if (keys === 0) {
return '';
}
return obj;
};
/**
* Trims the indent from text that sax-js emits. Some xml feeds will
* add indent to multiline text. Example:
*
* <item>
* The big brown fox
* jumped over the lazy dog
* </item>
*
* @param {string} str
* @returns {string}
*/
const trimIndent = (str) => {
let split = str.split('\n'), rs;
// The last line should be indented and only contain whitespace.
if (split.length > 1 &&
(rs = /^((?: {3})+|(?: {2})+|(?: {4})+|(?:\t)+)$/m.exec(split[split.length - 1]))) {
// The very first line should be empty.
if (split.shift() !== '') {
return str;
}
// Remove the last line, as it's only whitespace.
split.pop();
let wholeindent = rs[0] + rs[1];
// Remove indent from beginning of every line.
for (let i = 0, l = split.length; i < l; i++) {
let s = split[i];
if (s.indexOf(wholeindent) !== 0) {
return str;
}
split[i] = s.substr(wholeindent.length);
}
str = split.join('\n');
}
return str;
};
/**
* Parses an RSS/Atom feed.
*
* @param {boolean} buffer If true, will buffer entire object.
* @return {sax.Stream}
*/
class XMLFeedParser extends stream_1.Writable {
constructor(buffer) {
super();
this._buffer = buffer;
const parser = this.parser = sax_1.default.createStream(false, { lowercase: true });
const stack = [];
this._root = this._obj = {};
// First start listening for the root tag.
const openf1 = (node) => {
if (node.name === 'channel' || node.name === 'feed') {
if (node.name === 'feed') {
let type = 'atom';
this._root.type = type;
parser.emit('type', type);
}
parser.removeListener('opentag', openf1);
parser.on('text', ontext);
parser.on('cdata', ontext);
parser.on('opentag', onopentag);
parser.on('closetag', onclosetag);
}
else if (node.name === 'rss' || node.name === 'rdf:rdf') {
let type = 'rss ' + (node.attributes.version || '1.0');
this._root.type = type;
parser.emit('type', type);
}
else {
parser.removeListener('opentag', openf1);
parser.emit('error', new Error('Feed type not recognized'));
// parser.closed = true;
}
};
parser.on('opentag', openf1);
const ontext = (text) => {
// Make sure text events are text and not just whitespace.
const rs = /\n(( {3})+|( {2})+|( {4})+|(\t)+)$/m.exec(text);
if (rs !== null && rs.index === 0 && rs[0] === rs.input) {
return;
}
const obj = this._obj;
if (obj.text == null) {
obj.text = '';
}
obj.text += text;
};
// After the root is found, start storing the rest of the document.
const onopentag = (node) => {
const key = node.name;
let i;
if (this._obj[key]) {
if (!Array.isArray(this._obj[key])) {
this._obj[key] = [this._obj[key], node.attributes];
i = 1;
}
else {
i = this._obj[key].push(node.attributes) - 1;
}
}
else {
this._obj[key] = node.attributes;
}
stack.push({ obj: this._obj, key, i });
this._obj = node.attributes;
};
const onclosetag = () => {
const parent = stack.pop();
if (!parent) {
return;
}
this._obj = parent.obj;
const key = parent.key;
const data = parent.i ?
this._obj[key][parent.i] = cleanObj(this._obj[key][parent.i]) :
this._obj[key] = cleanObj(this._obj[key]);
if (!stack.length) {
let skey = key === 'entry' || key === 'items' ? 'item' : key;
// Some feeds will contain a summary of items at the top.
// Ignore this.
if (key !== 'items' || Array.isArray(data)) {
parser.emit(skey, data);
if (!this._buffer) {
delete this._obj[key];
}
}
}
};
}
_write(chunk, encoding, callback) {
this.parser.write(chunk, encoding);
callback(null);
}
_final(callback) {
this.parser.end();
callback(null);
}
// Called when done parsing the document.
// Returns entire document in object form.
done() {
if (!this._buffer) {
return;
}
let items;
if (this._root.item != null) {
items = this._root.item;
delete this._root.item;
}
else if (this._root.entry != null) {
items = this._root.entry;
delete this._root.entry;
}
else {
items = [];
}
if (!Array.isArray(items)) {
items = [items];
}
this._root.items = items;
delete this._root.text;
return this._root;
}
}
exports.default = XMLFeedParser;
//# sourceMappingURL=xmlfeedparser.js.map
File diff suppressed because one or more lines are too long