Skip to content

Commit

Permalink
infer slot/event type from literal string type props (#1121)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonlyu123 committed Jul 30, 2021
1 parent b421e1a commit 20ade7c
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1223,7 +1223,7 @@ describe('DiagnosticsProvider', () => {
{
code: 2322,
message:
'Type \'"asd"\' is not assignable to type \'number | unique symbol | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | "split" | "substring" | ... 34 more ... | "replaceAll"\'.',
'Type \'"asd"\' is not assignable to type \'number | unique symbol | "anchor" | "toString" | "charAt" | "charCodeAt" | "concat" | "indexOf" | "lastIndexOf" | "localeCompare" | "match" | "replace" | "search" | "slice" | ... 35 more ... | "replaceAll"\'.',
range: {
start: {
character: 25,
Expand Down Expand Up @@ -1290,6 +1290,24 @@ describe('DiagnosticsProvider', () => {
severity: 1,
source: 'ts',
tags: []
},
{
code: 2367,
message:
"This condition will always return 'false' since the types '\"anchor\"' and '\"big\"' have no overlap.",
range: {
end: {
character: 16,
line: 15
},
start: {
character: 5,
line: 15
}
},
tags: [],
severity: 1,
source: 'ts'
}
]);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@
</script>

<!-- valid -->
<Generics a={['a', 'b']} b={'anchor'} c={false} on:b={(e) => e.detail === 'str'} let:a>
{a === 'str'}
<Generics a={['a', 'b']} b={'anchor'} c={false} on:b={(e) => e.detail === 'str'} let:a let:b>
{a === 'str'}{b === 'anchor'}
</Generics>

<!-- invalid -->
<Generics a={['a', 'b']} b={'asd'} c={''} on:b={(e) => e.detail === true} let:a>
{a === true}
</Generics>

<Generics a={['a', 'b']} b={'anchor'} c={false} let:b>
{b === 'big'}
</Generics>
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
dispatch('b', a[0]);
</script>

<slot a={a[0]} />
<slot a={a[0]} {b} />
27 changes: 19 additions & 8 deletions packages/svelte2tsx/src/htmlxtojsx/utils/node-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,7 @@ function getNameValuePairsFromAttributes(
return { name, value: name, identifier: name };
}
if (val.type === 'Text') {
// Value not important, just that it's typeof text
return { name, value: '""' };
return { name, value: `'${val.data || val.raw}'` };
}
if (val.type === 'MustacheTag') {
const valueStr = originalStr.substring(val.start + 1, val.end - 1);
Expand All @@ -130,18 +129,30 @@ function getNameValuePairsFromAttributes(
}
if (val.expression.type === 'Literal') {
const value =
typeof val.expression.value === 'string' ? '""' : val.expression.value;
typeof val.expression.value === 'string'
? val.expression.raw
: val.expression.value;
return { name, value };
}
return { name, value: valueStr, complexExpression: true };
}
}

// In the case of zero values, the user did attr="", which is the empty string.
// In the case of multiple values, the user did put in a property value
// like a="a{b}c" which is a template literal string. Since we only care
// about the type of the expression in the end, we can simplify this
return { name, value: '""' };
if (!attr.value.length) {
return { name, value: '""' };
}

const value = attr.value
.map((val) =>
val.type === 'Text'
? val.raw
: val.type === 'MustacheTag'
? '$' + originalStr.substring(val.start, val.end)
: ''
)
.join('');

return { name, value: `\`${value}\`` };
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<><Parent bare shorthand={shorthand} text1="val1" text2="val2" text3={`a${a}b${b}`} textEmpty="" literal={true} strLiteral={'foo'} complex={{a}} a-dashed-complex={{a}} {...__sveltets_1_cssProp({"--custom-cssprop": `foo`})} >{() => {/*Ωignore_startΩ*/const Ψcomplex={a},Ψa_dashed_complex={a};/*Ωignore_endΩ*/() => { let {foo} = /*Ωignore_startΩ*/new Parent({target: __sveltets_1_any(''), props: {'bare':true, 'shorthand':shorthand, 'text1':"", 'text2':"", 'text3':"", 'textEmpty':"", 'literal':true, 'strLiteral':"", 'complex':Ψcomplex, 'a-dashed-complex':Ψa_dashed_complex}})/*Ωignore_endΩ*/.$$slot_def['default'];<>
{() => { let {bar} = /*Ωignore_startΩ*/new Parent({target: __sveltets_1_any(''), props: {'bare':true, 'shorthand':shorthand, 'text1':"", 'text2':"", 'text3':"", 'textEmpty':"", 'literal':true, 'strLiteral':"", 'complex':Ψcomplex, 'a-dashed-complex':Ψa_dashed_complex}})/*Ωignore_endΩ*/.$$slot_def['named'];<><Component >
<><Parent bare shorthand={shorthand} text1="val1" text2="val2" text3={`a${a}b${b}`} textEmpty="" literal={true} strLiteral={'foo'} complex={{a}} a-dashed-complex={{a}} {...__sveltets_1_cssProp({"--custom-cssprop": `foo`})} >{() => {/*Ωignore_startΩ*/const Ψcomplex={a},Ψa_dashed_complex={a};/*Ωignore_endΩ*/() => { let {foo} = /*Ωignore_startΩ*/new Parent({target: __sveltets_1_any(''), props: {'bare':true, 'shorthand':shorthand, 'text1':'val1', 'text2':'val2', 'text3':`a${a}b${b}`, 'textEmpty':"", 'literal':true, 'strLiteral':'foo', 'complex':Ψcomplex, 'a-dashed-complex':Ψa_dashed_complex}})/*Ωignore_endΩ*/.$$slot_def['default'];<>
{() => { let {bar} = /*Ωignore_startΩ*/new Parent({target: __sveltets_1_any(''), props: {'bare':true, 'shorthand':shorthand, 'text1':'val1', 'text2':'val2', 'text3':`a${a}b${b}`, 'textEmpty':"", 'literal':true, 'strLiteral':'foo', 'complex':Ψcomplex, 'a-dashed-complex':Ψa_dashed_complex}})/*Ωignore_endΩ*/.$$slot_def['named'];<><Component >
{foo} {bar}
</Component></>}}
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@



>{() => {/*Ωignore_startΩ*/const Ψsubthing=subthing,Ψshadowed1=shadowed1,Ψshadowed_2=shadowed2,Ψcomplex={complex};/*Ωignore_endΩ*/() => { let {name:n, shadowed1, shadowed2, subthing} = /*Ωignore_startΩ*/new Component({target: __sveltets_1_any(''), props: {'unshadowed1':unshadowed1, 'foo':unshadowed2, 'subthing':Ψsubthing, 'shadowed1':Ψshadowed1, 'shadowed-2':Ψshadowed_2, 'templateString':"", 'complex':Ψcomplex}})/*Ωignore_endΩ*/.$$slot_def['default'];<>
{() => { let {subthing} = /*Ωignore_startΩ*/new Component({target: __sveltets_1_any(''), props: {'unshadowed1':unshadowed1, 'foo':unshadowed2, 'subthing':Ψsubthing, 'shadowed1':Ψshadowed1, 'shadowed-2':Ψshadowed_2, 'templateString':"", 'complex':Ψcomplex}})/*Ωignore_endΩ*/.$$slot_def['sub1'];<><p >{thing}{subthing}</p></>}}
>{() => {/*Ωignore_startΩ*/const Ψsubthing=subthing,Ψshadowed1=shadowed1,Ψshadowed_2=shadowed2,Ψcomplex={complex};/*Ωignore_endΩ*/() => { let {name:n, shadowed1, shadowed2, subthing} = /*Ωignore_startΩ*/new Component({target: __sveltets_1_any(''), props: {'unshadowed1':unshadowed1, 'foo':unshadowed2, 'subthing':Ψsubthing, 'shadowed1':Ψshadowed1, 'shadowed-2':Ψshadowed_2, 'templateString':` ${complex} `, 'complex':Ψcomplex}})/*Ωignore_endΩ*/.$$slot_def['default'];<>
{() => { let {subthing} = /*Ωignore_startΩ*/new Component({target: __sveltets_1_any(''), props: {'unshadowed1':unshadowed1, 'foo':unshadowed2, 'subthing':Ψsubthing, 'shadowed1':Ψshadowed1, 'shadowed-2':Ψshadowed_2, 'templateString':` ${complex} `, 'complex':Ψcomplex}})/*Ωignore_endΩ*/.$$slot_def['sub1'];<><p >{thing}{subthing}</p></>}}

{() => { let {subthing, othersubthing} = /*Ωignore_startΩ*/new Component({target: __sveltets_1_any(''), props: {'unshadowed1':unshadowed1, 'foo':unshadowed2, 'subthing':Ψsubthing, 'shadowed1':Ψshadowed1, 'shadowed-2':Ψshadowed_2, 'templateString':"", 'complex':Ψcomplex}})/*Ωignore_endΩ*/.$$slot_def['sub2'];<><Sub subthing={subthing} >{thing}{subthing}</Sub></>}}
{() => { let {subthing, othersubthing} = /*Ωignore_startΩ*/new Component({target: __sveltets_1_any(''), props: {'unshadowed1':unshadowed1, 'foo':unshadowed2, 'subthing':Ψsubthing, 'shadowed1':Ψshadowed1, 'shadowed-2':Ψshadowed_2, 'templateString':` ${complex} `, 'complex':Ψcomplex}})/*Ωignore_endΩ*/.$$slot_def['sub2'];<><Sub subthing={subthing} >{thing}{subthing}</Sub></>}}

<Sub subthing={subthing} >{() => {/*Ωignore_startΩ*/const Ψsubthing=subthing;/*Ωignore_endΩ*/() => { let {subthing, othersubthing} = /*Ωignore_startΩ*/new Sub({target: __sveltets_1_any(''), props: {'subthing':Ψsubthing}})/*Ωignore_endΩ*/.$$slot_def['default'];<>{thing}{subthing}</>}}}</Sub>
</>}}}</Component></>
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<><Component bare shorthand={shorthand} text1="val1" text2="val2" text3={`a${a}b${b}`} textEmpty="" literal={true} strLiteral={'foo'} complex={{a}} a-dashed-complex={{a}} {...__sveltets_1_cssProp({"--custom-cssprop": `foo`})} />{/*Ωignore_startΩ*/new Component({target: __sveltets_1_any(''), props: {'bare':true, 'shorthand':shorthand, 'text1':"", 'text2':"", 'text3':"", 'textEmpty':"", 'literal':true, 'strLiteral':"", 'complex':{a}, 'a-dashed-complex':{a}}})/*Ωignore_endΩ*/.$on('click', e => e)}</>
<><Component bare shorthand={shorthand} text1="val1" text2="val2" text3={`a${a}b${b}`} textEmpty="" literal={true} strLiteral={'foo'} complex={{a}} a-dashed-complex={{a}} {...__sveltets_1_cssProp({"--custom-cssprop": `foo`})} />{/*Ωignore_startΩ*/new Component({target: __sveltets_1_any(''), props: {'bare':true, 'shorthand':shorthand, 'text1':'val1', 'text2':'val2', 'text3':`a${a}b${b}`, 'textEmpty':"", 'literal':true, 'strLiteral':'foo', 'complex':{a}, 'a-dashed-complex':{a}}})/*Ωignore_endΩ*/.$on('click', e => e)}</>
Original file line number Diff line number Diff line change
Expand Up @@ -429,17 +429,17 @@ s
injectedJS={mapbox_setup}
relaxed {/**
------------------------------------------------------------------------------------------------------------------------------------------------------ */}
/>{/*Ωignore_startΩ*/new Repl({target: __sveltets_1_any(''), props: {'workersUrl':"", 'svelteUrl':svelteUrl, 'rollupUrl':rollupUrl, 'orientation':mobile ? 'columns' : 'rows', 'fixed':mobile, 'injectedJS':mapbox_setup, 'relaxed':true}})/*Ωignore_endΩ*/.$on('change', handle_change)}{/**
╚╚╚/>{/*Ωignore_startΩ*/new•Repl({target:•__sveltets_1_any(''),•props:{'workersUrl':"",'svelteUrl':svelteUrl,'rollupUrl':rollupUrl,'orientation':mobile•?'columns':'rows','fixed':mobile,'injectedJS':mapbox_setup,'relaxed':true}})/*Ωignore_endΩ*/.$on('change',•handle_change)}↲ [generated] line 172
on('change',•handle_change)} [generated] subset
on: change= handle_change}
on:change= handle_change}
╚╚╚╚on:change={handle_change}↲ [original] line 309 (rest generated at line 169)

╚╚╚/>{/*Ωignore_startΩ*/new•Repl({target:•__sveltets_1_any(''),•props:{'workersUrl':"",'svelteUrl':svelteUrl,'rollupUrl':rollupUrl,'orientation':mobile•?'columns':'rows','fixed':mobile,'injectedJS':mapbox_setup,'relaxed':true}})/*Ωignore_endΩ*/.$on('change',•handle_change)}↲ [generated] line 172
╚╚╚/>{/*Ωignore_startΩ*/new•Repl({target:•__sveltets_1_any(''),•props:{'workersUrl':"",'svelteUrl':svelteUrl,'rollupUrl':rollupUrl,'orientation':mobile•?'columns':'rows','fixed':mobile,'injectedJS':mapbox_setup,'relaxed':true}})/*Ωignore_endΩ*/.$ [generated] subset
╚╚╚/>
╚╚╚/> [original] line 312
/>{/*Ωignore_startΩ*/new Repl({target: __sveltets_1_any(''), props: {'workersUrl':'workers', 'svelteUrl':svelteUrl, 'rollupUrl':rollupUrl, 'orientation':mobile ? 'columns' : 'rows', 'fixed':mobile, 'injectedJS':mapbox_setup, 'relaxed':true}})/*Ωignore_endΩ*/.$on('change', handle_change)}{/**
╚╚╚/>{/*Ωignore_startΩ*/new•Repl({target:•__sveltets_1_any(''),•props:{'workersUrl':'workers','svelteUrl':svelteUrl,'rollupUrl':rollupUrl,'orientation':mobile•?'columns':'rows','fixed':mobile,'injectedJS':mapbox_setup,'relaxed':true}})/*Ωignore_endΩ*/.$on('change',•handle_change)}↲ [generated] line 172
on('change',•handle_change)} [generated] subset
on: change= handle_change}
on:change= handle_change}
╚╚╚╚on:change={handle_change} [original] line 309 (rest generated at line 169)
╚╚╚/>{/*Ωignore_startΩ*/new•Repl({target:•__sveltets_1_any(''),•props:{'workersUrl':'workers','svelteUrl':svelteUrl,'rollupUrl':rollupUrl,'orientation':mobile•?'columns':'rows','fixed':mobile,'injectedJS':mapbox_setup,'relaxed':true}})/*Ωignore_endΩ*/.$on('change',•handle_change)}↲ [generated] line 172
╚╚╚/>{/*Ωignore_startΩ*/new•Repl({target:•__sveltets_1_any(''),•props:{'workersUrl':'workers','svelteUrl':svelteUrl,'rollupUrl':rollupUrl,'orientation':mobile•?'columns':'rows','fixed':mobile,'injectedJS':mapbox_setup,'relaxed':true}})/*Ωignore_endΩ*/.$ [generated] subset
╚╚╚/>
╚╚╚/> [original] line 312
------------------------------------------------------------------------------------------------------------------------------------------------------ */}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
///<reference types="svelte" />
<></>;function render() {
/*Ωignore_startΩ*/;const __sveltets_ensureSlot = __sveltets_1_createEnsureSlot();/*Ωignore_endΩ*/
<><Parent propA propB={propB} propC="val1" propD="val2" propE={`a${a}b${b}`} >{() => { let {foo} = /*Ωignore_startΩ*/new Parent({target: __sveltets_1_any(''), props: {'propA':true, 'propB':propB, 'propC':"", 'propD':"", 'propE':""}})/*Ωignore_endΩ*/.$$slot_def['default'];<>
<><Parent propA propB={propB} propC="val1" propD="val2" propE={`a${a}b${b}`} >{() => { let {foo} = /*Ωignore_startΩ*/new Parent({target: __sveltets_1_any(''), props: {'propA':true, 'propB':propB, 'propC':'val1', 'propD':'val2', 'propE':`a${a}b${b}`}})/*Ωignore_endΩ*/.$$slot_def['default'];<>
<slot foo={__sveltets_ensureSlot("default","foo",foo)} />
</>}}</Parent></>
return { props: {}, slots: {'default': {foo:__sveltets_1_instanceOf(Parent).$$slot_def['default'].foo}}, getters: {}, events: {} }}
Expand Down

0 comments on commit 20ade7c

Please sign in to comment.