66} from './options' ;
77import * as staticMethods from './static' ;
88import { Cheerio } from './cheerio' ;
9+ import { isHtml , isCheerio } from './utils' ;
910import parse from './parse' ;
1011import type { Node , Document , Element } from 'domhandler' ;
1112import type * as Load from './load' ;
@@ -94,30 +95,113 @@ export function load(
9495 }
9596
9697 const internalOpts = { ...defaultOptions , ...flattenOptions ( options ) } ;
97- const root = parse ( content , internalOpts , isDocument ) ;
98+ const initialRoot = parse ( content , internalOpts , isDocument ) ;
9899
99100 /** Create an extended class here, so that extensions only live on one instance. */
100- class LoadedCheerio < T > extends Cheerio < T > { }
101-
102- function initialize < T > (
103- selector ?: T extends Node
104- ? string | Cheerio < T > | T [ ] | T
105- : Cheerio < T > | T [ ] ,
106- context ?: string | Cheerio < Node > | Node [ ] | Node ,
107- r : string | Cheerio < Document > | Document | null = root ,
101+ class LoadedCheerio < T > extends Cheerio < T > {
102+ _make < T > (
103+ selector ?: ArrayLike < T > | T | string ,
104+ context ?: BasicAcceptedElems < Node > | null
105+ ) : Cheerio < T > {
106+ const cheerio = initialize ( selector , context ) ;
107+ cheerio . prevObject = this ;
108+
109+ return cheerio ;
110+ }
111+ }
112+
113+ function initialize < T = Node , S extends string = string > (
114+ selector ?: ArrayLike < T > | T | S ,
115+ context ?: BasicAcceptedElems < Node > | null ,
116+ root : BasicAcceptedElems < Document > = initialRoot ,
108117 opts ?: CheerioOptions
109- ) {
110- return new LoadedCheerio < T > ( selector , context , r , {
118+ ) : Cheerio < S extends SelectorType ? Element : T > {
119+ type Result = S extends SelectorType ? Element : T ;
120+
121+ // $($)
122+ if ( selector && isCheerio < Result > ( selector ) ) return selector ;
123+
124+ const options = {
111125 ...internalOpts ,
112126 ...flattenOptions ( opts ) ,
113- } ) ;
127+ } ;
128+ const r =
129+ typeof root === 'string'
130+ ? [ parse ( root , options , false ) ]
131+ : 'length' in root
132+ ? root
133+ : [ root ] ;
134+ const rootInstance = isCheerio < Document > ( r )
135+ ? r
136+ : new LoadedCheerio < Document > ( r , null , options ) ;
137+ // Add a cyclic reference, so that calling methods on `_root` never fails.
138+ rootInstance . _root = rootInstance ;
139+
140+ // $(), $(null), $(undefined), $(false)
141+ if ( ! selector ) {
142+ return new LoadedCheerio < Result > ( undefined , rootInstance , options ) ;
143+ }
144+
145+ const elements : Node [ ] | undefined =
146+ typeof selector === 'string' && isHtml ( selector )
147+ ? // $(<html>)
148+ parse ( selector , options , false ) . children
149+ : isNode ( selector )
150+ ? // $(dom)
151+ [ selector ]
152+ : Array . isArray ( selector )
153+ ? // $([dom])
154+ selector
155+ : undefined ;
156+
157+ const instance = new LoadedCheerio ( elements , rootInstance , options ) ;
158+
159+ if ( elements || ! selector ) {
160+ return instance as any ;
161+ }
162+
163+ if ( typeof selector !== 'string' ) throw new Error ( '' ) ;
164+
165+ // We know that our selector is a string now.
166+ let search = selector ;
167+
168+ const searchContext : Cheerio < Node > | undefined = ! context
169+ ? // If we don't have a context, maybe we have a root, from loading
170+ rootInstance
171+ : typeof context === 'string'
172+ ? isHtml ( context )
173+ ? // $('li', '<ul>...</ul>')
174+ new LoadedCheerio < Document > (
175+ [ parse ( context , options , false ) ] ,
176+ rootInstance ,
177+ options
178+ )
179+ : // $('li', 'ul')
180+ ( ( search = `${ context } ${ search } ` as S ) , rootInstance )
181+ : isCheerio < Node > ( context )
182+ ? // $('li', $)
183+ context
184+ : // $('li', node), $('li', [nodes])
185+ new LoadedCheerio < Node > (
186+ Array . isArray ( context ) ? context : [ context ] ,
187+ rootInstance ,
188+ options
189+ ) ;
190+
191+ // If we still don't have a context, return
192+ if ( ! searchContext ) return instance as any ;
193+
194+ /*
195+ * #id, .class, tag
196+ */
197+ return searchContext . find ( search ) as Cheerio < Result > ;
114198 }
115199
116200 // Add in static methods & properties
117201 Object . assign ( initialize , staticMethods , {
118202 load,
119203 // `_root` and `_options` are used in static methods.
120- _root : root ,
204+ _root : initialRoot ,
121205 _options : internalOpts ,
122206 // Add `fn` for plugins
123207 fn : LoadedCheerio . prototype ,
@@ -127,3 +211,12 @@ export function load(
127211
128212 return initialize as CheerioAPI ;
129213}
214+
215+ function isNode ( obj : any ) : obj is Node {
216+ return (
217+ ! ! obj . name ||
218+ obj . type === 'root' ||
219+ obj . type === 'text' ||
220+ obj . type === 'comment'
221+ ) ;
222+ }
0 commit comments