11const cssSelect = require ( 'css-select' )
22const { DomHandler, Parser } = require ( 'htmlparser2' )
33
4- const { UnknownFilterError } = require ( './errors' )
4+ const { ModelError , UnknownFilterError } = require ( './errors' )
55const filters = require ( './filters' )
66const getters = require ( './getters' )
77const { DOMHANDLER_OPTIONS , HTMLPARSER2_OPTIONS } = require ( './options' )
@@ -22,7 +22,7 @@ const {
2222 */
2323
2424function extract ( html , model , options = { } ) {
25- // Using Object.assig instead of object spread removes the need of null checks.
25+ // Using Object.assign instead of object spread removes the need of null checks.
2626 const parserOptions = Object . assign ( { } , HTMLPARSER2_OPTIONS , options . htmlparser2 )
2727 const handlerOptions = Object . assign ( { } , DOMHANDLER_OPTIONS , options . domhandler )
2828
@@ -44,31 +44,44 @@ function extract(html, model, options = {}) {
4444 */
4545
4646function getItem ( dom , item ) {
47- let data
48-
4947 if ( isArray ( item ) ) {
5048 const query = parseQuery ( item [ 0 ] )
5149 const matches = cssSelect . selectAll ( query . selector , dom )
5250
51+ if ( ! matches || ! matches . length ) return null
52+
5353 if ( isArray ( item [ 1 ] ) || isObject ( item [ 1 ] ) ) {
54- data = matches . map ( ( context ) => getItem ( context , item [ 1 ] ) )
55- } else {
56- data = matches . map ( resolveGetter ( getters , query ) ) . map ( applyFilters . bind ( null , filters , query ) )
54+ return matches . map ( ( context ) => getItem ( context , item [ 1 ] ) )
5755 }
58- } else if ( isObject ( item ) ) {
59- data = Object . keys ( item ) . reduce ( ( acc , key ) => {
56+
57+ return matches . map ( ( node ) => {
58+ const data = resolveGetter ( getters , query ) ( node )
59+ return applyFilters ( filters , query , data )
60+ } )
61+ }
62+
63+ if ( isObject ( item ) ) {
64+ return Object . keys ( item ) . reduce ( ( acc , key ) => {
6065 acc [ key ] = getItem ( dom , item [ key ] )
6166 return acc
6267 } , { } )
63- } else if ( isString ( item ) ) {
68+ }
69+
70+ if ( isString ( item ) ) {
6471 const query = parseQuery ( item )
65- const matches = cssSelect . selectOne ( query . selector , dom )
72+ const match = cssSelect . selectOne ( query . selector , dom )
73+
74+ if ( ! match ) return null
75+
76+ const data = resolveGetter ( getters , query ) ( match )
6677
67- data = resolveGetter ( getters , query ) ( matches )
68- data = applyFilters ( filters , query , data )
78+ return applyFilters ( filters , query , data )
6979 }
7080
71- return data
81+ const unsupportedType = item === null ? 'null' : typeof item
82+ throw new ModelError (
83+ `The model has to be a string, an Object or an Array; got ${ unsupportedType } instead.`
84+ )
7285}
7386
7487/**
0 commit comments