Skip to content

Commit

Permalink
🚧 Add extract-instance-nodes & extract snippet for setTemplate
Browse files Browse the repository at this point in the history
  • Loading branch information
xeho91 committed Jun 3, 2024
1 parent be04452 commit e585f27
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 4 deletions.
19 changes: 17 additions & 2 deletions src/parser/extract/svelte/fragment-nodes.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import type { Comment, Component, Fragment, SvelteNode } from 'svelte/compiler';
import type { Comment, Component, Fragment, SnippetBlock, SvelteNode } from 'svelte/compiler';
import type { Visitors } from 'zimmerframe';

import type { extractModuleNodes } from './module-nodes.js';
import type { extractInstanceNodes } from './instance-nodes.js';

interface Result {
storyComponents: Array<{
comment?: Comment;
component: Component;
}>;
setTemplateSnippet: SnippetBlock | undefined;
}

interface Params {
fragment: Fragment;
filename?: string;
instanceNodes: Awaited<ReturnType<typeof extractInstanceNodes>>;
moduleNodes: Awaited<ReturnType<typeof extractModuleNodes>>;
}

Expand All @@ -24,13 +27,15 @@ interface Params {
export async function extractFragmentNodes(params: Params): Promise<Result> {
const { walk } = await import('zimmerframe');

const { fragment, filename, moduleNodes } = params;
const { fragment, filename, moduleNodes, instanceNodes } = params;
const { setTemplateCall } = instanceNodes;

Check failure on line 31 in src/parser/extract/svelte/fragment-nodes.ts

View workflow job for this annotation

GitHub Actions / Test

src/parser/extract/svelte/fragment-nodes.test.ts > extractFragmentNodes > extracts '<Story />' AST nodes correctly

TypeError: Cannot destructure property 'setTemplateCall' of 'instanceNodes' as it is undefined. ❯ Module.extractFragmentNodes src/parser/extract/svelte/fragment-nodes.ts:31:11 ❯ src/parser/extract/svelte/fragment-nodes.test.ts:23:27

Check failure on line 31 in src/parser/extract/svelte/fragment-nodes.ts

View workflow job for this annotation

GitHub Actions / Test

src/parser/extract/svelte/fragment-nodes.test.ts > extractFragmentNodes > extracts '<Story />' leading HTML comments correctly

TypeError: Cannot destructure property 'setTemplateCall' of 'instanceNodes' as it is undefined. ❯ Module.extractFragmentNodes src/parser/extract/svelte/fragment-nodes.ts:31:11 ❯ src/parser/extract/svelte/fragment-nodes.test.ts:53:27
const { storyIdentifier } = moduleNodes;

let latestComment: Comment | undefined;

const state: Result = {
storyComponents: [],
setTemplateSnippet: undefined,
};

const visitors: Visitors<SvelteNode, typeof state> = {
Expand All @@ -48,6 +53,16 @@ export async function extractFragmentNodes(params: Params): Promise<Result> {
latestComment = undefined;
}
},

SnippetBlock(node, { state }) {
if (
setTemplateCall &&
setTemplateCall.arguments[0].type === 'Identifier' &&
setTemplateCall.arguments[0].name === node.expression.name
) {
state.setTemplateSnippet = node;
}
},
};

walk(fragment, state, visitors);
Expand Down
50 changes: 50 additions & 0 deletions src/parser/extract/svelte/instance-nodes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import type { CallExpression } from 'estree';
import type { Root, SvelteNode } from 'svelte/compiler';
import type { Visitors } from 'zimmerframe';

import type { extractModuleNodes } from './module-nodes.js';

interface Result {
setTemplateCall: CallExpression | undefined;
}

interface Params {
instance: Root['instance'];
moduleNodes: Awaited<ReturnType<typeof extractModuleNodes>>;
filename?: string;
}

/**
* Extract Svelte AST nodes via `svelte.compile`,
* and from the instance tag - `<script>` _(without `context="module"`)_.
* They are needed for further code analysis/transformation.
// NOTE: Is optional for the `*.stories.svelte` files to have this tag.
*/
export async function extractInstanceNodes(options: Params): Promise<Result> {
const { instance, moduleNodes, filename } = options;
const { setTemplateImport } = moduleNodes;

if (!instance || !setTemplateImport) {
return {
setTemplateCall: undefined,
};
}
const { walk } = await import('zimmerframe');

const state: Partial<Result> = {};
const visitors: Visitors<SvelteNode, typeof state> = {
CallExpression(node, { state }) {
if (node.callee.type === 'Identifier' && node.callee.name === setTemplateImport?.local.name) {
state.setTemplateCall = node;
}
},
};

walk(instance.content, state, visitors);

const { setTemplateCall } = state;

return {
setTemplateCall,
};
}
14 changes: 12 additions & 2 deletions src/parser/extract/svelte/nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ import type { Root } from 'svelte/compiler';

import { extractModuleNodes } from './module-nodes.js';
import { extractFragmentNodes } from './fragment-nodes.js';
import { extractInstanceNodes } from './instance-nodes.js';

/**
* Selected nodes extracted from the Svelte AST via `svelte.compile`,
* needed for further code analysis/transformation.
*/
export type SvelteASTNodes = Awaited<ReturnType<typeof extractModuleNodes>> &
Awaited<ReturnType<typeof extractFragmentNodes>>;
Awaited<
ReturnType<typeof extractFragmentNodes> & Awaited<ReturnType<typeof extractInstanceNodes>>
>;

interface Params {
ast: Root;
Expand All @@ -20,17 +23,24 @@ interface Params {
*/
export async function extractSvelteASTNodes(params: Params): Promise<SvelteASTNodes> {
const { ast, filename } = params;
const { module, fragment } = ast;
const { module, fragment, instance } = ast;

const moduleNodes = await extractModuleNodes({ module, filename });
const instanceNodes = await extractInstanceNodes({
instance,
filename,
moduleNodes,
});
const fragmentNodes = await extractFragmentNodes({
fragment,
filename,
moduleNodes,
instanceNodes,
});

return {
...moduleNodes,
...instanceNodes,
...fragmentNodes,
};
}

0 comments on commit e585f27

Please sign in to comment.