Skip to content

Commit

Permalink
Fix web builds (#3973)
Browse files Browse the repository at this point in the history
  • Loading branch information
fb55 committed Aug 5, 2024
1 parent caab069 commit c07bbf0
Show file tree
Hide file tree
Showing 11 changed files with 213 additions and 22 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ npm-debug.log
.cache-loader
/coverage
/.tshy
/.tshy-build
/dist
/website/docs/api
/website/build
2 changes: 1 addition & 1 deletion benchmark/benchmark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { Element } from 'domhandler';
import type { Cheerio } from '../src/cheerio.js';
import type { CheerioAPI } from '../src/load.js';
import { JSDOM } from 'jsdom';
import { load } from '../src/index-browser.js';
import { load } from '../src/base-exports.js';

const documentDir = new URL('documents/', import.meta.url);
const jQuerySrc = await fs.readFile(
Expand Down
29 changes: 17 additions & 12 deletions src/__fixtures__/fixtures.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
export const fruits = [
export const fruits: string = [
'<ul id="fruits">',
'<li class="apple">Apple</li>',
'<li class="orange">Orange</li>',
'<li class="pear">Pear</li>',
'</ul>',
].join('');

export const vegetables = [
export const vegetables: string = [
'<ul id="vegetables">',
'<li class="carrot">Carrot</li>',
'<li class="sweetcorn">Sweetcorn</li>',
'</ul>',
].join('');

export const divcontainers = [
export const divcontainers: string = [
'<div class="container">',
'<div class="inner">First</div>',
'<div class="inner">Second</div>',
Expand All @@ -27,15 +27,15 @@ export const divcontainers = [
'</div>',
].join('');

export const chocolates = [
export const chocolates: string = [
'<ul id="chocolates">',
'<li class="linth" data-highlight="Lindor" data-origin="swiss">Linth</li>',
'<li class="frey" data-taste="sweet" data-best-collection="Mahony">Frey</li>',
'<li class="cailler">Cailler</li>',
'</ul>',
].join('');

export const drinks = [
export const drinks: string = [
'<ul id="drinks">',
'<li class="beer">Beer</li>',
'<li class="juice">Juice</li>',
Expand All @@ -45,7 +45,12 @@ export const drinks = [
'</ul>',
].join('');

export const food = ['<ul id="food">', fruits, vegetables, '</ul>'].join('');
export const food: string = [
'<ul id="food">',
fruits,
vegetables,
'</ul>',
].join('');

export const eleven = `
<html>
Expand Down Expand Up @@ -73,15 +78,15 @@ export const eleven = `
</html>
`;

export const unwrapspans = [
export const unwrapspans: string = [
'<div id=unwrap style="display: none;">',
'<div id=unwrap1><span class=unwrap>a</span><span class=unwrap>b</span></div>',
'<div id=unwrap2><span class=unwrap>c</span><span class=unwrap>d</span></div>',
'<div id=unwrap3><b><span class="unwrap unwrap3">e</span></b><b><span class="unwrap unwrap3">f</span></b></div>',
'</div>',
].join('');

export const inputs = [
export const inputs: string = [
'<select id="one"><option value="option_not_selected">Option not selected</option><option value="option_selected" selected>Option selected</option></select>',
'<select id="one-valueless"><option>Option not selected</option><option selected>Option selected</option></select>',
'<select id="one-html-entity"><option>Option not selected</option><option selected>Option &lt;selected&gt;</option></select>',
Expand All @@ -96,12 +101,12 @@ export const inputs = [
'<select id="multi-valueless" multiple><option>1</option><option selected>2</option><option selected>3</option><option>4</option></select>',
].join('');

export const text = [
export const text: string = [
'<p>Apples, <b>oranges</b> and pears.</p>',
'<p>Carrots and <!-- sweetcorn --></p>',
].join('');

export const forms = [
export const forms: string = [
'<form id="simple"><input type="text" name="fruit" value="Apple" /></form>',
'<form id="nested"><div><input type="text" name="fruit" value="Apple" /></div><input type="text" name="vegetable" value="Carrot" /></form>',
'<form id="disabled"><input type="text" name="fruit" value="Apple" disabled /></form>',
Expand All @@ -113,7 +118,7 @@ export const forms = [
'<form id="spaces"><input type="text" name="fruit" value="Blood orange" /></form>',
].join('');

export const noscript = [
export const noscript: string = [
'</body>',
'<noscript>',
'<!-- anchor linking to external file -->',
Expand All @@ -123,7 +128,7 @@ export const noscript = [
'</body>',
].join('');

export const script = [
export const script: string = [
'<div>',
'<a>A</a>',
'<script>',
Expand Down
6 changes: 3 additions & 3 deletions src/api/extract.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, it, expect } from 'vitest';
import * as fixtures from '../__fixtures__/fixtures.js';
import cheerio from '../index-browser.js';
import { load } from '../base-exports.js';

interface RedSelObject {
red: string | undefined;
Expand All @@ -14,8 +14,8 @@ interface RedSelMultipleObject {

describe('$.extract', () => {
it('() : should extract values for selectors', () => {
const $ = cheerio.load(fixtures.eleven);
const $root = cheerio.load(fixtures.eleven).root();
const $ = load(fixtures.eleven);
const $root = load(fixtures.eleven).root();
// An empty object should lead to an empty extraction.

// $ExpectType ExtractedMap<{}>
Expand Down
30 changes: 30 additions & 0 deletions src/base-exports.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { describe, it, expect } from 'vitest';
import * as cheerio from './base-exports.js';
import * as statics from './static.js';

describe('static method re-exports', () => {
it('should export expected static methods', () => {
for (const key of Object.keys(statics) as (keyof typeof statics)[]) {
if (key === 'extract') continue;
expect(typeof cheerio[key]).toBe(typeof statics[key]);
}
});

it('should have a functional `html` that is bound to the default instance', () => {
expect(cheerio.html(cheerio.default('<div>test div</div>'))).toBe(
'<div>test div</div>',
);
});

it('should have a functional `xml` that is bound to the default instance', () => {
expect(cheerio.xml(cheerio.default('<div>test div</div>'))).toBe(
'<div>test div</div>',
);
});

it('should have a functional `text` that is bound to the default instance', () => {
expect(cheerio.text(cheerio.default('<div>test div</div>'))).toBe(
'test div',
);
});
});
148 changes: 148 additions & 0 deletions src/base-exports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { type CheerioAPI, getLoad } from './load.js';
import { getParse } from './parse.js';
import { renderWithParse5, parseWithParse5 } from './parsers/parse5-adapter.js';
import * as staticMethods from './static.js';
import type { BasicAcceptedElems } from './types.js';
import type { CheerioOptions } from './options.js';
import renderWithHtmlparser2 from 'dom-serializer';
import { parseDocument as parseWithHtmlparser2 } from 'htmlparser2';
import type { AnyNode } from 'domhandler';

/**
* The main types of Cheerio objects.
*
* @category Cheerio
*/
export type { Cheerio } from './cheerio.js';

/**
* Types used in signatures of Cheerio methods.
*
* @category Cheerio
*/
export * from './types.js';
export type { CheerioOptions, HTMLParser2Options } from './options.js';
export type { CheerioAPI } from './load.js';
export { contains, merge } from './static.js';

const parse = getParse((content, options, isDocument, context) =>
options._useHtmlParser2
? parseWithHtmlparser2(content, options)
: parseWithParse5(content, options, isDocument, context),
);

// Duplicate docs due to https://github.com/TypeStrong/typedoc/issues/1616
/**
* Create a querying function, bound to a document created from the provided
* markup.
*
* Note that similar to web browser contexts, this operation may introduce
* `<html>`, `<head>`, and `<body>` elements; set `isDocument` to `false` to
* switch to fragment mode and disable this.
*
* @category Loading
* @param content - Markup to be loaded.
* @param options - Options for the created instance.
* @param isDocument - Allows parser to be switched to fragment mode.
* @returns The loaded document.
* @see {@link https://cheerio.js.org#loading} for additional usage information.
*/
export const load: (
content: string | AnyNode | AnyNode[] | Buffer,
options?: CheerioOptions | null,
isDocument?: boolean,
) => CheerioAPI = getLoad(parse, (dom, options) =>
options._useHtmlParser2
? renderWithHtmlparser2(dom, options)
: renderWithParse5(dom),
);

const defaultInstance: CheerioAPI = load([]);

/**
* The default cheerio instance.
*
* @deprecated Use the function returned by `load` instead. To access load, make
* sure you are importing `* as cheerio` instead of this default export.
* @category Deprecated
*/
export default defaultInstance;

/**
* Renders the document.
*
* @deprecated Use `html` on the loaded instance instead.
* @category Deprecated
* @param dom - Element to render.
* @param options - Options for the renderer.
* @returns The rendered document.
*/
export const html: (
dom: BasicAcceptedElems<AnyNode>,
options?: CheerioOptions,
) => string = staticMethods.html.bind(defaultInstance);

/**
* Render the document as XML.
*
* @deprecated Use `xml` on the loaded instance instead.
* @category Deprecated
* @param dom - Element to render.
* @returns The rendered document.
*/
export const xml: (dom: BasicAcceptedElems<AnyNode>) => string =
staticMethods.xml.bind(defaultInstance);

/**
* Render the document as text.
*
* This returns the `textContent` of the passed elements. The result will
* include the contents of `<script>` and `<style>` elements. To avoid this, use
* `.prop('innerText')` instead.
*
* @deprecated Use `text` on the loaded instance instead.
* @category Deprecated
* @param elements - Elements to render.
* @returns The rendered document.
*/
export const text: (elements: ArrayLike<AnyNode>) => string =
staticMethods.text.bind(defaultInstance);

/**
* The `.parseHTML` method exported by the Cheerio module is deprecated.
*
* In order to promote consistency with the jQuery library, users are encouraged
* to instead use the static method of the same name as it is defined on the
* "loaded" Cheerio factory function.
*
* @deprecated Use `parseHTML` on the loaded instance instead.
* @category Deprecated
* @example
*
* ```js
* const $ = cheerio.load('');
* $.parseHTML('<b>markup</b>');
* ```
*/
export const parseHTML = staticMethods.parseHTML.bind(
defaultInstance,
) as typeof staticMethods.parseHTML;

/**
* The `.root` method exported by the Cheerio module is deprecated.
*
* Users seeking to access the top-level element of a parsed document should
* instead use the `root` static method of a "loaded" Cheerio function.
*
* @deprecated Use `root` on the loaded instance instead.
* @category Deprecated
* @example
*
* ```js
* const $ = cheerio.load('');
* $.root();
* ```
*/
export const root = staticMethods.root.bind(
defaultInstance,
) as typeof staticMethods.root;
3 changes: 3 additions & 0 deletions src/index-browser.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './base-exports.js';
// TODO: Remove this
export { default } from './base-exports.js';
8 changes: 4 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
* convenience methods for loading documents from various sources.
*/

export * from './index-browser.js';
export * from './base-exports.js';
// TODO: Remove this
export { default } from './index-browser.js';
export { default } from './base-exports.js';

/* eslint-disable n/no-unsupported-features/node-builtins */

import type { CheerioAPI, CheerioOptions } from './index-browser.js';
import { load } from './index-browser.js';
import type { CheerioAPI, CheerioOptions } from './base-exports.js';
import { load } from './base-exports.js';
import { flattenOptions, type InternalOptions } from './options.js';
import { adapter as htmlparser2Adapter } from 'parse5-htmlparser2-tree-adapter';

Expand Down
4 changes: 4 additions & 0 deletions tsconfig.typedoc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["*.config.ts", "*.spec.ts", "scripts/*", "website/*"]
}
2 changes: 1 addition & 1 deletion website/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ const config = {
{
// TypeDoc options
entryPoints: ['../src/index.ts'],
tsconfig: '../tsconfig.json',
tsconfig: '../tsconfig.typedoc.json',
readme: 'none',
excludePrivate: true,

Expand Down
2 changes: 1 addition & 1 deletion website/src/theme/ReactLiveScope/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import * as cheerio from '../../../../dist/index.js';
import * as cheerio from '../../../../dist/browser/index.js';

// Add react-live imports you need here
const ReactLiveScope = {
Expand Down

0 comments on commit c07bbf0

Please sign in to comment.