Skip to content

Commit

Permalink
Force enable Runes mode in the plugin config
Browse files Browse the repository at this point in the history
  • Loading branch information
SeppahBaws committed Oct 11, 2024
1 parent 655acc3 commit a491f01
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 73 deletions.
40 changes: 20 additions & 20 deletions packages/houdini-svelte/src/plugin/extract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe('parser tests', () => {
`

// parse the string
const result = await parseSvelte(doc)
const result = await parseSvelte(doc, false)

expect(result?.script).toMatchInlineSnapshot('console.log("instance");')
})
Expand All @@ -21,7 +21,7 @@ describe('parser tests', () => {
console.log('module')
</script>`
// parse the string
const result = await parseSvelte(doc)
const result = await parseSvelte(doc, false)

expect(result?.script).toMatchInlineSnapshot('console.log("module");')
})
Expand All @@ -33,7 +33,7 @@ describe('parser tests', () => {
</script>
`
// parse the string
const result = await parseSvelte(doc)
const result = await parseSvelte(doc, false)

expect(result?.script).toMatchInlineSnapshot(`undefined`)
})
Expand All @@ -45,7 +45,7 @@ describe('parser tests', () => {
</script>
`
// parse the string
const result = await parseSvelte(doc)
const result = await parseSvelte(doc, false)

expect(result?.script).toMatchInlineSnapshot(`
type Foo = {
Expand All @@ -61,7 +61,7 @@ describe('parser tests', () => {
</script>
`
// parse the string
const result = await parseSvelte(doc)
const result = await parseSvelte(doc, false)

expect(result?.script).toMatchInlineSnapshot('export let x: T;')
})
Expand Down Expand Up @@ -92,7 +92,7 @@ describe('parser tests', () => {
</script>
`
// parse the string
const result = await parseSvelte(doc)
const result = await parseSvelte(doc, false)

expect(result?.script).toMatchInlineSnapshot(`
import * as FormPrimitive from "formsnap";
Expand All @@ -115,7 +115,7 @@ describe('parser tests', () => {
`

// parse the string
const result = await parseSvelte(doc)
const result = await parseSvelte(doc, false)

expect(result?.script).toMatchInlineSnapshot(`undefined`)
})
Expand All @@ -130,7 +130,7 @@ describe('parser tests', () => {
`

// parse the string
const result = await parseSvelte(doc)
const result = await parseSvelte(doc, false)

expect(result?.script).toMatchInlineSnapshot('console.log("script");')
})
Expand All @@ -144,7 +144,7 @@ describe('parser tests', () => {
</script>
`
// parse the string
const result = await parseSvelte(doc)
const result = await parseSvelte(doc, false)

expect(result?.script).toMatchInlineSnapshot(`undefined`)
})
Expand All @@ -162,7 +162,7 @@ describe('parser tests', () => {
`

// parse the string
const result = await parseSvelte(doc)
const result = await parseSvelte(doc, false)

expect(result?.script).toMatchInlineSnapshot(`undefined`)
})
Expand All @@ -178,7 +178,7 @@ describe('parser tests', () => {
`

// parse the string
const result = await parseSvelte(doc)
const result = await parseSvelte(doc, false)

expect(result?.script).toMatchInlineSnapshot('console.log("hello");')
})
Expand All @@ -197,7 +197,7 @@ describe('parser tests', () => {
`

// parse the string
const result = await parseSvelte(doc)
const result = await parseSvelte(doc, false)

expect(result?.script).toMatchInlineSnapshot('console.log("hello");')
})
Expand All @@ -219,7 +219,7 @@ describe('parser tests', () => {
`

// parse the string
const result = await parseSvelte(doc)
const result = await parseSvelte(doc, false)

expect(result?.script).toMatchInlineSnapshot(`undefined`)
})
Expand All @@ -234,7 +234,7 @@ describe('parser tests', () => {
</div>
`
// parse the string
const result = await parseSvelte(doc)
const result = await parseSvelte(doc, false)

expect(result?.script).toMatchInlineSnapshot(`undefined`)
})
Expand Down Expand Up @@ -262,7 +262,7 @@ describe('parser tests', () => {
</script>
`
// parse the string
const result = await parseSvelte(doc)
const result = await parseSvelte(doc, false)

expect(result?.script).toMatchInlineSnapshot(`undefined`)
})
Expand Down Expand Up @@ -290,7 +290,7 @@ describe('parser tests', () => {
`

// parse the string
const result = await parseSvelte(doc)
const result = await parseSvelte(doc, false)

expect(result?.script).toMatchInlineSnapshot('console.log("hello");')
})
Expand Down Expand Up @@ -320,7 +320,7 @@ describe('parser tests', () => {
`

// parse the string
const result = await parseSvelte(doc)
const result = await parseSvelte(doc, false)

expect(result?.script).toMatchInlineSnapshot(`const example = object({});`)
})
Expand All @@ -334,7 +334,7 @@ describe('parser tests', () => {
`

// parse the string
const result = await parseSvelte(doc)
const result = await parseSvelte(doc, false)

expect(result?.script).toMatchInlineSnapshot(`const example = object({});`)
})
Expand Down Expand Up @@ -364,7 +364,7 @@ describe('parser svelte 5 runes detection', () => {

await Promise.all(
testCases.map(async (testCase) => {
const result = await parseSvelte(testCase.document)
const result = await parseSvelte(testCase.document, false)

expect(result?.useRunes, testCase.title).toBe(false)
})
Expand Down Expand Up @@ -472,7 +472,7 @@ describe('parser svelte 5 runes detection', () => {

await Promise.all(
testCases.map(async (testCase) => {
const result = await parseSvelte(testCase.document)
const result = await parseSvelte(testCase.document, false)

expect(result?.useRunes, `detects usage with ${testCase.runeName} rune`).toBe(true)
})
Expand Down
91 changes: 51 additions & 40 deletions packages/houdini-svelte/src/plugin/extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import type { Config, Maybe, Script } from 'houdini'
import { find_graphql, parseJS } from 'houdini'
import * as svelte from 'svelte/compiler'

import { plugin_config } from './kit'

export default async function ({
config,
content,
Expand All @@ -12,7 +14,8 @@ export default async function ({
content: string
}): Promise<string[]> {
const documents: string[] = []
let parsedFile = await parseSvelte(content)

let parsedFile = await parseSvelte(content, plugin_config(config).forceRunesMode)
if (!parsedFile) {
return documents
}
Expand Down Expand Up @@ -58,7 +61,10 @@ const svelteRunes: string[] = [
'$host',
]

export async function parseSvelte(str: string): Promise<Maybe<EmbeddedScript>> {
export async function parseSvelte(
str: string,
forceRunes: boolean
): Promise<Maybe<EmbeddedScript>> {
// parsing a file happens in two steps:
// - first we use svelte's parser to find the bounds of the script tag
// - then we run the contents through babel to parse it
Expand Down Expand Up @@ -113,46 +119,51 @@ export async function parseSvelte(str: string): Promise<Maybe<EmbeddedScript>> {
// while the second has a "MemberExpression" callee.
let usesRunes = false

walk(scriptParsed, {
enter(node) {
if (node.type === 'CallExpression') {
let callNode = node as CallExpressionKind

if (callNode.callee.type === 'Identifier') {
// Callee type can be 'Identifier' in the case of `$state()` etc.
const calleeName = callNode.callee.name

// See if the callee name matches any of the known runes
if (svelteRunes.some((rune) => rune === calleeName)) {
usesRunes = true

// We detected a Rune, stop walking the AST
this.skip()
}
} else if (callNode.callee.type === 'MemberExpression') {
// Or it can be a "MemberExpression" in the case of $state.frozen()`
const callee = callNode.callee

// The `object` and `property` nodes need to be an Identifier
if (
callee.object.type !== 'Identifier' ||
callee.property.type !== 'Identifier'
) {
return
}

// See if the callee name matches any of the known runes
const calleeName = `${callee.object.name}.${callee.property.name}`
if (svelteRunes.some((rune) => rune === calleeName)) {
usesRunes = true

// We detected a Rune, stop walking the AST
this.skip()
// If we were forced to enable Runes mode, we don't need to walk the tree to check if we're using Runes
if (forceRunes) {
usesRunes = true
} else {
walk(scriptParsed, {
enter(node) {
if (node.type === 'CallExpression') {
let callNode = node as CallExpressionKind

if (callNode.callee.type === 'Identifier') {
// Callee type can be 'Identifier' in the case of `$state()` etc.
const calleeName = callNode.callee.name

// See if the callee name matches any of the known runes
if (svelteRunes.some((rune) => rune === calleeName)) {
usesRunes = true

// We detected a Rune, stop walking the AST
this.skip()
}
} else if (callNode.callee.type === 'MemberExpression') {
// Or it can be a "MemberExpression" in the case of $state.frozen()`
const callee = callNode.callee

// The `object` and `property` nodes need to be an Identifier
if (
callee.object.type !== 'Identifier' ||
callee.property.type !== 'Identifier'
) {
return
}

// See if the callee name matches any of the known runes
const calleeName = `${callee.object.name}.${callee.property.name}`
if (svelteRunes.some((rune) => rune === calleeName)) {
usesRunes = true

// We detected a Rune, stop walking the AST
this.skip()
}
}
}
}
},
})
},
})
}

return {
script: scriptParsed,
Expand Down
7 changes: 7 additions & 0 deletions packages/houdini-svelte/src/plugin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,13 @@ export type HoudiniSvelteConfig = {
*/
framework: 'kit' | 'svelte' | undefined

/**
* Force Houdini to always use Runes under the hood. Set this to true if you are enabling Runes mode globally for your app.
* When disabled, Houdini will try to detect Runes and go into Runes mode if required.
* @default false
*/
forceRunesMode?: boolean

/**
* Override the classes used when building stores for documents. Values should take the form package.export
* For example, if you have a store exported from $lib/stores you should set the value to "$lib/stores.CustomStore".
Expand Down
7 changes: 4 additions & 3 deletions packages/houdini-svelte/src/plugin/kit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export async function walk_routes(
if (!contents) {
continue
}
const parsed = await parseSvelte(contents)
const parsed = await parseSvelte(contents, plugin_config(config).forceRunesMode)
if (!parsed) {
continue
}
Expand Down Expand Up @@ -209,7 +209,7 @@ export async function walk_routes(
if (!contents) {
continue
}
const parsed = await parseSvelte(contents)
const parsed = await parseSvelte(contents, plugin_config(config).forceRunesMode)
if (!parsed) {
continue
}
Expand Down Expand Up @@ -239,7 +239,7 @@ export async function walk_routes(
if (!contents) {
continue
}
const parsed = await parseSvelte(contents)
const parsed = await parseSvelte(contents, plugin_config(config).forceRunesMode)
if (!parsed) {
continue
}
Expand Down Expand Up @@ -415,6 +415,7 @@ export function plugin_config(config: Config): Required<HoudiniSvelteConfig> {
pageQueryFilename: '+page.gql',
layoutQueryFilename: '+layout.gql',
static: false,
forceRunesMode: false,
...cfg,
customStores: {
query: '../runtime/stores/query.QueryStore',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,4 +367,47 @@ describe('Svelte 5 runes', function () {
});
`)
})

test('force Runes mode enabled', async function () {
const route = await component_test(
`
const store = graphql(\`
query TestQuery($test: String!) @load {
users(stringValue: $test) {
id
}
}
\`)
`,
{
plugins: {
'houdini-plugin-svelte-global-stores': {},
'houdini-svelte': {
framework: 'kit',
forceRunesMode: true,
},
},
}
)

expect(route).toMatchInlineSnapshot(`
import { TestQueryStore } from "$houdini/plugins/houdini-svelte/stores/TestQuery";
import { isBrowser } from "$houdini/plugins/houdini-svelte/runtime/adapter";
import { RequestContext } from "$houdini/plugins/houdini-svelte/runtime/session";
import { getCurrentConfig } from "$houdini/runtime/lib/config";
import { marshalInputs } from "$houdini/runtime/lib/scalars";
const _houdini_TestQuery = new TestQueryStore();
const store = _houdini_TestQuery;
$effect(() => {
_houdini_TestQuery.fetch({
variables: marshalInputs({
config: getCurrentConfig(),
artifact: _houdini_TestQuery.artifact,
input: {}
})
});
});
`)
})
})
Loading

0 comments on commit a491f01

Please sign in to comment.