bunch uf utils

pull/8569/head
Simon Holthausen 3 years ago
parent 49880c0930
commit dfee586567

@ -1,14 +1,14 @@
import * as assert from 'assert';
import get_name_from_filename from './get_name_from_filename';
import get_name_from_filename from './get_name_from_filename.js';
import {
is_contenteditable,
has_contenteditable_attr,
is_name_contenteditable,
get_contenteditable_attr,
CONTENTEDITABLE_BINDINGS
} from './contenteditable';
import Element from '../nodes/Element';
import Attribute from '../nodes/Attribute';
} from './contenteditable.js';
import Element from '../nodes/Element.js';
import Attribute from '../nodes/Attribute.js';
describe('get_name_from_filename', () => {
it('uses the basename', () => {
@ -33,34 +33,34 @@ describe('get_name_from_filename', () => {
describe('contenteditable', () => {
describe('is_contenteditable', () => {
it('returns false if node is input', () => {
const node = { name: 'input' } as Element;
const node = /** @type {Element} */ ({ name: 'input' });
assert.equal(is_contenteditable(node), false);
});
it('returns false if node is textarea', () => {
const node = { name: 'textarea' } as Element;
const node = /** @type {Element} */ ({ name: 'textarea' });
assert.equal(is_contenteditable(node), false);
});
it('returns false if node is not input or textarea AND it is not contenteditable', () => {
const attr = { name: 'href' } as Attribute;
const node = { name: 'a', attributes: [attr] } as Element;
const attr = /** @type {Attribute} */ ({ name: 'href' });
const node = /** @type {Element} */ ({ name: 'a', attributes: [attr] });
assert.equal(is_contenteditable(node), false);
});
it('returns true if node is not input or textarea AND it is contenteditable', () => {
const attr = { name: 'contenteditable' } as Attribute;
const node = { name: 'a', attributes: [attr] } as Element;
const attr = /** @type {Attribute} */ ({ name: 'contenteditable' });
const node = /** @type {Element} */ ({ name: 'a', attributes: [attr] });
assert.equal(is_contenteditable(node), true);
});
});
describe('has_contenteditable_attr', () => {
it('returns true if attribute is contenteditable', () => {
const attr = { name: 'contenteditable' } as Attribute;
const node = { attributes: [attr] } as Element;
const attr = /** @type {Attribute} */ ({ name: 'contenteditable' });
const node = /** @type {Element} */ ({ attributes: [attr] });
assert.equal(has_contenteditable_attr(node), true);
});
it('returns false if attribute is not contenteditable', () => {
const attr = { name: 'href' } as Attribute;
const node = { attributes: [attr] } as Element;
const attr = /** @type {Attribute} */ ({ name: 'href' });
const node = /** @type {Element} */ ({ attributes: [attr] });
assert.equal(has_contenteditable_attr(node), false);
});
});
@ -76,12 +76,12 @@ describe('contenteditable', () => {
describe('get_contenteditable_attr', () => {
it('returns the contenteditable Attribute if it exists', () => {
const attr = { name: 'contenteditable' } as Attribute;
const node = { name: 'div', attributes: [attr] } as Element;
const attr = /** @type {Attribute} */ ({ name: 'contenteditable' });
const node = /** @type {Element} */ ({ name: 'div', attributes: [attr] });
assert.equal(get_contenteditable_attr(node), attr);
});
it('returns undefined if contenteditable attribute cannot be found', () => {
const node = { name: 'div', attributes: [] } as Element;
const node = /** @type {Element} */ ({ name: 'div', attributes: [] });
assert.equal(get_contenteditable_attr(node), undefined);
});
});

@ -0,0 +1,11 @@
/**
* @template T
* @param {Set<T>} a
* @param {Set<T> | T[]} b
*/
export default function add_to_set(a, b) {
// @ts-ignore
b.forEach((item) => {
a.add(item);
});
}

@ -1,6 +0,0 @@
export default function add_to_set<T>(a: Set<T>, b: Set<T> | T[]) {
// @ts-ignore
b.forEach((item) => {
a.add(item);
});
}

@ -0,0 +1,7 @@
/**
* @param {import("../../interfaces.js").EnableSourcemap} enable_sourcemap
* @param {keyof Extract<import("../../interfaces.js").EnableSourcemap, object>} namespace
*/
export default function check_enable_sourcemap(enable_sourcemap, namespace) {
return typeof enable_sourcemap === 'boolean' ? enable_sourcemap : enable_sourcemap[namespace];
}

@ -1,8 +0,0 @@
import { EnableSourcemap } from '../../interfaces';
export default function check_enable_sourcemap(
enable_sourcemap: EnableSourcemap,
namespace: keyof Extract<EnableSourcemap, object>
) {
return typeof enable_sourcemap === 'boolean' ? enable_sourcemap : enable_sourcemap[namespace];
}

@ -1,5 +1,10 @@
export default function check_graph_for_cycles(edges: Array<[any, any]>): any[] {
const graph: Map<any, any[]> = edges.reduce((g, edge) => {
/**
* @param {Array<[any, any]>} edges
* @returns {any[]}
*/
export default function check_graph_for_cycles(edges) {
/** @type {Map<any, any[]>} */
const graph = edges.reduce((g, edge) => {
const [u, v] = edge;
if (!g.has(u)) g.set(u, []);
if (!g.has(v)) g.set(v, []);

@ -1,10 +1,10 @@
import { TemplateLiteral } from 'estree';
import { escape_template } from './stringify';
import { escape_template } from './stringify.js';
/**
* Collapse string literals together
* @param {import('estree').TemplateLiteral} literal
*/
export function collapse_template_literal(literal: TemplateLiteral) {
export function collapse_template_literal(literal) {
if (!literal.quasis.length) return;
const collapsed_quasis = [];

@ -0,0 +1,21 @@
/**
* @param {import('estree').Node | void} a
* @param {import('estree').Node | void} b
*/
export function compare_node(a, b) {
if (a === b) return true;
if (!a || !b) return false;
if (a.type !== b.type) return false;
switch (a.type) {
case 'Identifier':
return a.name === /** @type {import('estree').Identifier} */ (b).name;
case 'MemberExpression':
return (
compare_node(a.object, /** @type {import('estree').MemberExpression} */ (b).object) &&
compare_node(a.property, /** @type {import('estree').MemberExpression} */ (b).property) &&
a.computed === /** @type {import('estree').MemberExpression} */ (b).computed
);
case 'Literal':
return a.value === /** @type {import('estree').Literal} */ (b).value;
}
}

@ -1,19 +0,0 @@
import { Node, Literal, Identifier, MemberExpression } from 'estree';
export function compare_node(a: Node | void, b: Node | void) {
if (a === b) return true;
if (!a || !b) return false;
if (a.type !== b.type) return false;
switch (a.type) {
case 'Identifier':
return a.name === (b as Identifier).name;
case 'MemberExpression':
return (
compare_node(a.object, (b as MemberExpression).object) &&
compare_node(a.property, (b as MemberExpression).property) &&
a.computed === (b as MemberExpression).computed
);
case 'Literal':
return a.value === (b as Literal).value;
}
}

@ -1,6 +1,6 @@
// Utilities for managing contenteditable nodes
import Attribute from '../nodes/Attribute';
import Element from '../nodes/Element';
import Attribute from '../nodes/Attribute.js';
import Element from '../nodes/Element.js';
export const CONTENTEDITABLE_BINDINGS = ['textContent', 'innerHTML', 'innerText'];
@ -8,7 +8,7 @@ export const CONTENTEDITABLE_BINDINGS = ['textContent', 'innerHTML', 'innerText'
* Returns true if node is an 'input' or 'textarea'.
* @param {Element} node The element to be checked
*/
function is_input_or_textarea(node: Element): boolean {
function is_input_or_textarea(node) {
return node.name === 'textarea' || node.name === 'input';
}
@ -16,7 +16,7 @@ function is_input_or_textarea(node: Element): boolean {
* Check if a given attribute is 'contenteditable'.
* @param {Attribute} attribute A node.attribute
*/
function is_attr_contenteditable(attribute: Attribute): boolean {
function is_attr_contenteditable(attribute) {
return attribute.name === 'contenteditable';
}
@ -24,7 +24,7 @@ function is_attr_contenteditable(attribute: Attribute): boolean {
* Check if any of a node's attributes are 'contentenditable'.
* @param {Element} node The element to be checked
*/
export function has_contenteditable_attr(node: Element): boolean {
export function has_contenteditable_attr(node) {
return node.attributes.some(is_attr_contenteditable);
}
@ -32,7 +32,7 @@ export function has_contenteditable_attr(node: Element): boolean {
* Returns true if node is not textarea or input, but has 'contenteditable' attribute.
* @param {Element} node The element to be tested
*/
export function is_contenteditable(node: Element): boolean {
export function is_contenteditable(node) {
return !is_input_or_textarea(node) && has_contenteditable_attr(node);
}
@ -40,7 +40,7 @@ export function is_contenteditable(node: Element): boolean {
* Returns true if a given binding/node is contenteditable.
* @param {string} name A binding or node name to be checked
*/
export function is_name_contenteditable(name: string): boolean {
export function is_name_contenteditable(name) {
return CONTENTEDITABLE_BINDINGS.includes(name);
}
@ -48,6 +48,6 @@ export function is_name_contenteditable(name: string): boolean {
* Returns the contenteditable attribute from the node (if it exists).
* @param {Element} node The element to get the attribute from
*/
export function get_contenteditable_attr(node: Element): Attribute | undefined {
export function get_contenteditable_attr(node) {
return node.attributes.find(is_attr_contenteditable);
}

@ -1,6 +1,7 @@
import { Node, Identifier } from 'estree';
export default function flatten_reference(node: Node) {
/**
* @param {import('estree').Node} node
*/
export default function flatten_reference(node) {
const nodes = [];
const parts = [];
@ -8,7 +9,7 @@ export default function flatten_reference(node: Node) {
nodes.unshift(node.property);
if (!node.computed) {
parts.unshift((node.property as Identifier).name);
parts.unshift(/** @type {import('estree').Identifier} */ (node.property).name);
} else {
const computed_property = to_string(node.property);
if (computed_property) {
@ -28,7 +29,10 @@ export default function flatten_reference(node: Node) {
return { name, nodes, parts };
}
function to_string(node: Node) {
/**
* @param {import('estree').Node} node
*/
function to_string(node) {
switch (node.type) {
case 'Literal':
return String(node.value);

@ -4,7 +4,10 @@ const regex_repeated_invalid_variable_identifier_characters = /[^a-zA-Z_$0-9]+/g
const regex_starts_with_digit = /^(\d)/;
const regex_may_starts_or_ends_with_underscore = /^_?(.+?)_?$/;
export default function get_name_from_filename(filename: string) {
/**
* @param {string} filename
*/
export default function get_name_from_filename(filename) {
if (!filename) return null;
const parts = filename.split(/[/\\]/).map(encodeURI);

@ -0,0 +1,7 @@
/**
* @param {import('estree').Node} node
*/
export default function get_object(node) {
while (node.type === 'MemberExpression') node = node.object;
return /** @type {import('estree').Identifier} */ (node);
}

@ -1,6 +0,0 @@
import { Node, Identifier } from 'estree';
export default function get_object(node: Node): Identifier {
while (node.type === 'MemberExpression') node = node.object;
return node as Identifier;
}

@ -2,7 +2,11 @@
const regex_return_characters = /\r/g;
export default function hash(str: string): string {
/**
* @param {string} str
* @returns {string}
*/
export default function hash(str) {
str = str.replace(regex_return_characters, '');
let hash = 5381;
let i = str.length;

@ -1,8 +1,18 @@
import { Node } from 'estree';
import is_reference, { NodeWithPropertyDefinition } from 'is-reference';
import is_reference from 'is-reference';
export default function is_used_as_reference(node: Node, parent: Node): boolean {
if (!is_reference(node as NodeWithPropertyDefinition, parent as NodeWithPropertyDefinition)) {
/**
*
* @param {import('estree').Node} node
* @param {import('estree').Node} parent
* @returns {boolean}
*/
export default function is_used_as_reference(node, parent) {
if (
!is_reference(
/** @type {import('is-reference').NodeWithPropertyDefinition} */ (node),
/** @type {import('is-reference').NodeWithPropertyDefinition} */ (parent)
)
) {
return false;
}
if (!parent) {

@ -0,0 +1,16 @@
/**
* @param {import('estree').Node} node
* @param {import('estree').Node} replacement
*/
export default function replace_object(node, replacement) {
if (node.type === 'Identifier') return replacement;
const ancestor = node;
let parent;
while (node.type === 'MemberExpression') {
parent = node;
node = node.object;
}
parent.object = /** @type {any} */ (replacement);
return ancestor;
}

@ -1,14 +0,0 @@
import { Node } from 'estree';
export default function replace_object(node: Node, replacement: Node) {
if (node.type === 'Identifier') return replacement;
const ancestor = node;
let parent;
while (node.type === 'MemberExpression') {
parent = node;
node = node.object;
}
parent.object = replacement;
return ancestor;
}

@ -1,5 +1,6 @@
export const reserved_keywords = new Set(['$$props', '$$restProps', '$$slots']);
/** @param {string} name */
export function is_reserved_keyword(name) {
return reserved_keywords.has(name);
}

@ -1,7 +1,9 @@
import { Node } from 'estree';
import { analyze, Scope, extract_names, extract_identifiers } from 'periscopic';
export function create_scopes(expression: Node) {
/**
* @param {import('estree').Node} expression
*/
export function create_scopes(expression) {
return analyze(expression);
}

@ -0,0 +1,19 @@
/**
* @param {string} name
*/
export function string_to_member_expression(name) {
const parts = name.split('.');
/** @type {import('estree').MemberExpression | import('estree').Identifier} */
let node = {
type: 'Identifier',
name: parts[0]
};
for (let i = 1; i < parts.length; i++) {
node = /** @type {import('estree').MemberExpression} */ ({
type: 'MemberExpression',
object: node,
property: { type: 'Identifier', name: parts[i] }
});
}
return node;
}

@ -1,17 +0,0 @@
import { MemberExpression, Identifier } from 'estree';
export function string_to_member_expression(name: string) {
const parts = name.split('.');
let node: MemberExpression | Identifier = {
type: 'Identifier',
name: parts[0]
};
for (let i = 1; i < parts.length; i++) {
node = {
type: 'MemberExpression',
object: node,
property: { type: 'Identifier', name: parts[i] }
} as MemberExpression;
}
return node;
}

@ -1,13 +1,19 @@
import { Literal } from 'estree';
export function string_literal(data: string): Literal {
/**
* @param {string} data
* @returns {import('estree').Literal}
*/
export function string_literal(data) {
return {
type: 'Literal',
value: data
};
}
export function escape(data: string, { only_escape_at_symbol = false } = {}) {
return data.replace(only_escape_at_symbol ? /@+/g : /(@+|#+)/g, (match: string) => {
/**
* @param {string} data
* @param {{ only_escape_at_symbol?: boolean }} [options]
*/
export function escape(data, { only_escape_at_symbol = false } = {}) {
return data.replace(only_escape_at_symbol ? /@+/g : /(@+|#+)/g, (match) => {
return match + match[0];
});
}
Loading…
Cancel
Save