-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Structured code generation #3539
Conversation
❤️ I wonder if it is possible to structure this PR in a way that is more piecemeal and easier to review… |
I would love it if that were the case but I'm not sure how, the two approaches are rather incompatible. May need to engineer some kind of solution if the brute force approach turns out to be too confusing or difficult to finish |
|
Reached a small but significant milestone — the first working component produced with this method. Behold, the results of compiling import {element, insert, noop, detach, SvelteComponent, init, safe_not_equal} from "svelte/internal";;
function create_fragment(ctx) {
let h1;
return {
c: function create() {
h1 = element("h1");
h1.textContent = "Hello world!";
},
m: function mount(target, anchor) {
insert(target, h1, anchor);
},
p: noop,
i: noop,
o: noop,
d: function destroy(detaching) {
if (detaching) detach(h1);
}
};
}
class App extends SvelteComponent {
constructor(options) {
super();
init(this, options, null, create_fragment, safe_not_equal, []);
}
}
export default App; The current output for the same input: /* App.svelte generated by Svelte v3.12.1 */
import {
SvelteComponent,
detach,
element,
init,
insert,
noop,
safe_not_equal
} from "svelte/internal";
function create_fragment(ctx) {
var h1;
return {
c() {
h1 = element("h1");
h1.textContent = "Hello world!";
},
m(target, anchor) {
insert(target, h1, anchor);
},
p: noop,
i: noop,
o: noop,
d(detaching) {
if (detaching) {
detach(h1);
}
}
};
}
class App extends SvelteComponent {
constructor(options) {
super();
init(this, options, null, create_fragment, safe_not_equal, []);
}
}
export default App; |
Quick update: this is laborious, but i'm getting there. Focusing on the tests in Some things are definitely harder when you can't just throw strings at the problem (e.g. you can't conditionally append an Didn't mention this above so I'll do it briefly here — my goal once everything is working is to add a Rollup plugin to Svelte's own build step that turns this... const node = x`${foo} = ${bar}`; ...into something like this... const node = {
type: 'AssignmentExpression',
operator: '=',
left: foo,
right: bar
}; ...so there's no compile-time (or rather run-time, from Svelte's perspective — I guess the terminology gets a bit weird at this level of abstraction) penalty for generating ASTs. |
Not quite sure why the lint check is failing |
Changing rollup.config.js#L80 like so fixed the lint error for me: - fs.writeFileSync(`${dir}/index.d.ts`, `export * from '../types/runtime/${dir}/index';`);
+ fs.writeFileSync(`${dir}/index.d.ts`, `export * from '../src/runtime/${dir}/index';`); |
Ohhhh I see. I already had the .d.ts types generated locally from when I last published, and presumably Rich did as well. The linting CI job did not because they're normally only run during prepublish. I can reproduce this by deleting my types folder. One way to handle this would be to add
Edit: Ohhhh part II. Moving the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole deindent util module can be removed now.
I'm not sure if #3548 should be added to this PR or be added separately. I'm fine either way but thought it's worth mentioning. |
This is completely experimental and may go nowhere.
One of the things that gets a bit frustrating when writing the Svelte compiler is that the code generation is all string-based. Creating new code is done with the
CodeBuilder
class and thedeindent
helper, both of which have all sorts of quirks, and manipulating user code is done withMagicString
, which is also responsible for gluing everything together at the end, using weird, brittle kludges like[✄start-end✄]
to preserve source mappings.I have a hunch that our lives would be much easier if we were manipulating an AST and stringifying it, and that we'd have new opportunities for code optimisation.
The approach taken in this PR is to use a purpose built utility called code-red (shitty name, but
codeine
('pain-free code generation!') andcodify
etc were all taken already. Alternatives welcome) which simplifies the process of generating AST nodes.So far all I've managed to do is get everything to typecheck, it doesn't, like, do anything yet.