mirror of
https://github.com/tenrok/BBob.git
synced 2026-06-17 19:21:20 +03:00
feat: typescript support (#185)
* feat: initial typescript support * feat: typescript support * feat(plugin-helper): move files to typescript * chore: update lock files * feat: preset types * fix: build * fix: benchmark * fix: remove pnpm cache * fix: bench action * fix: pnpm recursive install * fix: nx cache * fix: lock file * fix: workflows * fix: lerna support in pnpm * fix: pnpm workspace * fix: remove unused files * fix: pnpm lock file * fix: update lerna for support pnpm * fix: lerna bootstrap * fix: rollup build * fix: update nx * fix: build * fix: add nx dep target * fix: remove nx cache * fix: workflow run on push only for master * fix: test workflow run on push only for master * fix: remove parallel for gen types * fix: benchmark * fix: benchmark imports * fix: pnpm * fix: types errors and pnpm * fix: types * fix: types * refactor: parser * fix(parser): tests * fix: preset tests * fix: react types * fix: react type declarations * fix: pnpm lock file * fix: react preset types * fix: lock file * fix: vue2 types * feat: dev container support * fix: types * fix: types * refactor: rewrite pkg-task, add nx gen-types deps, fix react/render.ts * refactor: types * fix: types * fix: rename gen-types to types * fix: nx build order * fix: nx reset * fix: define nx deps explicit * fix: build * fix: nx * fix: nx order build * fix: nx deps * fix: bbob cli tests * fix: tests * fix: cli tests and import * fix: test cover * fix: cli cover
This commit is contained in:
@@ -2,3 +2,7 @@ coverage
|
||||
dist
|
||||
lib
|
||||
es
|
||||
types
|
||||
test/*.d.ts
|
||||
test/*.map
|
||||
tsconfig.tsbuildinfo
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package-lock.json
|
||||
pnpm-lock.yaml
|
||||
coverage
|
||||
src
|
||||
!dist
|
||||
|
||||
@@ -7,11 +7,49 @@
|
||||
"plugin",
|
||||
"helper"
|
||||
],
|
||||
"files": [
|
||||
"dist",
|
||||
"lib",
|
||||
"src",
|
||||
"es",
|
||||
"types"
|
||||
],
|
||||
"main": "lib/index.js",
|
||||
"module": "es/index.js",
|
||||
"jsnext:main": "es/index.js",
|
||||
"browser": "dist/index.js",
|
||||
"browserName": "BbobPluginHelper",
|
||||
"types": "types/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./types/index.d.ts",
|
||||
"import": "./es/index.js",
|
||||
"require": "./lib/index.js",
|
||||
"browser": "./dist/index.min.js",
|
||||
"umd": "./dist/index.min.js"
|
||||
},
|
||||
"./char": {
|
||||
"types": "./types/char.d.ts",
|
||||
"import": "./es/char.js",
|
||||
"require": "./lib/char.js",
|
||||
"browser": "./dist/index.min.js",
|
||||
"umd": "./dist/index.min.js"
|
||||
},
|
||||
"./helpers": {
|
||||
"types": "./types/helpers.d.ts",
|
||||
"import": "./es/helpers.js",
|
||||
"require": "./lib/helpers.js",
|
||||
"browser": "./dist/index.min.js",
|
||||
"umd": "./dist/index.min.js"
|
||||
},
|
||||
"./TagNode": {
|
||||
"types": "./types/TagNode.d.ts",
|
||||
"import": "./es/TagNode.js",
|
||||
"require": "./lib/TagNode.js",
|
||||
"browser": "./dist/index.min.js",
|
||||
"umd": "./dist/index.min.js"
|
||||
}
|
||||
},
|
||||
"homepage": "https://github.com/JiLiZART/bbob",
|
||||
"author": "Nikolay Kostyurin <jilizart@gmail.com>",
|
||||
"license": "MIT",
|
||||
@@ -23,35 +61,31 @@
|
||||
"url": "git://github.com/JiLiZART/bbob.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build:commonjs": "../../scripts/pkg-task build-commonjs",
|
||||
"build:es": "../../scripts/pkg-task build-es",
|
||||
"build:umd": "../../scripts/pkg-task build-umd",
|
||||
"build": "npm run build:commonjs && npm run build:es && npm run build:umd",
|
||||
"test": "../../scripts/pkg-task test",
|
||||
"cover": "../../scripts/pkg-task cover",
|
||||
"lint": "../../scripts/pkg-task lint",
|
||||
"size": "../../scripts/pkg-task size",
|
||||
"bundlesize": "../../scripts/pkg-task bundlesize",
|
||||
"build:commonjs": "pkg-task",
|
||||
"build:es": "pkg-task",
|
||||
"build:umd": "pkg-task",
|
||||
"build": "pkg-task",
|
||||
"test": "pkg-task",
|
||||
"cover": "pkg-task",
|
||||
"lint": "pkg-task",
|
||||
"size": "pkg-task",
|
||||
"bundlesize": "pkg-task",
|
||||
"types": "pkg-task",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"size-limit": [
|
||||
{
|
||||
"path": "lib/index.js"
|
||||
"path": "./dist/index.min.js",
|
||||
"size": "1 KB"
|
||||
}
|
||||
],
|
||||
"bundlesize": [
|
||||
{
|
||||
"path": "./dist/index.min.js",
|
||||
"maxSize": "1024 B"
|
||||
"maxSize": "1 KB"
|
||||
}
|
||||
],
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"lib",
|
||||
"src",
|
||||
"es"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
import { OPEN_BRAKET, CLOSE_BRAKET, SLASH } from './char';
|
||||
import {
|
||||
getNodeLength, appendToNode, attrsToString, attrValue, getUniqAttr,
|
||||
} from './helpers';
|
||||
|
||||
const getTagAttrs = (tag, params) => {
|
||||
const uniqAattr = getUniqAttr(params);
|
||||
|
||||
if (uniqAattr) {
|
||||
const tagAttr = attrValue(tag, uniqAattr);
|
||||
const attrs = { ...params };
|
||||
|
||||
delete attrs[uniqAattr];
|
||||
|
||||
const attrsStr = attrsToString(attrs);
|
||||
|
||||
return `${tagAttr}${attrsStr}`;
|
||||
}
|
||||
|
||||
return `${tag}${attrsToString(params)}`;
|
||||
};
|
||||
|
||||
class TagNode {
|
||||
constructor(tag, attrs, content) {
|
||||
this.tag = tag;
|
||||
this.attrs = attrs;
|
||||
this.content = Array.isArray(content) ? content : [content];
|
||||
}
|
||||
|
||||
attr(name, value) {
|
||||
if (typeof value !== 'undefined') {
|
||||
this.attrs[name] = value;
|
||||
}
|
||||
|
||||
return this.attrs[name];
|
||||
}
|
||||
|
||||
append(value) {
|
||||
return appendToNode(this, value);
|
||||
}
|
||||
|
||||
get length() {
|
||||
return getNodeLength(this);
|
||||
}
|
||||
|
||||
toTagStart({ openTag = OPEN_BRAKET, closeTag = CLOSE_BRAKET } = {}) {
|
||||
const tagAttrs = getTagAttrs(this.tag, this.attrs);
|
||||
|
||||
return `${openTag}${tagAttrs}${closeTag}`;
|
||||
}
|
||||
|
||||
toTagEnd({ openTag = OPEN_BRAKET, closeTag = CLOSE_BRAKET } = {}) {
|
||||
return `${openTag}${SLASH}${this.tag}${closeTag}`;
|
||||
}
|
||||
|
||||
toTagNode() {
|
||||
return new TagNode(this.tag.toLowerCase(), this.attrs, this.content);
|
||||
}
|
||||
|
||||
toString({ openTag = OPEN_BRAKET, closeTag = CLOSE_BRAKET } = {}) {
|
||||
const isEmpty = this.content.length === 0;
|
||||
const content = this.content.reduce((r, node) => r + node.toString({ openTag, closeTag }), '');
|
||||
const tagStart = this.toTagStart({ openTag, closeTag });
|
||||
|
||||
if (isEmpty) {
|
||||
return tagStart;
|
||||
}
|
||||
|
||||
return `${tagStart}${content}${this.toTagEnd({ openTag, closeTag })}`;
|
||||
}
|
||||
}
|
||||
|
||||
TagNode.create = (tag, attrs = {}, content = []) => new TagNode(tag, attrs, content);
|
||||
TagNode.isOf = (node, type) => (node.tag === type);
|
||||
|
||||
export { TagNode };
|
||||
export default TagNode;
|
||||
@@ -0,0 +1,115 @@
|
||||
import { OPEN_BRAKET, CLOSE_BRAKET, SLASH } from './char';
|
||||
import {
|
||||
getUniqAttr,
|
||||
getNodeLength,
|
||||
appendToNode,
|
||||
attrsToString,
|
||||
attrValue,
|
||||
isTagNode,
|
||||
} from './helpers';
|
||||
|
||||
import type { NodeContent, TagNodeObject, TagNodeTree } from "./types";
|
||||
|
||||
const getTagAttrs = <AttrValue>(tag: string, params: Record<string, AttrValue>) => {
|
||||
const uniqAttr = getUniqAttr(params);
|
||||
|
||||
if (uniqAttr) {
|
||||
const tagAttr = attrValue(tag, uniqAttr);
|
||||
const attrs = { ...params };
|
||||
|
||||
delete attrs[String(uniqAttr)];
|
||||
|
||||
const attrsStr = attrsToString(attrs);
|
||||
|
||||
return `${tagAttr}${attrsStr}`;
|
||||
}
|
||||
|
||||
return `${tag}${attrsToString(params)}`;
|
||||
};
|
||||
|
||||
const renderContent = (content: TagNodeTree, openTag: string, closeTag: string) => {
|
||||
const toString = (node: NodeContent) => {
|
||||
if (isTagNode(node)) {
|
||||
return node.toString({ openTag, closeTag })
|
||||
}
|
||||
|
||||
return String(node)
|
||||
}
|
||||
|
||||
if (Array.isArray(content)) {
|
||||
return content.reduce<string>((r, node) => {
|
||||
if (node !== null) {
|
||||
return r + toString(node)
|
||||
}
|
||||
|
||||
return r
|
||||
}, '')
|
||||
}
|
||||
|
||||
if (content) {
|
||||
return toString(content)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export class TagNode implements TagNodeObject {
|
||||
public readonly tag: string
|
||||
public attrs: Record<string, unknown>
|
||||
public content: TagNodeTree
|
||||
|
||||
constructor(tag: string, attrs: Record<string, unknown>, content: TagNodeTree) {
|
||||
this.tag = tag;
|
||||
this.attrs = attrs;
|
||||
this.content = content
|
||||
}
|
||||
|
||||
attr(name: string, value?: unknown) {
|
||||
if (typeof value !== 'undefined') {
|
||||
this.attrs[name] = value;
|
||||
}
|
||||
|
||||
return this.attrs[name];
|
||||
}
|
||||
|
||||
append(value: string) {
|
||||
return appendToNode(this, value);
|
||||
}
|
||||
|
||||
get length(): number {
|
||||
return getNodeLength(this);
|
||||
}
|
||||
|
||||
toTagStart({ openTag = OPEN_BRAKET, closeTag = CLOSE_BRAKET } = {}) {
|
||||
const tagAttrs = getTagAttrs(this.tag, this.attrs);
|
||||
|
||||
return `${openTag}${tagAttrs}${closeTag}`;
|
||||
}
|
||||
|
||||
toTagEnd({ openTag = OPEN_BRAKET, closeTag = CLOSE_BRAKET } = {}) {
|
||||
return `${openTag}${SLASH}${this.tag}${closeTag}`;
|
||||
}
|
||||
|
||||
toTagNode() {
|
||||
return new TagNode(this.tag.toLowerCase(), this.attrs, this.content);
|
||||
}
|
||||
|
||||
toString({ openTag = OPEN_BRAKET, closeTag = CLOSE_BRAKET } = {}): string {
|
||||
const content = this.content ? renderContent(this.content, openTag, closeTag) : ''
|
||||
const tagStart = this.toTagStart({ openTag, closeTag });
|
||||
|
||||
if (this.content === null || Array.isArray(this.content) && this.content.length === 0) {
|
||||
return tagStart;
|
||||
}
|
||||
|
||||
return `${tagStart}${content}${this.toTagEnd({ openTag, closeTag })}`;
|
||||
}
|
||||
|
||||
static create(tag: string, attrs: Record<string, unknown> = {}, content: TagNodeTree = []) {
|
||||
return new TagNode(tag, attrs, content)
|
||||
}
|
||||
|
||||
static isOf(node: TagNode, type: string) {
|
||||
return (node.tag === type)
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
import { N } from './char';
|
||||
|
||||
const isTagNode = (el) => typeof el === 'object' && !!el.tag;
|
||||
const isStringNode = (el) => typeof el === 'string';
|
||||
const isEOL = (el) => el === N;
|
||||
|
||||
const keysReduce = (obj, reduce, def) => Object.keys(obj).reduce(reduce, def);
|
||||
|
||||
const getNodeLength = (node) => {
|
||||
if (isTagNode(node)) {
|
||||
return node.content.reduce((count, contentNode) => count + getNodeLength(contentNode), 0);
|
||||
} if (isStringNode(node)) {
|
||||
return node.length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Appends value to Tag Node
|
||||
* @param {TagNode} node
|
||||
* @param value
|
||||
*/
|
||||
const appendToNode = (node, value) => {
|
||||
node.content.push(value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Replaces " to &qquot;
|
||||
* @param {String} value
|
||||
*/
|
||||
const escapeHTML = (value) => value
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
// eslint-disable-next-line no-script-url
|
||||
.replace(/(javascript|data|vbscript):/gi, '$1%3A');
|
||||
|
||||
/**
|
||||
* Acept name and value and return valid html5 attribute string
|
||||
* @param {String} name
|
||||
* @param {String} value
|
||||
* @return {string}
|
||||
*/
|
||||
const attrValue = (name, value) => {
|
||||
const type = typeof value;
|
||||
|
||||
const types = {
|
||||
boolean: () => (value ? `${name}` : ''),
|
||||
number: () => `${name}="${value}"`,
|
||||
string: () => `${name}="${escapeHTML(value)}"`,
|
||||
object: () => `${name}="${escapeHTML(JSON.stringify(value))}"`,
|
||||
};
|
||||
|
||||
return types[type] ? types[type]() : '';
|
||||
};
|
||||
|
||||
/**
|
||||
* Transforms attrs to html params string
|
||||
* @param values
|
||||
*/
|
||||
const attrsToString = (values) => {
|
||||
// To avoid some malformed attributes
|
||||
if (values == null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return keysReduce(
|
||||
values,
|
||||
(arr, key) => [...arr, attrValue(key, values[key])],
|
||||
[''],
|
||||
).join(' ');
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets value from
|
||||
* @example
|
||||
* getUniqAttr({ 'foo': true, 'bar': bar' }) => 'bar'
|
||||
* @param attrs
|
||||
* @returns {string}
|
||||
*/
|
||||
const getUniqAttr = (attrs) => keysReduce(
|
||||
attrs,
|
||||
(res, key) => (attrs[key] === key ? attrs[key] : null),
|
||||
null,
|
||||
);
|
||||
|
||||
export {
|
||||
attrsToString,
|
||||
attrValue,
|
||||
appendToNode,
|
||||
escapeHTML,
|
||||
getNodeLength,
|
||||
getUniqAttr,
|
||||
isTagNode,
|
||||
isStringNode,
|
||||
isEOL,
|
||||
};
|
||||
@@ -0,0 +1,125 @@
|
||||
import { N } from './char';
|
||||
import type { TagNode } from "./TagNode";
|
||||
import type { NodeContent, StringNode } from "./types";
|
||||
|
||||
function isTagNode(el: unknown): el is TagNode {
|
||||
return typeof el === 'object' && el !== null && 'tag' in el;
|
||||
}
|
||||
|
||||
function isStringNode(el: unknown): el is StringNode {
|
||||
return typeof el === 'string';
|
||||
}
|
||||
|
||||
// check string is end of line
|
||||
function isEOL(el: string) {
|
||||
return el === N
|
||||
}
|
||||
|
||||
function keysReduce<Res, Def extends Res, T extends Record<string, unknown>>(obj: T, reduce: (acc: Def, key: keyof T) => Res, def: Def): Res {
|
||||
const keys = Object.keys(obj)
|
||||
|
||||
return keys.reduce((acc, key) => reduce(acc, key), def)
|
||||
}
|
||||
|
||||
function getNodeLength(node: NodeContent): number {
|
||||
if (isTagNode(node) && Array.isArray(node.content)) {
|
||||
return node.content.reduce<number>((count, contentNode) => {
|
||||
return count + getNodeLength(contentNode)
|
||||
}, 0);
|
||||
}
|
||||
|
||||
if (isStringNode(node)) {
|
||||
return String(node).length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function appendToNode(node: TagNode, value: NodeContent) {
|
||||
if (Array.isArray(node.content)) {
|
||||
node.content.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces " to &qquot;
|
||||
* @param {string} value
|
||||
*/
|
||||
function escapeAttrValue(value: string) {
|
||||
return value
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
// eslint-disable-next-line no-script-url
|
||||
.replace(/(javascript|data|vbscript):/gi, '$1%3A');
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use escapeAttrValue
|
||||
*/
|
||||
const escapeHTML = escapeAttrValue
|
||||
|
||||
/**
|
||||
* Accept name and value and return valid html5 attribute string
|
||||
*/
|
||||
function attrValue<AttrValue = unknown>(name: string, value: AttrValue) {
|
||||
// in case of performance
|
||||
switch (typeof value) {
|
||||
case 'boolean':
|
||||
return value ? `${name}` : ''
|
||||
case 'number':
|
||||
return `${name}="${value}"`
|
||||
case 'string':
|
||||
return `${name}="${escapeAttrValue(value as string)}"`
|
||||
case 'object':
|
||||
return `${name}="${escapeAttrValue(JSON.stringify(value))}"`
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms attrs to html params string
|
||||
* @example
|
||||
* attrsToString({ 'foo': true, 'bar': bar' }) => 'foo="true" bar="bar"'
|
||||
*/
|
||||
function attrsToString<AttrValue = unknown>(values: Record<string, AttrValue> | null) {
|
||||
// To avoid some malformed attributes
|
||||
if (values == null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return keysReduce(
|
||||
values,
|
||||
(arr, key) => [...arr, attrValue(key, values[key])],
|
||||
[''],
|
||||
).join(' ');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets value from
|
||||
* @example
|
||||
* getUniqAttr({ 'foo': true, 'bar': bar' }) => 'bar'
|
||||
*/
|
||||
function getUniqAttr<Value>(attrs: Record<string, Value>) {
|
||||
return keysReduce(
|
||||
attrs,
|
||||
(res, key) => (attrs[key] === key ? attrs[key] : null),
|
||||
null,
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
attrsToString,
|
||||
attrValue,
|
||||
appendToNode,
|
||||
escapeHTML,
|
||||
escapeAttrValue,
|
||||
getNodeLength,
|
||||
getUniqAttr,
|
||||
isTagNode,
|
||||
isStringNode,
|
||||
isEOL,
|
||||
};
|
||||
@@ -1,3 +0,0 @@
|
||||
export * from './helpers';
|
||||
export * from './char';
|
||||
export { TagNode } from './TagNode';
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./helpers";
|
||||
export * from "./char";
|
||||
export * from "./TagNode";
|
||||
export * from "./types";
|
||||
@@ -0,0 +1,13 @@
|
||||
export type StringNode = string | number
|
||||
|
||||
export interface TagNodeObject {
|
||||
readonly tag: string
|
||||
attrs: Record<string, unknown>
|
||||
content: TagNodeTree
|
||||
}
|
||||
|
||||
export type NodeContent = TagNodeObject | StringNode | null
|
||||
|
||||
export type PartialNodeContent = Partial<TagNodeObject> | StringNode | null
|
||||
|
||||
export type TagNodeTree = NodeContent | NodeContent[] | null
|
||||
+31
@@ -13,6 +13,37 @@ describe('@bbob/plugin-helper/TagNode', () => {
|
||||
expect(TagNode.isOf(tagNode, 'test')).toBe(true);
|
||||
});
|
||||
|
||||
test('attr', () => {
|
||||
const tagNode = TagNode.create('test', {test: 1}, ['Hello']);
|
||||
|
||||
tagNode.attr('foo', 'bar')
|
||||
|
||||
expect(tagNode.attrs.foo).toBe('bar');
|
||||
});
|
||||
|
||||
test('append', () => {
|
||||
const tagNode = TagNode.create('test', {test: 1}, ['Hello']);
|
||||
|
||||
tagNode.append('World')
|
||||
|
||||
expect(tagNode.content).toEqual(['Hello', 'World']);
|
||||
});
|
||||
|
||||
test('length', () => {
|
||||
const tagNode = TagNode.create('test', {test: 1}, ['Hello', 'World']);
|
||||
|
||||
expect(tagNode.length).toEqual('HelloWorld'.length);
|
||||
});
|
||||
|
||||
test('toTagNode', () => {
|
||||
const tagNode = TagNode.create('test', {test: 1}, ['Hello']);
|
||||
const newTagNode = tagNode.toTagNode()
|
||||
|
||||
expect(newTagNode !== tagNode).toBe(true);
|
||||
expect(newTagNode.tag).toEqual(tagNode.tag);
|
||||
expect(newTagNode.content).toEqual(tagNode.content);
|
||||
});
|
||||
|
||||
describe('toString', () => {
|
||||
test('tag with content and params', () => {
|
||||
const tagNode = TagNode.create('test', {test: 1}, ['Hello']);
|
||||
@@ -1,116 +0,0 @@
|
||||
import {
|
||||
attrsToString,
|
||||
attrValue,
|
||||
appendToNode,
|
||||
getNodeLength,
|
||||
getUniqAttr,
|
||||
isTagNode,
|
||||
isStringNode,
|
||||
isEOL,
|
||||
} from '../src';
|
||||
|
||||
describe('@bbob/plugin-helper/helpers', () => {
|
||||
test('appendToNode', () => {
|
||||
const value = 'test';
|
||||
const node = { content: [] };
|
||||
|
||||
appendToNode(node, value);
|
||||
expect(node.content.pop()).toBe(value);
|
||||
});
|
||||
|
||||
test('getNodeLength', () => {
|
||||
const node = {
|
||||
tag: 'test',
|
||||
content: [
|
||||
'123',
|
||||
{
|
||||
tag: 'test2',
|
||||
content: ['123']
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
expect(getNodeLength(node)).toBe(6)
|
||||
});
|
||||
|
||||
test('isTagNode', () => {
|
||||
const node = {
|
||||
tag: 'test',
|
||||
content: []
|
||||
};
|
||||
|
||||
expect(isTagNode(node)).toBe(true)
|
||||
});
|
||||
|
||||
test('isStringNode', () => {
|
||||
const node = {
|
||||
tag: 'test',
|
||||
content: ['123']
|
||||
};
|
||||
|
||||
expect(isStringNode(node.content[0])).toBe(true);
|
||||
});
|
||||
|
||||
test('attrValue boolean', () => {
|
||||
expect(attrValue('test', true)).toBe('test');
|
||||
});
|
||||
|
||||
test('attrValue number', () => {
|
||||
expect(attrValue('test', 123)).toBe('test="123"');
|
||||
});
|
||||
|
||||
test('attrValue string', () => {
|
||||
expect(attrValue('test', 'hello')).toBe('test="hello"');
|
||||
});
|
||||
|
||||
test('attrValue object', () => {
|
||||
const attrs = { tag: 'test' };
|
||||
|
||||
expect(attrValue('test', attrs)).toBe('test="{"tag":"test"}"');
|
||||
});
|
||||
|
||||
test('isEOL', () => {
|
||||
expect(isEOL('\n')).toBe(true)
|
||||
});
|
||||
|
||||
test('attrsToString', () => {
|
||||
expect(attrsToString({
|
||||
tag: 'test',
|
||||
foo: 'bar',
|
||||
disabled: true
|
||||
})).toBe(` tag="test" foo="bar" disabled`)
|
||||
});
|
||||
|
||||
test('attrsToString undefined', () => {
|
||||
expect(attrsToString(undefined)).toBe('')
|
||||
});
|
||||
|
||||
describe('attrsToString escape', () => {
|
||||
test(`javascript:alert("hello")`, () => {
|
||||
expect(attrsToString({
|
||||
onclick: `javascript:alert('hello')`,
|
||||
href: `javascript:alert('hello')`,
|
||||
})).toBe(` onclick="javascript%3Aalert('hello')" href="javascript%3Aalert('hello')"`)
|
||||
});
|
||||
test(`JAVASCRIPT:alert("hello")`, () => {
|
||||
expect(attrsToString({
|
||||
onclick: `JAVASCRIPT:alert('hello')`,
|
||||
href: `JAVASCRIPT:alert('hello')`,
|
||||
})).toBe(` onclick="JAVASCRIPT%3Aalert('hello')" href="JAVASCRIPT%3Aalert('hello')"`)
|
||||
});
|
||||
test(`<tag>`, () => {
|
||||
expect(attrsToString({
|
||||
onclick: `<tag>`,
|
||||
href: `<tag>`,
|
||||
})).toBe(` onclick="<tag>" href="<tag>"`)
|
||||
});
|
||||
});
|
||||
|
||||
test('getUniqAttr with unq attr', () => {
|
||||
expect(getUniqAttr({foo: true, 'http://bar.com': 'http://bar.com'})).toBe('http://bar.com')
|
||||
});
|
||||
|
||||
test('getUniqAttr without unq attr', () => {
|
||||
expect(getUniqAttr({foo: true})).toBe(null)
|
||||
})
|
||||
});
|
||||
@@ -0,0 +1,117 @@
|
||||
import {
|
||||
attrsToString,
|
||||
attrValue,
|
||||
appendToNode,
|
||||
getNodeLength,
|
||||
getUniqAttr,
|
||||
isTagNode,
|
||||
isStringNode,
|
||||
isEOL,
|
||||
TagNode,
|
||||
} from '../src';
|
||||
|
||||
describe('@bbob/plugin-helper/helpers', () => {
|
||||
test('appendToNode', () => {
|
||||
const value = 'test';
|
||||
const node = {content: []} as TagNode;
|
||||
|
||||
appendToNode(node, value);
|
||||
expect(node.content.pop()).toBe(value);
|
||||
});
|
||||
|
||||
test('getNodeLength', () => {
|
||||
const node = {
|
||||
tag: 'test',
|
||||
content: [
|
||||
'123',
|
||||
{
|
||||
tag: 'test2',
|
||||
content: ['123']
|
||||
}
|
||||
]
|
||||
} as TagNode;
|
||||
|
||||
expect(getNodeLength(node)).toBe(6)
|
||||
});
|
||||
|
||||
test('isTagNode', () => {
|
||||
const node = {
|
||||
tag: 'test',
|
||||
content: []
|
||||
} as TagNode;
|
||||
|
||||
expect(isTagNode(node)).toBe(true)
|
||||
});
|
||||
|
||||
test('isStringNode', () => {
|
||||
const node = {
|
||||
tag: 'test',
|
||||
content: ['123']
|
||||
};
|
||||
|
||||
expect(isStringNode(node.content[0])).toBe(true);
|
||||
});
|
||||
|
||||
test('attrValue boolean', () => {
|
||||
expect(attrValue('test', true)).toBe('test');
|
||||
});
|
||||
|
||||
test('attrValue number', () => {
|
||||
expect(attrValue('test', 123)).toBe('test="123"');
|
||||
});
|
||||
|
||||
test('attrValue string', () => {
|
||||
expect(attrValue('test', 'hello')).toBe('test="hello"');
|
||||
});
|
||||
|
||||
test('attrValue object', () => {
|
||||
const attrs = {tag: 'test'};
|
||||
|
||||
expect(attrValue('test', attrs)).toBe('test="{"tag":"test"}"');
|
||||
});
|
||||
|
||||
test('isEOL', () => {
|
||||
expect(isEOL('\n')).toBe(true)
|
||||
});
|
||||
|
||||
test('attrsToString', () => {
|
||||
expect(attrsToString({
|
||||
tag: 'test',
|
||||
foo: 'bar',
|
||||
disabled: true
|
||||
})).toBe(` tag="test" foo="bar" disabled`)
|
||||
});
|
||||
|
||||
test('attrsToString undefined', () => {
|
||||
expect(attrsToString(undefined)).toBe('')
|
||||
});
|
||||
|
||||
describe('attrsToString escape', () => {
|
||||
test(`javascript:alert("hello")`, () => {
|
||||
expect(attrsToString({
|
||||
onclick: `javascript:alert('hello')`,
|
||||
href: `javascript:alert('hello')`,
|
||||
})).toBe(` onclick="javascript%3Aalert('hello')" href="javascript%3Aalert('hello')"`)
|
||||
});
|
||||
test(`JAVASCRIPT:alert("hello")`, () => {
|
||||
expect(attrsToString({
|
||||
onclick: `JAVASCRIPT:alert('hello')`,
|
||||
href: `JAVASCRIPT:alert('hello')`,
|
||||
})).toBe(` onclick="JAVASCRIPT%3Aalert('hello')" href="JAVASCRIPT%3Aalert('hello')"`)
|
||||
});
|
||||
test(`<tag>`, () => {
|
||||
expect(attrsToString({
|
||||
onclick: `<tag>`,
|
||||
href: `<tag>`,
|
||||
})).toBe(` onclick="<tag>" href="<tag>"`)
|
||||
});
|
||||
});
|
||||
|
||||
test('getUniqAttr with unq attr', () => {
|
||||
expect(getUniqAttr({foo: true, 'http://bar.com': 'http://bar.com'})).toBe('http://bar.com')
|
||||
});
|
||||
|
||||
test('getUniqAttr without unq attr', () => {
|
||||
expect(getUniqAttr({foo: true})).toBe(null)
|
||||
})
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"outDir": "./types"
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user