From 513f9358294738449ccc14793a3a6d623b1f4cf5 Mon Sep 17 00:00:00 2001 From: David Plugge <59972093+david-plugge@users.noreply.github.com> Date: Thu, 15 Sep 2022 12:22:11 +0200 Subject: [PATCH] (feat) create sveltekit route files (#1620) Adds commands and a context menu entries for creating SvelteKit route files + some snippets --- packages/svelte-vscode/package.json | 93 +++++++++++ .../svelte-vscode/snippets/javascript.json | 43 +++++ .../svelte-vscode/snippets/typescript.json | 37 +++++ packages/svelte-vscode/src/extension.ts | 4 + .../src/sveltekit/generateFiles/commands.ts | 12 ++ .../src/sveltekit/generateFiles/generate.ts | 38 +++++ .../src/sveltekit/generateFiles/index.ts | 149 ++++++++++++++++++ .../src/sveltekit/generateFiles/resources.ts | 52 ++++++ .../generateFiles/templates/error.ts | 21 +++ .../generateFiles/templates/layout-load.ts | 20 +++ .../generateFiles/templates/layout-server.ts | 20 +++ .../generateFiles/templates/layout.ts | 20 +++ .../generateFiles/templates/page-load.ts | 20 +++ .../generateFiles/templates/page-server.ts | 20 +++ .../sveltekit/generateFiles/templates/page.ts | 20 +++ .../generateFiles/templates/server.ts | 20 +++ .../src/sveltekit/generateFiles/types.ts | 42 +++++ packages/svelte-vscode/src/sveltekit/index.ts | 6 + packages/svelte-vscode/src/sveltekit/utils.ts | 29 ++++ 19 files changed, 666 insertions(+) create mode 100644 packages/svelte-vscode/snippets/javascript.json create mode 100644 packages/svelte-vscode/snippets/typescript.json create mode 100644 packages/svelte-vscode/src/sveltekit/generateFiles/commands.ts create mode 100644 packages/svelte-vscode/src/sveltekit/generateFiles/generate.ts create mode 100644 packages/svelte-vscode/src/sveltekit/generateFiles/index.ts create mode 100644 packages/svelte-vscode/src/sveltekit/generateFiles/resources.ts create mode 100644 packages/svelte-vscode/src/sveltekit/generateFiles/templates/error.ts create mode 100644 packages/svelte-vscode/src/sveltekit/generateFiles/templates/layout-load.ts create mode 100644 packages/svelte-vscode/src/sveltekit/generateFiles/templates/layout-server.ts create mode 100644 packages/svelte-vscode/src/sveltekit/generateFiles/templates/layout.ts create mode 100644 packages/svelte-vscode/src/sveltekit/generateFiles/templates/page-load.ts create mode 100644 packages/svelte-vscode/src/sveltekit/generateFiles/templates/page-server.ts create mode 100644 packages/svelte-vscode/src/sveltekit/generateFiles/templates/page.ts create mode 100644 packages/svelte-vscode/src/sveltekit/generateFiles/templates/server.ts create mode 100644 packages/svelte-vscode/src/sveltekit/generateFiles/types.ts create mode 100644 packages/svelte-vscode/src/sveltekit/index.ts create mode 100644 packages/svelte-vscode/src/sveltekit/utils.ts diff --git a/packages/svelte-vscode/package.json b/packages/svelte-vscode/package.json index d5e98a758..1025a4566 100644 --- a/packages/svelte-vscode/package.json +++ b/packages/svelte-vscode/package.json @@ -538,6 +538,42 @@ { "command": "svelte.typescript.findComponentReferences", "title": "Svelte: Find Component References" + }, + { + "command": "svelte.kit.generateMultipleFiles", + "title": "SvelteKit: Generate files" + }, + { + "command": "svelte.kit.generatePage", + "title": "SvelteKit: Generate Page" + }, + { + "command": "svelte.kit.generatePageLoad", + "title": "SvelteKit: Generate Page load" + }, + { + "command": "svelte.kit.generatePageServerLoad", + "title": "SvelteKit: Generate Page server load" + }, + { + "command": "svelte.kit.generateLayout", + "title": "SvelteKit: Generate Layout" + }, + { + "command": "svelte.kit.generateLayoutLoad", + "title": "SvelteKit: Generate Layout load" + }, + { + "command": "svelte.kit.generateLayoutServerLoad", + "title": "SvelteKit: Generate Layout server load" + }, + { + "command": "svelte.kit.generateServer", + "title": "SvelteKit: Generate Endpoint" + }, + { + "command": "svelte.kit.generateError", + "title": "SvelteKit: Generate Error" } ], "menus": { @@ -599,9 +635,58 @@ "command": "svelte.typescript.findComponentReferences", "when": "resourceLangId == svelte", "group": "4_search" + }, + { + "when": "explorerResourceIsFolder", + "submenu": "sveltekit2files", + "group": "1_SvelteKit2files" + } + ], + "sveltekit2files": [ + { + "command": "svelte.kit.generateMultipleFiles", + "group": "0_SvelteKit_Multiple" + }, + { + "command": "svelte.kit.generatePage", + "group": "1_SvelteKit_Page" + }, + { + "command": "svelte.kit.generatePageLoad", + "group": "1_SvelteKit_Page" + }, + { + "command": "svelte.kit.generatePageServerLoad", + "group": "1_SvelteKit_Page" + }, + { + "command": "svelte.kit.generateLayout", + "group": "3_SvelteKit_Layout" + }, + { + "command": "svelte.kit.generateLayoutLoad", + "group": "3_SvelteKit_Layout" + }, + { + "command": "svelte.kit.generateLayoutServerLoad", + "group": "3_SvelteKit_Layout" + }, + { + "command": "svelte.kit.generateServer", + "group": "2_SvelteKit_Server" + }, + { + "command": "svelte.kit.generateError", + "group": "4_SvelteKit_Error" } ] }, + "submenus": [ + { + "id": "sveltekit2files", + "label": "SvelteKit Files" + } + ], "breakpoints": [ { "language": "svelte" @@ -611,6 +696,14 @@ { "language": "svelte", "path": "./snippets/svelte.json" + }, + { + "language": "javascript", + "path": "./snippets/javascript.json" + }, + { + "language": "typescript", + "path": "./snippets/typescript.json" } ] }, diff --git a/packages/svelte-vscode/snippets/javascript.json b/packages/svelte-vscode/snippets/javascript.json new file mode 100644 index 000000000..417f51cc4 --- /dev/null +++ b/packages/svelte-vscode/snippets/javascript.json @@ -0,0 +1,43 @@ +{ + "SvelteKit Endpoint": { + "prefix": "kitEndpoint", + "description": "SvelteKit Endpoint", + "body": [ + "/** @type {import('./\\$types').RequestHandler} */", + "export async function ${1|GET,POST,PUT,PATCH,DELETE|}($2) {", + "\t$3", + "\treturn new Response();", + "}" + ] + }, + "SvelteKit Actions": { + "prefix": "kitActions", + "description": "SvelteKit Actions", + "body": [ + "/** @type {import('./\\$types').Actions} */", + "export const actions = {", + "\t$1", + "};" + ] + }, + "SvelteKit Load": { + "prefix": "kitLoad", + "description": "SvelteKit Load", + "body": [ + "/** @type {import('./\\$types').${1|PageLoad,PageServerLoad,LayoutLoad,LayoutServerLoad|}} */", + "export async function load($2) {", + "\t$3", + "}" + ] + }, + "SvelteKit Param Matcher": { + "prefix": "kitParamMatcher", + "description": "SvelteKit Param Matcher", + "body": [ + "/** @type {import('./\\$types').ParamMatcher */", + "export function match(param) {", + "\treturn $1;", + "}" + ] + } +} diff --git a/packages/svelte-vscode/snippets/typescript.json b/packages/svelte-vscode/snippets/typescript.json new file mode 100644 index 000000000..e3fe5db58 --- /dev/null +++ b/packages/svelte-vscode/snippets/typescript.json @@ -0,0 +1,37 @@ +{ + "SvelteKit Endpoint": { + "prefix": "kitEndpoint", + "description": "SvelteKit Endpoint", + "body": [ + "export const ${1|GET,POST,PUT,PATCH,DELETE|}: RequestHandler = async ($2) => {", + "\t$3", + "\treturn new Response();", + "};" + ] + }, + "SvelteKit Actions": { + "prefix": "kitActions", + "description": "SvelteKit Actions", + "body": ["export const actions: Actions = {", "\t$1", "};"] + }, + "SvelteKit Load": { + "prefix": "kitLoad", + "description": "SvelteKit Load", + "body": [ + "export const load: ${1|PageLoad,PageServerLoad,LayoutLoad,LayoutServerLoad|} = async ($2) => {", + "\t$3", + "};" + ] + }, + "SvelteKit Param Matcher": { + "prefix": "kitParamMatcher", + "description": "SvelteKit Param Matcher", + "body": [ + "import type { ParamMatcher } from '@sveltejs/kit';", + "", + "export const match: ParamMatcher = (param) => {", + "\treturn $1;", + "};" + ] + } +} diff --git a/packages/svelte-vscode/src/extension.ts b/packages/svelte-vscode/src/extension.ts index 0e4ba25fd..012fb6e56 100644 --- a/packages/svelte-vscode/src/extension.ts +++ b/packages/svelte-vscode/src/extension.ts @@ -31,7 +31,9 @@ import { EMPTY_ELEMENTS } from './html/htmlEmptyTagsShared'; import { TsPlugin } from './tsplugin'; import { addFindComponentReferencesListener } from './typescript/findComponentReferences'; import { addFindFileReferencesListener } from './typescript/findFileReferences'; +import { setupSvelteKit } from './sveltekit'; +// eslint-disable-next-line @typescript-eslint/no-namespace namespace TagCloseRequest { export const type: RequestType = new RequestType( 'html/tag' @@ -60,6 +62,8 @@ export function activate(context: ExtensionContext) { context.subscriptions.push(onTextDocumentListener); } + setupSvelteKit(context); + // This API is considered private and only exposed for experimenting. // Interface may change at any time. Use at your own risk! return { diff --git a/packages/svelte-vscode/src/sveltekit/generateFiles/commands.ts b/packages/svelte-vscode/src/sveltekit/generateFiles/commands.ts new file mode 100644 index 000000000..7d3f013e7 --- /dev/null +++ b/packages/svelte-vscode/src/sveltekit/generateFiles/commands.ts @@ -0,0 +1,12 @@ +import { CommandType, ResourceType } from './types'; + +export const addResourceCommandMap = new Map([ + [CommandType.PAGE, ResourceType.PAGE], + [CommandType.PAGE_LOAD, ResourceType.PAGE_LOAD], + [CommandType.PAGE_SERVER, ResourceType.PAGE_SERVER], + [CommandType.LAYOUT, ResourceType.LAYOUT], + [CommandType.LAYOUT_LOAD, ResourceType.LAYOUT_LOAD], + [CommandType.LAYOUT_SERVER, ResourceType.LAYOUT_SERVER], + [CommandType.SERVER, ResourceType.SERVER], + [CommandType.ERROR, ResourceType.ERROR] +]); diff --git a/packages/svelte-vscode/src/sveltekit/generateFiles/generate.ts b/packages/svelte-vscode/src/sveltekit/generateFiles/generate.ts new file mode 100644 index 000000000..31a27fcf8 --- /dev/null +++ b/packages/svelte-vscode/src/sveltekit/generateFiles/generate.ts @@ -0,0 +1,38 @@ +import { FileType, GenerateConfig } from './types'; +import { join } from 'path'; +import { Position, Uri, window, workspace, WorkspaceEdit } from 'vscode'; + +export async function generateResources(config: GenerateConfig) { + workspace.fs.createDirectory(Uri.file(config.path)); + const edit = new WorkspaceEdit(); + + for (const resource of config.resources) { + const ext = resource.type === FileType.PAGE ? config.pageExtension : config.scriptExtension; + const filepath = join(config.path, `${resource.filename}.${ext}`); + + const uri = Uri.file(filepath); + edit.createFile(uri, { + overwrite: false, + ignoreIfExists: true + }); + + const data = await resource.generate(config); + edit.insert(uri, new Position(0, 0), data); + } + + await workspace.applyEdit(edit); + + // save documents and open the first + await Promise.all( + edit.entries().map(async ([uri], i) => { + const doc = workspace.textDocuments.find((t) => t.uri.path === uri.path); + if (doc) { + await doc?.save(); + if (i === 0) { + await workspace.openTextDocument(uri); + await window.showTextDocument(doc); + } + } + }) + ); +} diff --git a/packages/svelte-vscode/src/sveltekit/generateFiles/index.ts b/packages/svelte-vscode/src/sveltekit/generateFiles/index.ts new file mode 100644 index 000000000..ba8a3e55d --- /dev/null +++ b/packages/svelte-vscode/src/sveltekit/generateFiles/index.ts @@ -0,0 +1,149 @@ +import * as path from 'path'; +import { commands, ExtensionContext, ProgressLocation, Uri, window, workspace } from 'vscode'; +import { addResourceCommandMap } from './commands'; +import { generateResources } from './generate'; +import { resourcesMap } from './resources'; +import { FileType, ResourceType, GenerateConfig, CommandType } from './types'; +import { checkIfTypescriptProject } from '../utils'; + +class GenerateError extends Error {} + +export function addGenerateKitRouteFilesCommand(context: ExtensionContext) { + addResourceCommandMap.forEach((value, key) => { + context.subscriptions.push( + commands.registerCommand(key, (args) => { + handleSingle(args, value).catch(handleError); + }) + ); + }); + context.subscriptions.push( + commands.registerCommand(CommandType.MULTIPLE, async (args) => { + handleMultiple(args).catch(handleError); + }) + ); +} + +async function handleError(err: unknown) { + if (err instanceof GenerateError) { + await window.showErrorMessage(err.message); + } else { + throw err; + } +} + +async function handleSingle(uri: Uri | undefined, resourceType: ResourceType) { + const resource = resourcesMap.get(resourceType); + if (!resource) { + throw new GenerateError(`Resource '${resourceType}' does not exist`); + } + const resources = [resource]; + + const { isTs, rootPath, scriptExtension } = await getCommonConfig(uri); + + const itemPath = await promptResourcePath(); + + if (!itemPath) { + return; + } + + await generate({ + path: path.join(rootPath, itemPath), + typescript: isTs, + pageExtension: 'svelte', + scriptExtension, + resources + }); +} + +async function handleMultiple(uri: Uri | undefined) { + const { isTs, rootPath, scriptExtension } = await getCommonConfig(uri); + + // Add multiple files + const opts = [ + ResourceType.PAGE, + ResourceType.PAGE_LOAD, + ResourceType.PAGE_SERVER, + ResourceType.LAYOUT, + ResourceType.LAYOUT_LOAD, + ResourceType.LAYOUT_SERVER, + ResourceType.ERROR + ].map((type) => { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const resource = resourcesMap.get(type)!; + // const iconName = resource.type === FileType.PAGE ? 'svelte' : isTs ? 'typescript' : 'javascript'; + const extension = resource.type === FileType.PAGE ? 'svelte' : scriptExtension; + return { + label: resource.title, + // TODO: maybe add icons (ts,js,svelte - but it doesn´t work like this) + // description: `$(${iconName}) ${resource.filename}.${extension}`, + description: `${resource.filename}.${extension}`, + value: resource + }; + }); + const result = await window.showQuickPick(opts, { canPickMany: true }); + if (!result) { + return; + } + const resources = result.map((res) => res.value); + + const itemPath = await promptResourcePath(); + + if (!itemPath) { + return; + } + + await generate({ + path: path.join(rootPath, itemPath), + typescript: isTs, + pageExtension: 'svelte', + scriptExtension, + resources + }); +} + +async function promptResourcePath() { + const itemPath = await window.showInputBox({ + prompt: 'Enter the path of the resources, relative to current folder', + value: '/' + }); + + return itemPath; +} + +async function generate(config: GenerateConfig) { + await window.withProgress( + { location: ProgressLocation.Window, title: 'Creating SvelteKit files...' }, + async () => { + await generateResources(config); + } + ); +} + +async function getCommonConfig(uri: Uri | undefined) { + const rootPath = getRootPath(uri); + if (!rootPath) { + throw new GenerateError( + 'Could not resolve root path. Please open a file first or use the context menu!' + ); + } + + const isTs = await checkIfTypescriptProject(rootPath); + const scriptExtension = isTs ? 'ts' : 'js'; + return { + isTs, + scriptExtension, + rootPath + }; +} + +function getRootPath(uri: Uri | undefined) { + let rootPath!: string; + if (uri) { + rootPath = uri.fsPath; + } else if (window.activeTextEditor) { + rootPath = path.dirname(window.activeTextEditor.document.fileName); + } else if (workspace.workspaceFolders && workspace.workspaceFolders.length === 1) { + rootPath = workspace.workspaceFolders[0].uri.fsPath; + } + return rootPath; +} diff --git a/packages/svelte-vscode/src/sveltekit/generateFiles/resources.ts b/packages/svelte-vscode/src/sveltekit/generateFiles/resources.ts new file mode 100644 index 000000000..eb312f37c --- /dev/null +++ b/packages/svelte-vscode/src/sveltekit/generateFiles/resources.ts @@ -0,0 +1,52 @@ +import { FileType, Resource, ResourceType } from './types'; + +import page from './templates/page'; +import pageLoad from './templates/page-load'; +import pageServer from './templates/page-server'; +import layout from './templates/layout'; +import layoutLoad from './templates/layout-load'; +import layoutServer from './templates/layout-server'; +import error from './templates/error'; +import server from './templates/server'; + +export const resourcesMap = new Map([ + [ResourceType.PAGE, { type: FileType.PAGE, filename: '+page', title: 'Page', generate: page }], + [ + ResourceType.PAGE_LOAD, + { type: FileType.SCRIPT, filename: '+page', title: 'Page load', generate: pageLoad } + ], + [ + ResourceType.PAGE_SERVER, + { + type: FileType.SCRIPT, + filename: '+page.server', + title: 'Page server load', + generate: pageServer + } + ], + [ + ResourceType.LAYOUT, + { type: FileType.PAGE, filename: '+layout', title: 'Layout', generate: layout } + ], + [ + ResourceType.LAYOUT_LOAD, + { type: FileType.SCRIPT, filename: '+layout', title: 'Layout load', generate: layoutLoad } + ], + [ + ResourceType.LAYOUT_SERVER, + { + type: FileType.SCRIPT, + filename: '+layout.server', + title: 'Layout server load', + generate: layoutServer + } + ], + [ + ResourceType.SERVER, + { type: FileType.SCRIPT, filename: '+server', title: 'Server', generate: server } + ], + [ + ResourceType.ERROR, + { type: FileType.PAGE, filename: '+error', title: 'Error', generate: error } + ] +]); diff --git a/packages/svelte-vscode/src/sveltekit/generateFiles/templates/error.ts b/packages/svelte-vscode/src/sveltekit/generateFiles/templates/error.ts new file mode 100644 index 000000000..70eff270e --- /dev/null +++ b/packages/svelte-vscode/src/sveltekit/generateFiles/templates/error.ts @@ -0,0 +1,21 @@ +import { GenerateConfig } from '../types'; + +export default async function (config: GenerateConfig) { + const ts = ` + + +

{$page.status}: {$page.error.message}

+ `.trim(); + + const js = ` + + +

{$page.status}: {$page.error.message}

+ `.trim(); + + return config.typescript ? ts : js; +} diff --git a/packages/svelte-vscode/src/sveltekit/generateFiles/templates/layout-load.ts b/packages/svelte-vscode/src/sveltekit/generateFiles/templates/layout-load.ts new file mode 100644 index 000000000..8fd4c4d92 --- /dev/null +++ b/packages/svelte-vscode/src/sveltekit/generateFiles/templates/layout-load.ts @@ -0,0 +1,20 @@ +import { GenerateConfig } from '../types'; + +export default async function (config: GenerateConfig) { + const ts = ` +import type { LayoutLoad } from './$types'; + +export const load: LayoutLoad = async () => { + return {}; +}; + `.trim(); + + const js = ` +/** @type {import('./$types').LayoutLoad} */ +export async function load() { + return {}; +} + `.trim(); + + return config.typescript ? ts : js; +} diff --git a/packages/svelte-vscode/src/sveltekit/generateFiles/templates/layout-server.ts b/packages/svelte-vscode/src/sveltekit/generateFiles/templates/layout-server.ts new file mode 100644 index 000000000..a954664bf --- /dev/null +++ b/packages/svelte-vscode/src/sveltekit/generateFiles/templates/layout-server.ts @@ -0,0 +1,20 @@ +import { GenerateConfig } from '../types'; + +export default async function (config: GenerateConfig) { + const ts = ` +import type { LayoutServerLoad } from './$types'; + +export const load: LayoutServerLoad = async () => { + return {}; +}; + `.trim(); + + const js = ` +/** @type {import('./$types').LayoutServerLoad} */ +export async function load() { + return {}; +} + `.trim(); + + return config.typescript ? ts : js; +} diff --git a/packages/svelte-vscode/src/sveltekit/generateFiles/templates/layout.ts b/packages/svelte-vscode/src/sveltekit/generateFiles/templates/layout.ts new file mode 100644 index 000000000..6173a7711 --- /dev/null +++ b/packages/svelte-vscode/src/sveltekit/generateFiles/templates/layout.ts @@ -0,0 +1,20 @@ +import { GenerateConfig } from '../types'; + +export default async function (config: GenerateConfig) { + const ts = ` + + `.trim(); + + const js = ` + + `.trim(); + + return config.typescript ? ts : js; +} diff --git a/packages/svelte-vscode/src/sveltekit/generateFiles/templates/page-load.ts b/packages/svelte-vscode/src/sveltekit/generateFiles/templates/page-load.ts new file mode 100644 index 000000000..29c322825 --- /dev/null +++ b/packages/svelte-vscode/src/sveltekit/generateFiles/templates/page-load.ts @@ -0,0 +1,20 @@ +import { GenerateConfig } from '../types'; + +export default async function (config: GenerateConfig) { + const ts = ` +import type { PageLoad } from './$types'; + +export const load: PageLoad = async () => { + return {}; +}; + `.trim(); + + const js = ` +/** @type {import('./$types').PageLoad} */ +export async function load() { + return {}; +}; + `.trim(); + + return config.typescript ? ts : js; +} diff --git a/packages/svelte-vscode/src/sveltekit/generateFiles/templates/page-server.ts b/packages/svelte-vscode/src/sveltekit/generateFiles/templates/page-server.ts new file mode 100644 index 000000000..46dea41de --- /dev/null +++ b/packages/svelte-vscode/src/sveltekit/generateFiles/templates/page-server.ts @@ -0,0 +1,20 @@ +import { GenerateConfig } from '../types'; + +export default async function (config: GenerateConfig) { + const ts = ` +import type { PageServerLoad } from './$types'; + +export const load: PageServerLoad = async () => { + return {}; +}; + `.trim(); + + const js = ` +/** @type {import('./$types').PageServerLoad} */ +export async function load() { + return {}; +}; + `.trim(); + + return config.typescript ? ts : js; +} diff --git a/packages/svelte-vscode/src/sveltekit/generateFiles/templates/page.ts b/packages/svelte-vscode/src/sveltekit/generateFiles/templates/page.ts new file mode 100644 index 000000000..95ac3a611 --- /dev/null +++ b/packages/svelte-vscode/src/sveltekit/generateFiles/templates/page.ts @@ -0,0 +1,20 @@ +import { GenerateConfig } from '../types'; + +export default async function (config: GenerateConfig) { + const ts = ` + + `.trim(); + + const js = ` + + `.trim(); + + return config.typescript ? ts : js; +} diff --git a/packages/svelte-vscode/src/sveltekit/generateFiles/templates/server.ts b/packages/svelte-vscode/src/sveltekit/generateFiles/templates/server.ts new file mode 100644 index 000000000..5be1ef7a9 --- /dev/null +++ b/packages/svelte-vscode/src/sveltekit/generateFiles/templates/server.ts @@ -0,0 +1,20 @@ +import { GenerateConfig } from '../types'; + +export default async function generate(config: GenerateConfig) { + const ts = ` +import type { RequestHandler } from './$types'; + +export const GET: RequestHandler = async () => { + return new Response(); +}; + `.trim(); + + const js = ` +/** @type {import('./$types').RequestHandler} */ +export async function GET() { + return new Response(); +}; + `.trim(); + + return config.typescript ? ts : js; +} diff --git a/packages/svelte-vscode/src/sveltekit/generateFiles/types.ts b/packages/svelte-vscode/src/sveltekit/generateFiles/types.ts new file mode 100644 index 000000000..c61ec54b6 --- /dev/null +++ b/packages/svelte-vscode/src/sveltekit/generateFiles/types.ts @@ -0,0 +1,42 @@ +export enum CommandType { + PAGE = 'svelte.kit.generatePage', + PAGE_LOAD = 'svelte.kit.generatePageLoad', + PAGE_SERVER = 'svelte.kit.generatePageServerLoad', + LAYOUT = 'svelte.kit.generateLayout', + LAYOUT_LOAD = 'svelte.kit.generateLayoutLoad', + LAYOUT_SERVER = 'svelte.kit.generateLayoutServerLoad', + SERVER = 'svelte.kit.generateServer', + ERROR = 'svelte.kit.generateError', + MULTIPLE = 'svelte.kit.generateMultipleFiles' +} + +export enum FileType { + SCRIPT, + PAGE +} + +export enum ResourceType { + PAGE, + PAGE_LOAD, + PAGE_SERVER, + LAYOUT, + LAYOUT_LOAD, + LAYOUT_SERVER, + SERVER, + ERROR +} + +export type Resource = { + type: FileType; + filename: string; + title: string; + generate: (config: GenerateConfig) => Promise; +}; + +export interface GenerateConfig { + path: string; + typescript: boolean; + pageExtension: string; + scriptExtension: string; + resources: Resource[]; +} diff --git a/packages/svelte-vscode/src/sveltekit/index.ts b/packages/svelte-vscode/src/sveltekit/index.ts new file mode 100644 index 000000000..9b176c39f --- /dev/null +++ b/packages/svelte-vscode/src/sveltekit/index.ts @@ -0,0 +1,6 @@ +import { ExtensionContext } from 'vscode'; +import { addGenerateKitRouteFilesCommand } from './generateFiles'; + +export function setupSvelteKit(context: ExtensionContext) { + addGenerateKitRouteFilesCommand(context); +} diff --git a/packages/svelte-vscode/src/sveltekit/utils.ts b/packages/svelte-vscode/src/sveltekit/utils.ts new file mode 100644 index 000000000..07ffc574a --- /dev/null +++ b/packages/svelte-vscode/src/sveltekit/utils.ts @@ -0,0 +1,29 @@ +import * as path from 'path'; +import { Uri, workspace } from 'vscode'; + +export async function fileExists(file: string) { + try { + await workspace.fs.stat(Uri.file(file)); + return true; + } catch (err) { + return false; + } +} + +export async function findFile(searchPath: string, fileName: string) { + for (;;) { + const filePath = path.join(searchPath, fileName); + if (await fileExists(filePath)) { + return filePath; + } + const parentPath = path.dirname(searchPath); + if (parentPath === searchPath) { + return; + } + searchPath = parentPath; + } +} + +export async function checkIfTypescriptProject(path: string) { + return !!(await findFile(path, 'tsconfig.json')); +}