Skip to content

Commit

Permalink
(feat) preserve bind: in new transformation (#1596)
Browse files Browse the repository at this point in the history
On HTML attributes
  • Loading branch information
dummdidumm committed Aug 26, 2022
1 parent cdd046a commit 7d6d2e6
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 27 deletions.
Expand Up @@ -4,7 +4,8 @@ import {
mapRangeToOriginal,
getLineAtPosition,
getNodeIfIsInStartTag,
isInHTMLTagRange
isInHTMLTagRange,
getNodeIfIsInHTMLStartTag
} from '../../../lib/documents';
import { filterAsync, isNotNullOrUndefined, pathToUrl, unique } from '../../../utils';
import { RenameProvider } from '../../interfaces';
Expand Down Expand Up @@ -503,12 +504,35 @@ export class RenameProviderImpl implements RenameProvider {
const { parent } = snapshot;

if (this.configManager.getConfig().svelte.useNewTransformation) {
let rangeStart = parent.offsetAt(location.range.start);
let prefixText = location.prefixText?.trimRight();

// rename needs to be prefixed in case of a bind shortand on a HTML element
if (!prefixText) {
const original = parent.getText({
start: Position.create(
location.range.start.line,
location.range.start.character - bind.length
),
end: location.range.end
});
if (
original.startsWith(bind) &&
getNodeIfIsInHTMLStartTag(parent.html, rangeStart)
) {
return {
...location,
prefixText: original.slice(bind.length) + '={',
suffixText: '}'
};
}
}

if (!prefixText || prefixText.slice(-1) !== ':') {
return location;
}

// prefix is of the form `oldVarName: ` -> hints at a shorthand
let rangeStart = parent.offsetAt(location.range.start);
// we need to make sure we only adjust shorthands on elements/components
if (
!getNodeIfIsInStartTag(parent.html, rangeStart) ||
Expand All @@ -524,12 +548,14 @@ export class RenameProviderImpl implements RenameProvider {
) {
return location;
}

prefixText = prefixText.slice(0, -1) + '={';
location = {
...location,
prefixText,
suffixText: '}'
};

// rename range needs to be adjusted in case of an attribute shortand
if (snapshot.getOriginalText().charAt(rangeStart - 1) === '{') {
rangeStart--;
Expand All @@ -539,6 +565,7 @@ export class RenameProviderImpl implements RenameProvider {
end: parent.positionAt(rangeEnd)
};
}

return location;
}

Expand Down
8 changes: 7 additions & 1 deletion packages/svelte2tsx/src/htmlxtojsx_v2/index.ts
Expand Up @@ -117,7 +117,13 @@ export function convertHtmlxToJsx(
handleComment(str, node);
break;
case 'Binding':
handleBinding(str, node as BaseDirective, parent, element);
handleBinding(
str,
node as BaseDirective,
parent,
element,
options.typingsNamespace === 'svelteHTML'
);
break;
case 'Class':
handleClassDirective(str, node as BaseDirective, element as Element);
Expand Down
47 changes: 32 additions & 15 deletions packages/svelte2tsx/src/htmlxtojsx_v2/nodes/Binding.ts
Expand Up @@ -4,16 +4,18 @@ import { BaseDirective, BaseNode } from '../../interfaces';
import { Element } from './Element';
import { InlineComponent } from './InlineComponent';

const oneWayBindingAttributes: Map<string, string> = new Map(
['clientWidth', 'clientHeight', 'offsetWidth', 'offsetHeight']
.map((e) => [e, 'HTMLDivElement'] as [string, string])
.concat(
['duration', 'buffered', 'seekable', 'seeking', 'played', 'ended'].map((e) => [
e,
'HTMLMediaElement'
])
)
);
const oneWayBindingAttributes: Set<string> = new Set([
'clientWidth',
'clientHeight',
'offsetWidth',
'offsetHeight',
'duration',
'buffered',
'seekable',
'seeking',
'played',
'ended'
]);
/**
* List of all binding names that are transformed to sth like `binding = variable`.
* This applies to readonly bindings and the this binding.
Expand All @@ -34,7 +36,8 @@ export function handleBinding(
str: MagicString,
attr: BaseDirective,
parent: BaseNode,
element: Element | InlineComponent
element: Element | InlineComponent,
preserveBind: boolean
): void {
// bind group on input
if (element instanceof Element && attr.name == 'group' && parent.name == 'input') {
Expand Down Expand Up @@ -70,11 +73,25 @@ export function handleBinding(

// other bindings which are transformed to normal attributes/props
const isShorthand = attr.expression.start === attr.start + 'bind:'.length;
const name: TransformationArray = isShorthand
? [[attr.expression.start, attr.expression.end]]
: [[attr.start + 'bind:'.length, str.original.lastIndexOf('=', attr.expression.start)]];
const name: TransformationArray =
preserveBind && element instanceof Element
? // HTML typings - preserve the bind: prefix
isShorthand
? [`"${str.original.substring(attr.start, attr.end)}"`]
: [
`"${str.original.substring(
attr.start,
str.original.lastIndexOf('=', attr.expression.start)
)}"`
]
: // Other typings - remove the bind: prefix
isShorthand
? [[attr.expression.start, attr.expression.end]]
: [[attr.start + 'bind:'.length, str.original.lastIndexOf('=', attr.expression.start)]];
const value: TransformationArray | undefined = isShorthand
? undefined
? preserveBind && element instanceof Element
? [rangeWithTrailingPropertyAccess(str.original, attr.expression)]
: undefined
: [rangeWithTrailingPropertyAccess(str.original, attr.expression)];
if (element instanceof Element) {
element.addAttribute(name, value);
Expand Down
@@ -1,2 +1,2 @@
{ svelteHTML.createElement("input", { "type":`text`,value,});}
{ svelteHTML.createElement("input", { "type":`checkbox`,checked,});}
{ svelteHTML.createElement("input", { "type":`text`,"bind:value":value,});}
{ svelteHTML.createElement("input", { "type":`checkbox`,"bind:checked":checked,});}
@@ -1,3 +1,3 @@
{ svelteHTML.createElement("input", { "type":`text`,value:test,});}
{ svelteHTML.createElement("input", { "type":`text`,value:test,});}
{ svelteHTML.createElement("input", { "type":`text`,value:test,});}
{ svelteHTML.createElement("input", { "type":`text`,"bind:value":test,});}
{ svelteHTML.createElement("input", { "type":`text`,"bind:value":test,});}
{ svelteHTML.createElement("input", { "type":`text`,"bind:value":test,});}
Expand Up @@ -4,4 +4,4 @@
{ svelteHTML.createElement("img", { });__sveltets_2_ensureTransition(fade(svelteHTML.mapElementTag('img'),(params)));}
{ svelteHTML.createElement("img", { });classthing;}
{ svelteHTML.createElement("img", { });__sveltets_2_ensureAnimation(thing(svelteHTML.mapElementTag('img'),__sveltets_2_AnimationMove,(params)));}
{ svelteHTML.createElement("img", { thing:binding,});}
{ svelteHTML.createElement("img", { "bind:thing":binding,});}
@@ -1,3 +1,3 @@
{ svelteHTML.createElement("input", { });obj.;}
{ svelteHTML.createElement("input", { value:obj.,});}
{ svelteHTML.createElement("input", { "bind:value":obj.,});}
{ const $$_Input0C = __sveltets_2_ensureComponent(Input); new $$_Input0C({ target: __sveltets_2_any(), props: { value:obj.,}});}
Expand Up @@ -4,8 +4,8 @@ async () => { { const $$_div0 = svelteHTML.createElement("div", { });$compile_o
{ const $$_div0 = svelteHTML.createElement("div", { });$compile_options.foo= $$_div0.offsetHeight;}
{ const $$_div0 = svelteHTML.createElement("div", { });$compile_options = $$_div0;}
{ const $$_div0 = svelteHTML.createElement("div", { });$compile_options.foo = $$_div0;}
{ svelteHTML.createElement("div", { noAssignment:$compile_options,});}
{ svelteHTML.createElement("div", { noAssignment:$compile_options.foo,});}};
{ svelteHTML.createElement("div", { "bind:noAssignment":$compile_options,});}
{ svelteHTML.createElement("div", { "bind:noAssignment":$compile_options.foo,});}};
return { props: {}, slots: {}, getters: {}, events: {} }}

export default class Input__SvelteComponent_ extends __sveltets_1_createSvelte2TsxComponent(__sveltets_1_partial(__sveltets_1_with_any_event(render()))) {
Expand Down

0 comments on commit 7d6d2e6

Please sign in to comment.