Skip to content

Commit

Permalink
⚡️refactor everything
Browse files Browse the repository at this point in the history
  • Loading branch information
nberlette committed Jul 12, 2022
1 parent 9cdfc09 commit 9d34b2c
Show file tree
Hide file tree
Showing 6 changed files with 303 additions and 75 deletions.
48 changes: 43 additions & 5 deletions deps.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,58 @@
export {
graphql,
GraphQLBoolean,
type GraphQLFieldConfigMap,
GraphQLDeprecatedDirective,
GraphQLEnumType,
GraphQLError,
GraphQLInputObjectType,
GraphQLInt,
GraphQLInterfaceType,
type GraphQLInterfaceTypeConfig,
GraphQLList,
GraphQLNonNull,
GraphQLObjectType,
type GraphQLObjectTypeConfig,
GraphQLScalarType,
GraphQLSchema,
GraphQLString,
graphqlSync,
GraphQLUnionType,
} from "https://deno.land/x/graphql_deno@v15.0.0/mod.ts";

export type {
GraphQLAbstractType,
GraphQLCompositeType,
GraphQLEnumTypeConfig,
GraphQLEnumValue,
GraphQLEnumValueConfig,
GraphQLEnumValueConfigMap,
GraphQLField,
GraphQLFieldConfig,
GraphQLFieldConfigMap,
GraphQLFieldMap,
GraphQLFormattedError,
GraphQLInputObjectTypeConfig,
GraphQLInterfaceTypeConfig,
GraphQLNamedType,
GraphQLNullableType,
GraphQLObjectTypeConfig,
GraphQLSchemaConfig,
GraphQLType,
GraphQLTypeResolver,
GraphQLUnionTypeConfig,
Thunk,
} from "https://deno.land/x/graphql_deno@v15.0.0/mod.ts";

export { default as PQueue } from "https://deno.land/x/p_queue@1.0.1/mod.ts";

export {
denoDomDisableQuerySelectorCodeGeneration as disableCodeGen,
DOMParser,
Element,
} from "https://deno.land/x/deno_dom@v0.1.31-alpha/deno-dom-wasm.ts";
export { serve } from "https://deno.land/std@0.145.0/http/server.ts";

export type { Element } from "https://deno.land/x/deno_dom@v0.1.31-alpha/deno-dom-wasm.ts";

export {
serve,
type ServeInit,
Server,
type ServerInit,
} from "https://deno.land/std@0.145.0/http/server.ts";
6 changes: 5 additions & 1 deletion lib/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ export const TDocument = new GraphQLObjectType({
if (!meta) {
meta = element?.querySelector(`meta[property='${name}']`);
}
return getAttributeOfElement(meta!, "content") ?? null;
try {
return getAttributeOfElement(meta!, "content");
} catch {
return null;
}
},
},
}),
Expand Down
28 changes: 24 additions & 4 deletions lib/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,34 @@
import { Element } from "../deps.ts";

export function getAttributeOfElement(element: Element, name: string) {
export function getAttributeOfElement(
element: Element,
name?: string,
trim = false,
): string | null {
if (element == null || name == null) {
return null;
}
const attribute = element.getAttribute(name);
if (attribute == null) return null;
if (attribute == null) {
return null;
}
return trim ? attribute.trim() : attribute;
}

return attribute;
export function getAttributesOfElement(element: Element, trim = false) {
if (element == null) {
return null;
}
const names = element.getAttributeNames();
if (names == null || names.length === 0) {
return {};
}
return Object.fromEntries(names.map(
(attr) => [attr, getAttributeOfElement(element, attr, trim)],
));
}

export function resolveURL(base: string, url: string) {
const uri = new URL(url, base);

return uri.toString();
}
104 changes: 63 additions & 41 deletions lib/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ export const shared: GraphQLFieldConfigMap<Element, any> = {
selector,
trim: {
type: GraphQLBoolean,
description: "Trim any leading and trailing whitespace from the value (optional, default: false)",
description:
"Trim any leading and trailing whitespace from the value (optional, default: false)",
defaultValue: false,
},
},
Expand All @@ -79,22 +80,30 @@ export const shared: GraphQLFieldConfigMap<Element, any> = {
},
table: {
type: new GraphQLList(new GraphQLList(GraphQLString)),
description: "Returns a two-dimensional array representing an HTML table element's contents. The first level is a list of rows (`<tr>`), and each row is an array of cell (`<td>`) contents.",
description:
"Returns a two-dimensional array representing an HTML table element's contents. The first level is a list of rows (`<tr>`), and each row is an array of cell (`<td>`) contents.",
args: {
selector,
trim: {
type: GraphQLBoolean,
description:
"Trim any leading and trailing whitespace from the values (optional, default: false)",
defaultValue: false,
},
},
resolve(element: Element, { selector }: ElementParams) {
resolve(element: Element, { selector, trim }: TextParams) {
element = selector ? element.querySelector(selector)! : element;

const result = element && Array.from(
element.querySelectorAll("tr"),
).map((row) =>
Array.from((row as Element).querySelectorAll("td")).map((td) =>
td.textContent.trim()
)
(row) =>
Array.from(
(row as Element).querySelectorAll("td"),
(td) => (trim ? td.textContent.trim() : td.textContent),
),
);

return result.filter((row) => row.length > 0);
return result.filter(Boolean).filter((row) => row.length > 0);
},
},
tag: {
Expand All @@ -103,71 +112,85 @@ export const shared: GraphQLFieldConfigMap<Element, any> = {
args: { selector },
resolve(element: Element, { selector }: ElementParams) {
element = selector ? element.querySelector(selector)! : element;

return element && element.tagName;
return element?.tagName ?? null;
},
},
attr: {
type: GraphQLString,
description: "The value of a given attribute from the selected node (`href`, `src`, etc.), if it exists.",
description:
"The value of a given attribute from the selected node (`href`, `src`, etc.), if it exists.",
args: {
selector,
name: {
type: new GraphQLNonNull(GraphQLString),
description: "The name of the attribute",
},
trim: {
type: GraphQLBoolean,
description:
"Trim any leading and trailing whitespace from the value (optional, default: false)",
defaultValue: false,
},
},
resolve(element: Element, { selector, name }: TParams) {
resolve(element: Element, { selector, name, trim }: TParams) {
element = selector ? element.querySelector(selector)! : element;
if (element == null || name == null) {
return null;
}

const attribute = element.getAttribute(name);
if (attribute == null) {
return null;
}

return attribute;
return getAttributeOfElement(element, name as string, trim);
},
},
href: {
type: GraphQLString,
description: "Shorthand for `attr(name: \"href\")`",
description: "Shorthand for `attr(name: 'href')`",
args: {
selector,
trim: {
type: GraphQLBoolean,
description:
"Trim any leading and trailing whitespace from the value (optional, default: false)",
defaultValue: false,
},
},
resolve(element: Element, { selector }: ElementParams) {
resolve(element: Element, { selector, trim }: TextParams) {
element = selector ? element.querySelector(selector)! : element;
if (element == null) return null;

return getAttributeOfElement(element, "href");
return getAttributeOfElement(element, "href", trim);
},
},
src: {
type: GraphQLString,
description: "Shorthand for `attr(name: \"src\")`",
description: "Shorthand for `attr(name: 'src')`",
args: {
selector,
trim: {
type: GraphQLBoolean,
description:
"Trim any leading and trailing whitespace from the value (optional, default: false)",
defaultValue: false,
},
},
resolve(element: Element, { selector }: ElementParams) {
resolve(element: Element, { selector, trim }: TextParams) {
element = selector ? element.querySelector(selector)! : element;
if (element == null) return null;

return getAttributeOfElement(element, "src");
return getAttributeOfElement(element, "src", trim);
},
},
class: {
type: GraphQLString,
description: "The class attribute of the selected node, if any exists. Formatted as a space-separated list of CSS class names.",
description:
"The class attribute of the selected node, if any exists. Formatted as a space-separated list of CSS class names.",
args: {
selector,
trim: {
type: GraphQLBoolean,
description:
"Trim any leading and trailing whitespace from the value (optional, default: false)",
defaultValue: false,
},
},
resolve(element: Element, { selector }: TParams) {
resolve(element: Element, { selector, trim }: TextParams) {
element = selector ? element.querySelector(selector)! : element;
if (element == null) return null;

return getAttributeOfElement(element, "class");
return getAttributeOfElement(element, "class", trim);
},
},
classList: {
Expand All @@ -179,24 +202,22 @@ export const shared: GraphQLFieldConfigMap<Element, any> = {
resolve(element: Element, { selector }: ElementParams) {
element = selector ? element.querySelector(selector)! : element;
if (element == null) return null;

const attribute = getAttributeOfElement(element, "class");
if (attribute == null) return null;

return attribute.split(" ");
return [...(element?.classList.values() ?? [])];
},
},
has: {
type: GraphQLBoolean,
description: "Returns true if an element with the given selector exists, otherwise false.",
description:
"Returns true if an element with the given selector exists, otherwise false.",
args: { selector },
resolve(element: Element, { selector }: ElementParams) {
return !!element.querySelector(selector!);
},
},
count: {
type: GraphQLInt,
description: "Returns the number of DOM nodes that match the given selector, or 0 if no nodes match.",
description:
"Returns the number of DOM nodes that match the given selector, or 0 if no nodes match.",
args: { selector },
resolve(element: Element, { selector }: ElementParams) {
if (!selector) return 0;
Expand Down Expand Up @@ -231,7 +252,8 @@ export const shared: GraphQLFieldConfigMap<Element, any> = {
},
childNodes: {
type: new GraphQLList(TElement),
description: "Child nodes (not elements) of a selected node, including any text nodes.",
description:
"Child nodes (not elements) of a selected node, including any text nodes.",
resolve(element: Element) {
return Array.from(element.childNodes);
},
Expand Down
Loading

0 comments on commit 9d34b2c

Please sign in to comment.