Skip to content

Commit

Permalink
(svelte2tsx) export class, const and function (#328)
Browse files Browse the repository at this point in the history
* export const and class are not props

* add getters for exported to exported class
  • Loading branch information
jasonlyu123 committed Jul 25, 2020
1 parent 5cd71dc commit 7f89480
Show file tree
Hide file tree
Showing 71 changed files with 206 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export class RenameProviderImpl implements RenameProvider {
// First find out if it's really the "rename prop inside component with that prop" case
// Use original document for that because only there the `export` is present.
const regex = new RegExp(
`export\\s+(const|let)\\s+${this.getVariableAtPosition(
`export\\s+let\\s+${this.getVariableAtPosition(
tsDoc,
fragment,
lang,
Expand Down
2 changes: 2 additions & 0 deletions packages/svelte2tsx/.editorconfig
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
[test/**/*.{tsx,jsx,html}]
trim_trailing_whitespace = false
[test/**/*.html]
insert_final_newline = false
25 changes: 25 additions & 0 deletions packages/svelte2tsx/src/interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import MagicString from 'magic-string';
import { Node } from 'estree-walker';

export type ExportedNames = Map<
string,
{
type?: string;
identifierText?: string;
required?: boolean;
}
>;

export interface InstanceScriptProcessResult {
exportedNames: ExportedNames;
uses$$props: boolean;
uses$$restProps: boolean;
getters: Set<string>;
}

export interface CreateRenderFunctionPara extends InstanceScriptProcessResult {
str: MagicString;
scriptTag: Node;
scriptDestination: number;
slots: Map<string, Map<string, string>>;
}
9 changes: 9 additions & 0 deletions packages/svelte2tsx/src/nodes/exportgetters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const createClassGetter = (name: string) =>
`\n${' '.repeat(4)}get ${name}() { return render().getters.${name} }`;
export const createClassGetters = (names: Set<string>) => {
return Array.from(names).map(createClassGetter).join('');
};
export function createRenderFunctionGetterStr(getters: Set<string>) {
const properties = Array.from(getters).map((name) => `${name}: ${name}`);
return `{${properties.join(', ')}}`;
}
106 changes: 61 additions & 45 deletions packages/svelte2tsx/src/svelte2tsx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { parseHtmlx } from './htmlxparser';
import { convertHtmlxToJsx } from './htmlxtojsx';
import { Node } from 'estree-walker';
import * as ts from 'typescript';
import { findExortKeyword } from './utils/tsAst';
import { ExportedNames, InstanceScriptProcessResult, CreateRenderFunctionPara } from './interfaces';
import { createRenderFunctionGetterStr, createClassGetters } from './nodes/exportgetters';

function AttributeValueAsJsExpression(htmlx: string, attr: Node): string {
if (attr.value.length == 0) return "''"; //wut?
Expand Down Expand Up @@ -364,20 +367,6 @@ function processSvelteTemplate(str: MagicString): TemplateProcessResult {
};
}

type ExportedNames = Map<
string,
{
type?: string;
identifierText?: string;
required?: boolean;
}
>;

type InstanceScriptProcessResult = {
exportedNames: ExportedNames;
uses$$props: boolean;
uses$$restProps: boolean;
};

function processInstanceScriptContent(str: MagicString, script: Node): InstanceScriptProcessResult {
const htmlx = str.original;
Expand All @@ -391,6 +380,7 @@ function processInstanceScriptContent(str: MagicString, script: Node): InstanceS
);
const astOffset = script.content.start;
const exportedNames: ExportedNames = new Map();
const getters = new Set<string>();

const implicitTopLevelNames: Map<string, number> = new Map();
let uses$$props = false;
Expand Down Expand Up @@ -431,6 +421,12 @@ function processInstanceScriptContent(str: MagicString, script: Node): InstanceS
exportedNames.set(name.text, {});
}
};
const addGetter = (node: ts.Identifier) => {
if (!node) {
return;
}
getters.add(node.text);
};

const removeExport = (start: number, end: number) => {
const exportStart = str.original.indexOf('export', start + astOffset);
Expand All @@ -439,10 +435,6 @@ function processInstanceScriptContent(str: MagicString, script: Node): InstanceS
};

const propTypeAssertToUserDefined = (node: ts.VariableDeclarationList) => {
if (node.flags !== ts.NodeFlags.Let) {
return;
}

const hasInitializers = node.declarations.filter((declaration) => declaration.initializer);
const handleTypeAssertion = (declaration: ts.VariableDeclaration) => {
const identifier = declaration.name;
Expand Down Expand Up @@ -669,31 +661,46 @@ function processInstanceScriptContent(str: MagicString, script: Node): InstanceS
const onLeaveCallbacks: onLeaveCallback[] = [];

if (ts.isVariableStatement(node)) {
const exportModifier = node.modifiers
? node.modifiers.find((x) => x.kind == ts.SyntaxKind.ExportKeyword)
: null;
const exportModifier = findExortKeyword(node);
if (exportModifier) {
handleExportedVariableDeclarationList(node.declarationList);
propTypeAssertToUserDefined(node.declarationList);
const isLet = node.declarationList.flags === ts.NodeFlags.Let;
const isConst = node.declarationList.flags === ts.NodeFlags.Const;

if (isLet) {
handleExportedVariableDeclarationList(node.declarationList);
propTypeAssertToUserDefined(node.declarationList);
} else if (isConst) {
node.declarationList.forEachChild((n) => {
if (ts.isVariableDeclaration(n) && ts.isIdentifier(n.name)) {
addGetter(n.name);
}
});
}
removeExport(exportModifier.getStart(), exportModifier.end);
}
}

if (ts.isFunctionDeclaration(node)) {
if (node.modifiers) {
const exportModifier = node.modifiers.find(
(x) => x.kind == ts.SyntaxKind.ExportKeyword,
);
const exportModifier = findExortKeyword(node);
if (exportModifier) {
addExport(node.name);
removeExport(exportModifier.getStart(), exportModifier.end);
addGetter(node.name);
}
}

pushScope();
onLeaveCallbacks.push(() => popScope());
}

if (ts.isClassDeclaration(node)) {
const exportModifier = findExortKeyword(node);
if (exportModifier) {
removeExport(exportModifier.getStart(), exportModifier.end);
addGetter(node.name);
}
}

if (ts.isBlock(node)) {
pushScope();
onLeaveCallbacks.push(() => popScope());
Expand Down Expand Up @@ -803,6 +810,7 @@ function processInstanceScriptContent(str: MagicString, script: Node): InstanceS
exportedNames,
uses$$props,
uses$$restProps,
getters,
};
}

Expand All @@ -825,6 +833,7 @@ function addComponentExport(
uses$$propsOr$$restProps: boolean,
strictMode: boolean,
isTsFile: boolean,
getters: Set<string>,
/** A named export allows for TSDoc-compatible docstrings */
className?: string,
componentDocumentation?: string | null,
Expand All @@ -841,10 +850,12 @@ function addComponentExport(

const doc = formatComponentDocumentation(componentDocumentation);

// eslint-disable-next-line max-len
const statement = `\n\n${doc}export default class ${
className ? `${className} ` : ''
}{\n $$prop_def = ${propDef}\n $$slot_def = render().slots\n}`;
const statement =
`\n\n${doc}export default class ${
className ? `${className} ` : ''
}{\n $$prop_def = ${propDef}\n $$slot_def = render().slots` +
createClassGetters(getters) +
'\n}';

str.append(statement);
}
Expand Down Expand Up @@ -899,15 +910,16 @@ function processModuleScriptTag(str: MagicString, script: Node) {
str.overwrite(scriptEndTagStart, script.end, ';<>');
}

function createRenderFunction(
str: MagicString,
scriptTag: Node,
scriptDestination: number,
slots: Map<string, Map<string, string>>,
exportedNames: ExportedNames,
uses$$props: boolean,
uses$$restProps: boolean,
) {
function createRenderFunction({
str,
scriptTag,
scriptDestination,
slots,
getters,
exportedNames,
uses$$props,
uses$$restProps
}: CreateRenderFunctionPara) {
const htmlx = str.original;
let propsDecl = '';

Expand Down Expand Up @@ -946,7 +958,7 @@ function createRenderFunction(

const returnString = `\nreturn { props: ${createPropsStr(
exportedNames,
)}, slots: ${slotsAsDef} }}`;
)}, slots: ${slotsAsDef}, getters: ${createRenderFunctionGetterStr(getters)} }}`;
str.append(returnString);
}

Expand Down Expand Up @@ -1008,27 +1020,30 @@ export function svelte2tsx(svelte: string, options?: { filename?: string; strict

//move the instance script and process the content
let exportedNames: ExportedNames = new Map();
let getters = new Set<string>();
if (scriptTag) {
//ensure it is between the module script and the rest of the template (the variables need to be declared before the jsx template)
if (scriptTag.start != instanceScriptTarget) {
str.move(scriptTag.start, scriptTag.end, instanceScriptTarget);
}
const res = processInstanceScriptContent(str, scriptTag);
exportedNames = res.exportedNames;
uses$$props = uses$$props || res.uses$$props;
uses$$restProps = uses$$restProps || res.uses$$restProps;

({ exportedNames, getters } = res);
}

//wrap the script tag and template content in a function returning the slot and exports
createRenderFunction(
createRenderFunction({
str,
scriptTag,
instanceScriptTarget,
scriptDestination: instanceScriptTarget,
slots,
getters,
exportedNames,
uses$$props,
uses$$restProps,
);
});

// we need to process the module script after the instance script has moved otherwise we get warnings about moving edited items
if (moduleScriptTag) {
Expand All @@ -1042,6 +1057,7 @@ export function svelte2tsx(svelte: string, options?: { filename?: string; strict
uses$$props || uses$$restProps,
!!options?.strictMode,
isTsFile(scriptTag, moduleScriptTag),
getters,
className,
componentDocumentation,
);
Expand Down
5 changes: 5 additions & 0 deletions packages/svelte2tsx/src/utils/tsAst.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import ts from 'typescript';

export function findExortKeyword(node: ts.Node) {
return node.modifiers?.find((x) => x.kind == ts.SyntaxKind.ExportKeyword);
}
2 changes: 0 additions & 2 deletions packages/svelte2tsx/test/sourcemaps/.editorconfig

This file was deleted.

2 changes: 1 addition & 1 deletion packages/svelte2tsx/test/sourcemaps/event-binding.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
1==== 2==================
<button onclick={__sveltets_store_get(check) ? method1 : method2} >Bla</button></>
3==== 4==================
return { props: {}, slots: {} }}
return { props: {}, slots: {}, getters: {} }}

export default class {
$$prop_def = __sveltets_partial(render().props)
Expand Down
2 changes: 1 addition & 1 deletion packages/svelte2tsx/test/sourcemaps/let.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
;
<>
</>
return { props: {}, slots: {} }}
return { props: {}, slots: {}, getters: {} }}

export default class {
$$prop_def = __sveltets_partial(render().props)
Expand Down
2 changes: 1 addition & 1 deletion packages/svelte2tsx/test/sourcemaps/repl.html
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@
</>}}}
</div>
</>
return { props: {slug: slug , chapter: chapter}, slots: {} }}
return { props: {slug: slug , chapter: chapter}, slots: {}, getters: {} }}

export default class {
$$prop_def = __sveltets_partial(render().props)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
let [a,b,c] = [1,2,3];
;
<></>
return { props: {a: a , b: b , c: c}, slots: {} }}
return { props: {a: a , b: b , c: c}, slots: {}, getters: {} }}

export default class Input__SvelteComponent_ {
$$prop_def = __sveltets_partial(render().props)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<></>;function render() {
__sveltets_store_get(var);
<></>
return { props: {}, slots: {} }}
return { props: {}, slots: {}, getters: {} }}

export default class Input__SvelteComponent_ {
$$prop_def = __sveltets_partial(render().props)
$$slot_def = render().slots
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<></>;function render() {
__sveltets_store_get(var);
<></>
return { props: {}, slots: {} }}
return { props: {}, slots: {}, getters: {} }}

export default class Input__SvelteComponent_ {
$$prop_def = __sveltets_partial(render().props)
$$slot_def = render().slots
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function render() {
</>; _$$p.then((data) => {<>
{data}
</>})}}</>
return { props: {}, slots: {} }}
return { props: {}, slots: {}, getters: {} }}

export default class Input__SvelteComponent_ {
$$prop_def = __sveltets_partial(render().props)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<></>;function render() {
<><input id="dom-input" type="radio" {...__sveltets_any(__sveltets_store_get(compile_options).generate)} value="dom"/></>
return { props: {}, slots: {} }}
return { props: {}, slots: {}, getters: {} }}

export default class Input__SvelteComponent_ {
$$prop_def = __sveltets_partial(render().props)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@
<input type="range" value={selected.r} oninput={adjust}/>
</div>
</>}}}</>
return { props: {}, slots: {} }}
return { props: {}, slots: {}, getters: {} }}

export default class Input__SvelteComponent_ {
$$prop_def = __sveltets_partial(render().props)
$$slot_def = render().slots
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
<div>
<slot a={b}>Hello</slot>
</div></>
return { props: {}, slots: {default: {a:b}} }}
return { props: {}, slots: {default: {a:b}}, getters: {} }}

export default class Input__SvelteComponent_ {
$$prop_def = __sveltets_partial(render().props)
$$slot_def = render().slots
}
}
Loading

0 comments on commit 7f89480

Please sign in to comment.