hi-xml2html
Advanced tools
Comparing version 1.2.1 to 2.0.0
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -14,2 +22,3 @@ const sax = require("sax"); | ||
exports.EmptyTag = empty_1.default; | ||
const utils_1 = require("./utils"); | ||
exports.default = (xmlString, settings = {}) => new Promise((resolve, reject) => { | ||
@@ -22,4 +31,12 @@ const state = new state_1.default(settings); | ||
parser.onerror = (e) => reject(e); | ||
parser.onend = () => resolve(state); | ||
parser.onend = () => __awaiter(this, void 0, void 0, function* () { | ||
if (state.settings.outputType === 'json') { | ||
if (state.settings.parent != null) { | ||
state.output = `<root>${state.output}</root>`; | ||
} | ||
state.output = yield utils_1.xml2json(state.output); | ||
} | ||
resolve(state); | ||
}); | ||
parser.write(xmlString).close(); | ||
}); |
@@ -1,2 +0,3 @@ | ||
declare var _default: (state: any) => (tagName: any) => void; | ||
import { IState } from "./types"; | ||
declare var _default: (state: IState) => (tagName: string) => void; | ||
export default _default; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const utils_1 = require("./utils"); | ||
exports.default = (state) => (tagName) => { | ||
const { ignore, parent } = state.settings; | ||
const tag = state.openTags.remove(); | ||
if (tag != null && | ||
state.tagsToSkip.indexOf(tag.data.name) === -1 && | ||
!state.openTags.containsOneOf(state.tagsToSkip)) { | ||
!utils_1.ignoreNode(ignore, tag.data) && | ||
!state.openTags.containsOneOf(ignore)) { | ||
const close = tag.close(); | ||
state.appendHtml(close); | ||
if (parent != null && | ||
utils_1.compareNodeToSelector(tag.data)(parent)) { | ||
state.writeToOutput = false; | ||
} | ||
} | ||
if (state.startFromTag === tagName) | ||
state.writeToOutput = false; | ||
}; |
@@ -1,3 +0,4 @@ | ||
import { Tag } from "sax"; | ||
declare var _default: (state: any) => (node: Tag) => void; | ||
import { Tag as SaxTag } from "sax"; | ||
import { IState } from "./types"; | ||
declare var _default: (state: IState) => (node: SaxTag) => void; | ||
export default _default; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const utils_1 = require("./utils"); | ||
exports.default = (state) => (node) => { | ||
if (state.startFromTag === node.name) | ||
const { getComponent, parent, ignore } = state.settings; | ||
if (parent != null && | ||
utils_1.compareNodeToSelector(node)(parent)) { | ||
state.writeToOutput = true; | ||
const Tag = Object.keys(state.tags).indexOf(node.name) > -1 ? | ||
state.tags[node.name] : | ||
state.GenericTag; | ||
const tag = new Tag(node, state); | ||
} | ||
let Comp; | ||
if (getComponent != null) | ||
Comp = getComponent(node); | ||
if (Comp == null) | ||
Comp = state.GenericTag; | ||
const tag = new Comp(node, state); | ||
const open = tag.open(); | ||
if (state.tagsToSkip.indexOf(node.name) === -1 && | ||
!state.openTags.containsOneOf(state.tagsToSkip)) { | ||
if (!utils_1.ignoreNode(state.settings.ignore, node) && | ||
!state.openTags.containsOneOf(state.settings.ignore)) { | ||
state.appendHtml(open); | ||
@@ -14,0 +20,0 @@ } |
@@ -1,2 +0,3 @@ | ||
declare var _default: (state: any) => (text: any) => void; | ||
import { IState } from "./types"; | ||
declare var _default: (state: IState) => (text: string) => void; | ||
export default _default; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.default = (state) => (text) => { | ||
if (!state.openTags.containsOneOf(state.tagsToSkip)) { | ||
if (!state.openTags.containsOneOf(state.settings.ignore)) { | ||
if (text.trim().length > 0) { | ||
text = state.settings.transformTextNode(text); | ||
} | ||
state.appendHtml(text); | ||
} | ||
}; |
import OpenTags from './open-tags'; | ||
import PreviousNodes from './previous-nodes'; | ||
import { ISettings, IState, TagClasses } from "../types"; | ||
import { ISettings, IState } from "../types"; | ||
declare class State implements IState { | ||
private componentsPath; | ||
output: string; | ||
settings: ISettings; | ||
custom: {}; | ||
GenericTag: any; | ||
openTags: OpenTags; | ||
output: string; | ||
previousNodes: PreviousNodes; | ||
startFromTag: any; | ||
tagClass: TagClasses; | ||
tags: any; | ||
tagsToSkip: any; | ||
usedTags: Set<any>; | ||
@@ -15,0 +12,0 @@ writeToOutput: boolean; |
@@ -5,26 +5,37 @@ "use strict"; | ||
const previous_nodes_1 = require("./previous-nodes"); | ||
const html_1 = require("../tags/html"); | ||
const jsx_1 = require("../tags/jsx"); | ||
const html_1 = require("../tags/html"); | ||
const empty_1 = require("../tags/empty"); | ||
const xml_1 = require("../tags/xml"); | ||
class State { | ||
constructor(settings) { | ||
this.settings = settings; | ||
this.custom = {}; | ||
this.openTags = new open_tags_1.default(); | ||
this.output = ''; | ||
this.openTags = new open_tags_1.default(); | ||
this.previousNodes = new previous_nodes_1.default(); | ||
this.tagClass = 'html'; | ||
this.usedTags = new Set(); | ||
this.writeToOutput = false; | ||
let { componentsPath, startFromTag, tagClass, tags, tagsToSkip } = settings; | ||
this.componentsPath = (componentsPath == null) ? 'components' : componentsPath; | ||
this.startFromTag = startFromTag; | ||
if (startFromTag == null) | ||
if (this.settings.componentsPath == null) | ||
this.settings.componentsPath = 'components'; | ||
if (this.settings.parent == null) | ||
this.writeToOutput = true; | ||
this.tags = (tags == null) ? {} : tags; | ||
this.tagsToSkip = (tagsToSkip == null) ? [] : tagsToSkip; | ||
this.appendHtml(false); | ||
if (tagClass != null && tagClass.length) | ||
this.tagClass = tagClass; | ||
this.GenericTag = this.tagClass === 'html' ? | ||
if (this.settings.ignore == null) | ||
this.settings.ignore = []; | ||
if (this.settings.outputType == null) | ||
this.settings.outputType = 'html'; | ||
if (this.settings.transformTextNode == null) | ||
this.settings.transformTextNode = (t) => t; | ||
if (this.settings.state != null) { | ||
this.custom = this.settings.state; | ||
delete this.settings.state; | ||
} | ||
const { outputType } = this.settings; | ||
this.GenericTag = outputType === 'html' ? | ||
html_1.default : | ||
this.tagClass === 'jsx' ? jsx_1.default : empty_1.default; | ||
outputType === 'jsx' ? | ||
jsx_1.default : | ||
outputType === 'xml' || outputType === 'json' ? | ||
xml_1.default : | ||
empty_1.default; | ||
} | ||
@@ -31,0 +42,0 @@ appendHtml(str) { |
@@ -1,2 +0,2 @@ | ||
import { IBaseTag, IOpenTags } from "../types"; | ||
import { IBaseTag, IOpenTags, ITagSelector } from "../types"; | ||
declare class OpenTags implements IOpenTags { | ||
@@ -7,4 +7,4 @@ private tags; | ||
contains(tagName: any): boolean; | ||
containsBy(tagName: any, attributeKey: any, attributeValue: any): boolean; | ||
containsOneOf(tagNames: any): any; | ||
containsBy(selector: ITagSelector): any; | ||
containsOneOf(selectors: ITagSelector[]): boolean; | ||
count(): number; | ||
@@ -11,0 +11,0 @@ countType(tagName: any): number; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const utils_1 = require("../utils"); | ||
class OpenTags { | ||
@@ -16,9 +17,7 @@ constructor() { | ||
} | ||
containsBy(tagName, attributeKey, attributeValue) { | ||
return this.tags.find((t) => t.data.name === tagName && | ||
t.data.attributes.hasOwnProperty(attributeKey) && | ||
t.data.attributes[attributeKey] === attributeValue) != null; | ||
containsBy(selector) { | ||
return this.tags.find((t) => utils_1.compareNodeToSelector(t.data)(selector)); | ||
} | ||
containsOneOf(tagNames) { | ||
return tagNames.some((tagName) => this.contains(tagName)); | ||
containsOneOf(selectors) { | ||
return selectors.some((selector) => this.containsBy(selector)); | ||
} | ||
@@ -25,0 +24,0 @@ count() { |
import { IBaseTag, IState } from "../types"; | ||
import { Tag } from "sax"; | ||
import { Tag as SaxTag } from "sax"; | ||
declare class BaseTag implements IBaseTag { | ||
protected data: Tag; | ||
data: SaxTag; | ||
state: IState; | ||
protected className: string; | ||
protected classNames: Set<string>; | ||
protected tagName: string; | ||
constructor(data: Tag, state: IState); | ||
constructor(data: SaxTag, state: IState); | ||
protected classNamesToString(): string; | ||
@@ -14,3 +13,4 @@ protected getAttributes(): string; | ||
protected closeBefore(): string; | ||
name(): string; | ||
} | ||
export default BaseTag; |
@@ -8,3 +8,2 @@ "use strict"; | ||
this.classNames = new Set(); | ||
this.tagName = 'div'; | ||
} | ||
@@ -38,3 +37,6 @@ classNamesToString() { | ||
} | ||
name() { | ||
return this.data.name; | ||
} | ||
} | ||
exports.default = BaseTag; |
@@ -6,3 +6,4 @@ import BaseTag from "./base"; | ||
close(): string; | ||
name(): string; | ||
} | ||
export default HtmlTag; |
@@ -6,8 +6,11 @@ "use strict"; | ||
open() { | ||
return `<${this.tagName}${this.classNamesToString()}${this.getAttributes()}>${this.openAfter()}`; | ||
return `<${this.name()}${this.classNamesToString()}${this.getAttributes()}>${this.openAfter()}`; | ||
} | ||
close() { | ||
return `${this.closeBefore()}</${this.tagName}>`; | ||
return `${this.closeBefore()}</${this.name()}>`; | ||
} | ||
name() { | ||
return 'div'; | ||
} | ||
} | ||
exports.default = HtmlTag; |
import BaseTag from "./base"; | ||
import { ICustomTag } from "../types"; | ||
declare class JsxTag extends BaseTag implements ICustomTag { | ||
protected passProps: boolean; | ||
constructor(data: any, state: any); | ||
open(): string; | ||
close(): string; | ||
name(): string; | ||
protected getAttributes(): string; | ||
} | ||
export default JsxTag; |
@@ -8,5 +8,5 @@ "use strict"; | ||
super(data, state); | ||
this.tagName = utils_1.formatTagName(this.data.name); | ||
this.passProps = false; | ||
if (state.writeToOutput) | ||
state.usedTags.add(this.tagName); | ||
state.usedTags.add(this.name()); | ||
} | ||
@@ -18,3 +18,4 @@ open() { | ||
''; | ||
return `<${this.tagName}${className}${this.getAttributes()}${slash}>${this.openAfter()}`; | ||
const props = this.passProps ? ' {...props}' : ''; | ||
return `<${this.name()}${className}${this.getAttributes()}${props}${slash}>${this.openAfter()}`; | ||
} | ||
@@ -24,5 +25,19 @@ close() { | ||
'' : | ||
`${this.closeBefore()}</${this.tagName}>`; | ||
`${this.closeBefore()}</${this.name()}>`; | ||
} | ||
name() { | ||
return utils_1.formatTagName(this.data.name); | ||
} | ||
getAttributes() { | ||
const attrs = this.data.attributes; | ||
const keys = Object.keys(attrs); | ||
return keys | ||
.map((key) => { | ||
const value = attrs[key]; | ||
key = utils_1.convertColon(key); | ||
return ` ${key}="${value}"`; | ||
}) | ||
.join(''); | ||
} | ||
} | ||
exports.default = JsxTag; |
@@ -1,3 +0,8 @@ | ||
import { Tag } from "sax"; | ||
import { Tag as SaxTag } from "sax"; | ||
import JsxTag from "./tags/jsx"; | ||
import HtmlTag from "./tags/html"; | ||
import EmptyTag from "./tags/empty"; | ||
import XmlTag from "./tags/xml"; | ||
export interface IBaseTag { | ||
data: SaxTag; | ||
state: IState; | ||
@@ -7,40 +12,52 @@ } | ||
close(): string; | ||
name?(): string; | ||
open(): string; | ||
} | ||
export declare type TagClasses = 'html' | 'jsx' | 'empty'; | ||
export interface ITagSelector { | ||
attribute?: string; | ||
name: string; | ||
value?: string; | ||
} | ||
export declare type OutputType = 'html' | 'jsx' | 'xml' | 'json' | 'empty'; | ||
export declare type TagClass = typeof HtmlTag | typeof JsxTag | typeof XmlTag | typeof EmptyTag; | ||
export interface ISettings { | ||
componentsPath?: string; | ||
parent?: ITagSelector; | ||
outputType?: OutputType; | ||
getComponent?(node: SaxTag): TagClass; | ||
ignore?: ITagSelector[]; | ||
state?: { | ||
[prop: string]: any; | ||
}; | ||
transformTextNode?: (text: string) => string; | ||
} | ||
export interface IState { | ||
openTags: any; | ||
previousNodes: any; | ||
startFromTag: string; | ||
tagClass: TagClasses; | ||
tags: any; | ||
tagsToSkip: string[]; | ||
appendHtml(str: string): void; | ||
custom: { | ||
[prop: string]: any; | ||
}; | ||
GenericTag: TagClass; | ||
openTags: IOpenTags; | ||
output: string; | ||
previousNodes: IPreviousNodes; | ||
settings: ISettings; | ||
usedTags: Set<string>; | ||
writeToOutput: boolean; | ||
appendHtml(str: string): void; | ||
[prop: string]: any; | ||
} | ||
export interface ISettings { | ||
componentsPath?: string; | ||
startFromTag?: string; | ||
tagClass?: TagClasses; | ||
tags?: Object; | ||
tagsToSkip?: any[]; | ||
} | ||
export interface IPreviousNodes { | ||
add(node: Tag): void; | ||
last(): Tag; | ||
lastButOne(): Tag; | ||
lastButTwo(): Tag; | ||
add(node: SaxTag): void; | ||
last(): SaxTag; | ||
lastButOne(): SaxTag; | ||
lastButTwo(): SaxTag; | ||
} | ||
export interface IOpenTags { | ||
add(tag: IBaseTag): void; | ||
remove(): void; | ||
add(tag: ICustomTag): void; | ||
remove(): ICustomTag; | ||
contains(name: string): boolean; | ||
containsBy(tagName: string, attributeKey: string, attributeValue: string): boolean; | ||
containsOneOf(tagNames: string[]): void; | ||
containsBy(selector: ITagSelector): boolean; | ||
containsOneOf(selectors: ITagSelector[]): void; | ||
count(): number; | ||
countType(tagName: string): number; | ||
lastOfType(tagName: string): IBaseTag; | ||
lastOfType(tagName: string): ICustomTag; | ||
log(): string; | ||
} |
@@ -0,1 +1,7 @@ | ||
import { ITagSelector } from "./types"; | ||
import { Tag as SaxTag } from "sax"; | ||
export declare const convertColon: (str: string) => string; | ||
export declare const formatTagName: (str: string) => string; | ||
export declare const compareNodeToSelector: (node: SaxTag) => (selector: ITagSelector) => boolean; | ||
export declare const ignoreNode: (ignore: ITagSelector[], node: SaxTag) => boolean; | ||
export declare const xml2json: (xml: any) => Promise<string>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const xml2js_1 = require("xml2js"); | ||
const capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1); | ||
const convertColon = (str) => str.replace(/:([a-z]{1})/g, (match, p1) => p1.toUpperCase()); | ||
exports.convertColon = (str) => str.replace(/:([a-zA-Z]{1})/g, (match, p1) => p1.toUpperCase()); | ||
exports.formatTagName = (str) => { | ||
if (str === 'date') | ||
str = `${str}_`; | ||
return capitalize(convertColon(str)); | ||
return capitalize(exports.convertColon(str)); | ||
}; | ||
exports.compareNodeToSelector = (node) => (selector) => { | ||
const name = selector.name === node.name; | ||
const attribute = selector.attribute == null || Object.keys(node.attributes).indexOf(selector.attribute) > -1; | ||
const value = selector.value == null || (attribute && selector.value === node.attributes[selector.attribute]); | ||
return name && attribute && value; | ||
}; | ||
exports.ignoreNode = (ignore, node) => ignore.some(exports.compareNodeToSelector(node)); | ||
exports.xml2json = (xml) => new Promise((resolve, reject) => { | ||
xml2js_1.parseString(xml, (err, result) => { | ||
if (err) | ||
return reject(err); | ||
resolve(result); | ||
}); | ||
}); |
@@ -0,1 +1,5 @@ | ||
### v2.0.0 (2017/4/28 16:50) | ||
* Refactor | ||
* Move settings to state | ||
### v1.2.1 (2017/4/20 10:1) | ||
@@ -2,0 +6,0 @@ * Pass className to JSX tag |
{ | ||
"name": "hi-xml2html", | ||
"version": "1.2.1", | ||
"version": "2.0.0", | ||
"description": "", | ||
@@ -9,3 +9,3 @@ "main": "build/index.js", | ||
"bump": "hi-bump", | ||
"test": "node test/index.js", | ||
"test": "jest", | ||
"watch": "tsc -w" | ||
@@ -16,10 +16,25 @@ }, | ||
"dependencies": { | ||
"sax": "^1.2.2" | ||
"sax": "^1.2.2", | ||
"xml2js": "^0.4.17" | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^19.2.2", | ||
"@types/sax": "^1.0.0", | ||
"hi-bump": "^1.1.1", | ||
"jest": "^19.0.2", | ||
"ts-jest": "^19.0.10", | ||
"typescript": "^2.2.1" | ||
}, | ||
"types": "build/index" | ||
"types": "build/index", | ||
"jest": { | ||
"transform": { | ||
".(ts|tsx)": "<rootDir>/node_modules/ts-jest/preprocessor.js" | ||
}, | ||
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$", | ||
"moduleFileExtensions": [ | ||
"ts", | ||
"tsx", | ||
"js" | ||
] | ||
} | ||
} |
@@ -11,2 +11,3 @@ import * as sax from "sax"; | ||
import EmptyTag from './tags/empty'; | ||
import {xml2json} from "./utils"; | ||
export { EmptyTag, HtmlTag, JsxTag } ; | ||
@@ -22,4 +23,18 @@ | ||
parser.onerror = (e) => reject(e); | ||
parser.onend = () => resolve(state); | ||
parser.onend = async () => { | ||
if (state.settings.outputType === 'json') { | ||
// The settings.parent option can yield invalid XML. If parent is 'b': | ||
// <a><b /><b /></a>, results in: <b /><b />. If this is passed | ||
// to xml2json, only the first <b /> will be parsed, therefor a | ||
// root node is added. | ||
if (state.settings.parent != null) { | ||
state.output = `<root>${state.output}</root>`; | ||
} | ||
state.output = await xml2json(state.output); | ||
} | ||
resolve(state); | ||
}; | ||
parser.write(xmlString).close(); | ||
}); |
@@ -1,2 +0,6 @@ | ||
export default (state) => (tagName) => { | ||
import {IState} from "./types"; | ||
import {compareNodeToSelector, ignoreNode} from "./utils"; | ||
export default (state: IState) => (tagName: string) => { | ||
const { ignore, parent } = state.settings; | ||
const tag = state.openTags.remove(); | ||
@@ -7,11 +11,18 @@ | ||
// Ignore tags to skip | ||
state.tagsToSkip.indexOf(tag.data.name) === -1 && | ||
// state.settings.ignore.indexOf(tag.data.name) === -1 && | ||
!ignoreNode(ignore, tag.data) && | ||
// Ignore children of tags to skip | ||
!state.openTags.containsOneOf(state.tagsToSkip) | ||
!state.openTags.containsOneOf(ignore) | ||
) { | ||
const close = tag.close() | ||
const close = tag.close(); | ||
state.appendHtml(close); | ||
if ( | ||
parent != null && | ||
compareNodeToSelector(tag.data)(parent) | ||
) { | ||
state.writeToOutput = false; | ||
} | ||
} | ||
if (state.startFromTag === tagName) state.writeToOutput = false; | ||
} |
@@ -1,15 +0,24 @@ | ||
import {Tag} from "sax"; | ||
import {Tag as SaxTag} from "sax"; | ||
import {IState} from "./types"; | ||
import {compareNodeToSelector, ignoreNode} from "./utils"; | ||
export default (state) => (node: Tag) => { | ||
if (state.startFromTag === node.name) state.writeToOutput = true; | ||
export default (state: IState) => (node: SaxTag) => { | ||
const { getComponent, parent, ignore } = state.settings; | ||
const Tag = Object.keys(state.tags).indexOf(node.name) > -1 ? | ||
state.tags[node.name] : | ||
state.GenericTag; | ||
const tag = new Tag(node, state); | ||
if ( | ||
parent != null && | ||
compareNodeToSelector(node)(parent) | ||
) { | ||
state.writeToOutput = true; | ||
} | ||
let Comp; | ||
if (getComponent != null) Comp = getComponent(node); | ||
if (Comp == null) Comp = state.GenericTag; | ||
const tag = new Comp(node, state); | ||
const open = tag.open(); | ||
if ( | ||
state.tagsToSkip.indexOf(node.name) === -1 && | ||
!state.openTags.containsOneOf(state.tagsToSkip) | ||
!ignoreNode(state.settings.ignore, node) && | ||
!state.openTags.containsOneOf(state.settings.ignore) | ||
) { | ||
@@ -16,0 +25,0 @@ state.appendHtml(open); |
@@ -1,5 +0,11 @@ | ||
export default (state) => (text) => { | ||
if (!state.openTags.containsOneOf(state.tagsToSkip)) { | ||
import {IState} from "./types"; | ||
export default (state: IState) => (text: string) => { | ||
if (!state.openTags.containsOneOf(state.settings.ignore)) { | ||
if (text.trim().length > 0) { | ||
text = state.settings.transformTextNode(text); | ||
} | ||
state.appendHtml(text); | ||
} | ||
} |
import OpenTags from './open-tags'; | ||
import PreviousNodes from './previous-nodes'; | ||
import {ICustomTag, ISettings, IState, TagClasses} from "../types"; | ||
import {ISettings, IState} from "../types"; | ||
import HtmlTag from "../tags/html"; | ||
import JsxTag from "../tags/jsx"; | ||
import HtmlTag from "../tags/html"; | ||
import EmptyTag from "../tags/empty"; | ||
import XmlTag from "../tags/xml"; | ||
class State implements IState { | ||
private componentsPath: string; | ||
public output: string = ''; | ||
public custom = {}; | ||
public GenericTag; | ||
public openTags = new OpenTags(); | ||
public output: string = ''; | ||
public previousNodes = new PreviousNodes(); | ||
public startFromTag; | ||
public tagClass: TagClasses = 'html'; | ||
public tags; | ||
public tagsToSkip; | ||
public usedTags = new Set(); | ||
public writeToOutput = false; | ||
constructor(settings: ISettings) { | ||
let { componentsPath, startFromTag, tagClass, tags, tagsToSkip } = settings; | ||
this.componentsPath = (componentsPath == null) ? 'components' : componentsPath; | ||
this.startFromTag = startFromTag; | ||
if (startFromTag == null) this.writeToOutput = true; | ||
this.tags = (tags == null) ? {} : tags; | ||
this.tagsToSkip = (tagsToSkip == null) ? [] : tagsToSkip; | ||
this.appendHtml(false); | ||
if (tagClass != null && tagClass.length) this.tagClass = tagClass; | ||
this.GenericTag = this.tagClass === 'html' ? | ||
constructor(public settings: ISettings) { | ||
if (this.settings.componentsPath == null) this.settings.componentsPath = 'components'; | ||
if (this.settings.parent == null) this.writeToOutput = true; | ||
if (this.settings.ignore == null) this.settings.ignore = []; | ||
if (this.settings.outputType == null) this.settings.outputType = 'html'; | ||
if (this.settings.transformTextNode == null) this.settings.transformTextNode = (t) => t; | ||
if (this.settings.state != null) { | ||
this.custom = this.settings.state; | ||
delete this.settings.state; | ||
} | ||
const { outputType } = this.settings; | ||
this.GenericTag = outputType === 'html' ? | ||
HtmlTag : | ||
this.tagClass === 'jsx' ? JsxTag : EmptyTag; | ||
outputType === 'jsx' ? | ||
JsxTag : | ||
outputType === 'xml' || outputType === 'json' ? | ||
XmlTag : | ||
EmptyTag; | ||
} | ||
// ToDo rename to appendString | ||
public appendHtml(str) { | ||
@@ -37,0 +41,0 @@ if (this.writeToOutput) this.output += str; |
@@ -1,2 +0,3 @@ | ||
import {IBaseTag, IOpenTags} from "../types"; | ||
import {IBaseTag, IOpenTags, ITagSelector} from "../types"; | ||
import {compareNodeToSelector} from "../utils"; | ||
@@ -18,12 +19,8 @@ class OpenTags implements IOpenTags { | ||
public containsBy(tagName, attributeKey, attributeValue) { | ||
return this.tags.find((t) => | ||
t.data.name === tagName && | ||
t.data.attributes.hasOwnProperty(attributeKey) && | ||
t.data.attributes[attributeKey] === attributeValue | ||
) != null; | ||
public containsBy(selector: ITagSelector) { | ||
return this.tags.find((t) => compareNodeToSelector(t.data)(selector)) | ||
} | ||
public containsOneOf(tagNames) { | ||
return tagNames.some((tagName) => this.contains(tagName)); | ||
public containsOneOf(selectors: ITagSelector[]) { | ||
return selectors.some((selector) => this.containsBy(selector)); | ||
} | ||
@@ -30,0 +27,0 @@ |
import {formatTagName} from "../utils"; | ||
import {IBaseTag, IState} from "../types"; | ||
import {Tag} from "sax"; | ||
import {Tag as SaxTag} from "sax"; | ||
@@ -8,5 +8,5 @@ class BaseTag implements IBaseTag { | ||
protected classNames: Set<string> = new Set(); | ||
protected tagName: string = 'div'; | ||
constructor(protected data: Tag, public state: IState) {} | ||
// ToDo rename data to node | ||
constructor(public data: SaxTag, public state: IState) {} | ||
@@ -48,4 +48,8 @@ protected classNamesToString() { | ||
} | ||
public name(): string { | ||
return this.data.name; | ||
} | ||
} | ||
export default BaseTag; |
@@ -6,10 +6,14 @@ import BaseTag from "./base"; | ||
public open() { | ||
return `<${this.tagName}${this.classNamesToString()}${this.getAttributes()}>${this.openAfter()}`; | ||
return `<${this.name()}${this.classNamesToString()}${this.getAttributes()}>${this.openAfter()}`; | ||
} | ||
public close() { | ||
return `${this.closeBefore()}</${this.tagName}>`; | ||
return `${this.closeBefore()}</${this.name()}>`; | ||
} | ||
public name(): string { | ||
return 'div'; | ||
} | ||
} | ||
export default HtmlTag; |
@@ -1,2 +0,2 @@ | ||
import {formatTagName} from "../utils"; | ||
import {convertColon, formatTagName} from "../utils"; | ||
import BaseTag from "./base"; | ||
@@ -6,6 +6,8 @@ import {ICustomTag} from "../types"; | ||
class JsxTag extends BaseTag implements ICustomTag { | ||
protected passProps = false; | ||
constructor(data, state) { | ||
super(data, state); | ||
this.tagName = formatTagName(this.data.name); | ||
if (state.writeToOutput) state.usedTags.add(this.tagName); | ||
if (state.writeToOutput) state.usedTags.add(this.name()); | ||
} | ||
@@ -19,3 +21,5 @@ | ||
return `<${this.tagName}${className}${this.getAttributes()}${slash}>${this.openAfter()}`; | ||
const props = this.passProps ? ' {...props}' : ''; | ||
return `<${this.name()}${className}${this.getAttributes()}${props}${slash}>${this.openAfter()}`; | ||
} | ||
@@ -26,6 +30,27 @@ | ||
'' : | ||
`${this.closeBefore()}</${this.tagName}>`; | ||
`${this.closeBefore()}</${this.name()}>`; | ||
} | ||
public name() { | ||
return formatTagName(this.data.name); | ||
} | ||
protected getAttributes() { | ||
const attrs = this.data.attributes; | ||
const keys = Object.keys(attrs); | ||
return keys | ||
.map((key) => { | ||
const value = attrs[key]; | ||
// Rename the key if necessary | ||
// key = key.replace(':', '-'); | ||
key = convertColon(key); | ||
return ` ${key}="${value}"` | ||
}) | ||
.join(''); | ||
} | ||
} | ||
export default JsxTag; |
@@ -1,28 +0,27 @@ | ||
import {Tag} from "sax"; | ||
import {Tag as SaxTag} from "sax"; | ||
import JsxTag from "./tags/jsx"; | ||
import HtmlTag from "./tags/html"; | ||
import EmptyTag from "./tags/empty"; | ||
import XmlTag from "./tags/xml"; | ||
export interface IBaseTag { | ||
data: SaxTag; | ||
state: IState; | ||
} | ||
// ToDo rename ICustomTag to ITag | ||
export interface ICustomTag extends IBaseTag { | ||
close(): string; | ||
name?(): string; | ||
open(): string; | ||
} | ||
export type TagClasses = 'html' | 'jsx' | 'empty'; | ||
export interface IState { | ||
openTags; | ||
previousNodes; | ||
startFromTag: string; | ||
tagClass: TagClasses; | ||
tags; | ||
// ToDo make more flexibel: [{name: 'hi', rend: 'super'}] | ||
tagsToSkip: string[]; | ||
usedTags: Set<string>; | ||
writeToOutput: boolean; | ||
appendHtml(str: string): void; | ||
[prop: string]: any; | ||
export interface ITagSelector { | ||
attribute?: string; | ||
name: string; | ||
value?: string; | ||
} | ||
export type OutputType = 'html' | 'jsx' | 'xml' | 'json' | 'empty'; | ||
export type TagClass = typeof HtmlTag | typeof JsxTag | typeof XmlTag | typeof EmptyTag; | ||
export interface ISettings { | ||
@@ -32,33 +31,57 @@ // Path where JSX components can be found. | ||
// When the parser encouters this tag name, the parser starts writing | ||
// to this.output. The tag name should be a unique tag (like <body>). | ||
startFromTag?: string; | ||
// When the parser encouters this tag, the parser starts writing | ||
// to this.output. The tag should be unique (like <body> or <div type="unique-type" />), | ||
// if the tag is not unique, the first encountered will be used. | ||
// ToDo is this correct? Prob all parents will be parsed | ||
parent?: ITagSelector; | ||
tagClass?: TagClasses; | ||
outputType?: OutputType; | ||
// Maps a tag name (key) to a tag class (value). The tag class may extend | ||
// BaseTag. If a tag is not in the map, BaseTag is used to generate output. | ||
tags?: Object; | ||
getComponent?(node: SaxTag): TagClass; | ||
// List of tag names to skip (and their children!) | ||
tagsToSkip?: any[]; | ||
// List of tags to skip (and their children!) | ||
ignore?: ITagSelector[]; | ||
state?: { | ||
[prop: string]: any, | ||
} | ||
// Called on all text nodes. | ||
transformTextNode?: (text: string) => string; | ||
} | ||
export interface IState { | ||
appendHtml(str: string): void; | ||
custom: { | ||
[prop: string]: any | ||
}; | ||
GenericTag: TagClass; | ||
openTags: IOpenTags; | ||
output: string; | ||
previousNodes: IPreviousNodes; | ||
settings: ISettings; | ||
usedTags: Set<string>; | ||
writeToOutput: boolean; | ||
} | ||
export interface IPreviousNodes { | ||
add(node: Tag): void; | ||
last(): Tag; | ||
lastButOne(): Tag; | ||
lastButTwo(): Tag; | ||
add(node: SaxTag): void; | ||
last(): SaxTag; | ||
lastButOne(): SaxTag; | ||
lastButTwo(): SaxTag; | ||
} | ||
export interface IOpenTags { | ||
add(tag: IBaseTag): void; | ||
remove(): void; | ||
add(tag: ICustomTag): void; | ||
remove(): ICustomTag; | ||
contains(name: string): boolean; | ||
containsBy(tagName: string, attributeKey: string, attributeValue: string): boolean; | ||
containsOneOf(tagNames: string[]): void; | ||
containsBy(selector: ITagSelector): boolean; | ||
containsOneOf(selectors: ITagSelector[]): void; | ||
count(): number; | ||
countType(tagName: string): number; | ||
lastOfType(tagName: string): IBaseTag; | ||
lastOfType(tagName: string): ICustomTag; | ||
log(): string; | ||
} | ||
@@ -0,1 +1,5 @@ | ||
import {ITagSelector} from "./types"; | ||
import {Tag as SaxTag} from "sax"; | ||
import { parseString } from 'xml2js'; | ||
const capitalize = (str: string): string => | ||
@@ -15,4 +19,4 @@ str.charAt(0).toUpperCase() + str.slice(1); | ||
*/ | ||
const convertColon = (str: string): string => | ||
str.replace(/:([a-z]{1})/g, (match, p1) => p1.toUpperCase()); | ||
export const convertColon = (str: string): string => | ||
str.replace(/:([a-zA-Z]{1})/g, (match, p1) => p1.toUpperCase()); | ||
@@ -23,1 +27,18 @@ export const formatTagName = (str: string): string => { | ||
}; | ||
export const compareNodeToSelector = (node: SaxTag) => (selector: ITagSelector): boolean => { | ||
const name = selector.name === node.name; | ||
const attribute = selector.attribute == null || Object.keys(node.attributes).indexOf(selector.attribute) > -1; | ||
const value = selector.value == null || (attribute && selector.value === node.attributes[selector.attribute]); | ||
return name && attribute && value; | ||
}; | ||
export const ignoreNode = (ignore: ITagSelector[], node: SaxTag): boolean => | ||
ignore.some(compareNodeToSelector(node)); | ||
export const xml2json = (xml) => new Promise<string>((resolve, reject) => { | ||
parseString(xml, (err, result) => { | ||
if (err) return reject(err); | ||
resolve(result); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
149931
56
1880
2
6
+ Addedxml2js@^0.4.17
+ Addedxml2js@0.4.23(transitive)
+ Addedxmlbuilder@11.0.1(transitive)