@ -2,70 +2,65 @@ import { set_current_component, current_component } from './lifecycle';
import { run _all , blank _object } from './utils' ;
import { boolean _attributes } from '../../shared/boolean_attributes' ;
export { is _void } from '../../shared/utils/names' ;
export const invalid _attribute _name _character = /[\s'">/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u ;
export const invalid _attribute _name _character =
/[\s'">/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u ;
// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
// https://infra.spec.whatwg.org/#noncharacter
/** @returns {string} */
export function spread ( args , attrs _to _add ) {
const attributes = Object . assign ( { } , ... args ) ;
if ( attrs _to _add ) {
const classes _to _add = attrs _to _add . classes ;
const styles _to _add = attrs _to _add . styles ;
if ( classes _to _add ) {
if ( attributes . class == null ) {
attributes . class = classes _to _add ;
}
else {
attributes . class += ' ' + classes _to _add ;
}
}
if ( styles _to _add ) {
if ( attributes . style == null ) {
attributes . style = style _object _to _string ( styles _to _add ) ;
}
else {
attributes . style = style _object _to _string ( merge _ssr _styles ( attributes . style , styles _to _add ) ) ;
}
}
}
let str = '' ;
Object . keys ( attributes ) . forEach ( ( name ) => {
if ( invalid _attribute _name _character . test ( name ) )
return ;
const value = attributes [ name ] ;
if ( value === true )
str += ' ' + name ;
else if ( boolean _attributes . has ( name . toLowerCase ( ) ) ) {
if ( value )
str += ' ' + name ;
}
else if ( value != null ) {
str += ` ${ name } =" ${ value } " ` ;
}
} ) ;
return str ;
const attributes = Object . assign ( { } , ... args ) ;
if ( attrs _to _add ) {
const classes _to _add = attrs _to _add . classes ;
const styles _to _add = attrs _to _add . styles ;
if ( classes _to _add ) {
if ( attributes . class == null ) {
attributes . class = classes _to _add ;
} else {
attributes . class += ' ' + classes _to _add ;
}
}
if ( styles _to _add ) {
if ( attributes . style == null ) {
attributes . style = style _object _to _string ( styles _to _add ) ;
} else {
attributes . style = style _object _to _string (
merge _ssr _styles ( attributes . style , styles _to _add )
) ;
}
}
}
let str = '' ;
Object . keys ( attributes ) . forEach ( ( name ) => {
if ( invalid _attribute _name _character . test ( name ) ) return ;
const value = attributes [ name ] ;
if ( value === true ) str += ' ' + name ;
else if ( boolean _attributes . has ( name . toLowerCase ( ) ) ) {
if ( value ) str += ' ' + name ;
} else if ( value != null ) {
str += ` ${ name } =" ${ value } " ` ;
}
} ) ;
return str ;
}
/** @returns {{}} */
export function merge _ssr _styles ( style _attribute , style _directive ) {
const style _object = { } ;
for ( const individual _style of style _attribute . split ( ';' ) ) {
const colon _index = individual _style . indexOf ( ':' ) ;
const name = individual _style . slice ( 0 , colon _index ) . trim ( ) ;
const value = individual _style . slice ( colon _index + 1 ) . trim ( ) ;
if ( ! name )
continue ;
style _object [ name ] = value ;
}
for ( const name in style _directive ) {
const value = style _directive [ name ] ;
if ( value ) {
style _object [ name ] = value ;
}
else {
delete style _object [ name ] ;
}
}
return style _object ;
const style _object = { } ;
for ( const individual _style of style _attribute . split ( ';' ) ) {
const colon _index = individual _style . indexOf ( ':' ) ;
const name = individual _style . slice ( 0 , colon _index ) . trim ( ) ;
const value = individual _style . slice ( colon _index + 1 ) . trim ( ) ;
if ( ! name ) continue ;
style _object [ name ] = value ;
}
for ( const name in style _directive ) {
const value = style _directive [ name ] ;
if ( value ) {
style _object [ name ] = value ;
} else {
delete style _object [ name ] ;
}
}
return style _object ;
}
const ATTR _REGEX = /[&"]/g ;
const CONTENT _REGEX = /[&<]/g ;
@ -76,123 +71,119 @@ const CONTENT_REGEX = /[&<]/g;
* @ returns { string }
* /
export function escape ( value , is _attr = false ) {
const str = String ( value ) ;
const pattern = is _attr ? ATTR _REGEX : CONTENT _REGEX ;
pattern . lastIndex = 0 ;
let escaped = '' ;
let last = 0 ;
while ( pattern . test ( str ) ) {
const i = pattern . lastIndex - 1 ;
const ch = str [ i ] ;
escaped += str . substring ( last , i ) + ( ch === '&' ? '&' : ch === '"' ? '"' : '<' ) ;
last = i + 1 ;
}
return escaped + str . substring ( last ) ;
const str = String ( value ) ;
const pattern = is _attr ? ATTR _REGEX : CONTENT _REGEX ;
pattern . lastIndex = 0 ;
let escaped = '' ;
let last = 0 ;
while ( pattern . test ( str ) ) {
const i = pattern . lastIndex - 1 ;
const ch = str [ i ] ;
escaped += str . substring ( last , i ) + ( ch === '&' ? '&' : ch === '"' ? '"' : '<' ) ;
last = i + 1 ;
}
return escaped + str . substring ( last ) ;
}
/** @returns {any} */
export function escape _attribute _value ( value ) {
// keep booleans, null, and undefined for the sake of `spread`
const should _escape = typeof value === 'string' || ( value && typeof value === 'object' ) ;
return should _escape ? escape ( value , true ) : value ;
// keep booleans, null, and undefined for the sake of `spread`
const should _escape = typeof value === 'string' || ( value && typeof value === 'object' ) ;
return should _escape ? escape ( value , true ) : value ;
}
/** @returns {{}} */
export function escape _object ( obj ) {
const result = { } ;
for ( const key in obj ) {
result [ key ] = escape _attribute _value ( obj [ key ] ) ;
}
return result ;
const result = { } ;
for ( const key in obj ) {
result [ key ] = escape _attribute _value ( obj [ key ] ) ;
}
return result ;
}
/** @returns {string} */
export function each ( items , fn ) {
let str = '' ;
for ( let i = 0 ; i < items . length ; i += 1 ) {
str += fn ( items [ i ] , i ) ;
}
return str ;
let str = '' ;
for ( let i = 0 ; i < items . length ; i += 1 ) {
str += fn ( items [ i ] , i ) ;
}
return str ;
}
export const missing _component = {
$$render : ( ) => ''
$$render : ( ) => ''
} ;
/** @returns {any} */
export function validate _component ( component , name ) {
if ( ! component || ! component . $$render ) {
if ( name === 'svelte:component' )
name += ' this={...}' ;
throw new Error ( ` < ${ name } > is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules. Otherwise you may need to fix a < ${ name } >. ` ) ;
}
return component ;
if ( ! component || ! component . $$render ) {
if ( name === 'svelte:component' ) name += ' this={...}' ;
throw new Error (
` < ${ name } > is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules. Otherwise you may need to fix a < ${ name } >. `
) ;
}
return component ;
}
/** @returns {string} */
export function debug ( file , line , column , values ) {
console . log ( ` {@debug} ${ file ? file + ' ' : '' } ( ${ line } : ${ column } ) ` ) ; // eslint-disable-line no-console
console . log ( values ) ; // eslint-disable-line no-console
return '' ;
console . log ( ` {@debug} ${ file ? file + ' ' : '' } ( ${ line } : ${ column } ) ` ) ; // eslint-disable-line no-console
console . log ( values ) ; // eslint-disable-line no-console
return '' ;
}
let on _destroy ;
/** @returns {{ render: (props?: {}, { $$slots, context }?: { $$slots?: {}; context?: Map<any, any>; }) => { html: any; css: { code: string; map: any; }; head: string; }; $$render: (result: any, props: any, bindings: any, slots: any, context: any) => any; }} */
export function create _ssr _component ( fn ) {
/** @returns {any} */
function $$render ( result , props , bindings , slots , context ) {
const parent _component = current _component ;
const $$ = {
on _destroy ,
context : new Map ( context || ( parent _component ? parent _component . $$ . context : [ ] ) ) ,
// these will be immediately discarded
on _mount : [ ] ,
before _update : [ ] ,
after _update : [ ] ,
callbacks : blank _object ( )
} ;
set _current _component ( { $$ } ) ;
const html = fn ( result , props , bindings , slots ) ;
set _current _component ( parent _component ) ;
return html ;
}
return {
render : ( props = { } , { $$slots = { } , context = new Map ( ) } = { } ) => {
on _destroy = [ ] ;
const result = { title : '' , head : '' , css : new Set ( ) } ;
const html = $$render ( result , props , { } , $$slots , context ) ;
run _all ( on _destroy ) ;
return {
html ,
css : {
code : Array . from ( result . css )
. map ( ( css ) => css . code )
. join ( '\n' ) ,
map : null // TODO
} ,
head : result . title + result . head
} ;
} ,
$$render
} ;
/** @returns {any} */
function $$render ( result , props , bindings , slots , context ) {
const parent _component = current _component ;
const $$ = {
on _destroy ,
context : new Map ( context || ( parent _component ? parent _component . $$ . context : [ ] ) ) ,
// these will be immediately discarded
on _mount : [ ] ,
before _update : [ ] ,
after _update : [ ] ,
callbacks : blank _object ( )
} ;
set _current _component ( { $$ } ) ;
const html = fn ( result , props , bindings , slots ) ;
set _current _component ( parent _component ) ;
return html ;
}
return {
render : ( props = { } , { $$slots = { } , context = new Map ( ) } = { } ) => {
on _destroy = [ ] ;
const result = { title : '' , head : '' , css : new Set ( ) } ;
const html = $$render ( result , props , { } , $$slots , context ) ;
run _all ( on _destroy ) ;
return {
html ,
css : {
code : Array . from ( result . css )
. map ( ( css ) => css . code )
. join ( '\n' ) ,
map : null // TODO
} ,
head : result . title + result . head
} ;
} ,
$$render
} ;
}
/** @returns {string} */
export function add _attribute ( name , value , boolean ) {
if ( value == null || ( boolean && ! value ) )
return '' ;
const assignment = boolean && value === true ? '' : ` =" ${ escape ( value , true ) } " ` ;
return ` ${ name } ${ assignment } ` ;
if ( value == null || ( boolean && ! value ) ) return '' ;
const assignment = boolean && value === true ? '' : ` =" ${ escape ( value , true ) } " ` ;
return ` ${ name } ${ assignment } ` ;
}
/** @returns {string} */
export function add _classes ( classes ) {
return classes ? ` class=" ${ classes } " ` : '' ;
return classes ? ` class=" ${ classes } " ` : '' ;
}
/** @returns {string} */
function style _object _to _string ( style _object ) {
return Object . keys ( style _object )
. filter ( ( key ) => style _object [ key ] )
. map ( ( key ) => ` ${ key } : ${ escape _attribute _value ( style _object [ key ] ) } ; ` )
. join ( ' ' ) ;
return Object . keys ( style _object )
. filter ( ( key ) => style _object [ key ] )
. map ( ( key ) => ` ${ key } : ${ escape _attribute _value ( style _object [ key ] ) } ; ` )
. join ( ' ' ) ;
}
/** @returns {string} */
export function add _styles ( style _object ) {
const styles = style _object _to _string ( style _object ) ;
return styles ? ` style=" ${ styles } " ` : '' ;
const styles = style _object _to _string ( style _object ) ;
return styles ? ` style=" ${ styles } " ` : '' ;
}