sv-utils = what to do to content, sv = where and when to do it.
Each transform wraps: parse -> callback({ast/data, utils}) -> generateCode().
The parser choice is baked into the transform type - you can't accidentally
parse a vite config as svelte because you never call a parser yourself.
Transforms are curried: call with the callback to get a (content: string) => string
function that plugs directly into sv.file().
import{transforms}from'@sveltejs/sv-utils';// use with sv.file() - curried form plugs in directlysv.file(files.viteConfig,transforms.script(({ast,js})=>{js.vite.addPlugin(ast,{code:'kitRoutes()'});}));// standalone usage / testingconstresult=transforms.script(({ast,js})=>{js.imports.addDefault(ast,{as:'foo',from:'foo'});})(fileContent);
}from'sv';exportdefaultdefineAddon(alias)defineAddon<"addon-name",{who:Question<Record<"who",{readonlyquestion:"À qui cet add-on doit-il dire bonjour ?";readonlytype:"string";}>>;}>(config:Addon<{who:Question<Record<"who",{readonlyquestion:"À qui cet add-on doit-il dire bonjour ?";readonlytype:"string";}>>;},"addon-name",Record<string,unknown>>):Addon<{who:Question<Record<"who",{readonlyquestion:"À qui cet add-on doit-il dire bonjour ?";readonlytype:"string";}>>;},"addon-name",Record<string,unknown>>(+1overload)importdefineAddon
The entry point for your addon, It will hold every thing! (options, setup, run, nextSteps, ...)
For dynamic options added via addOption in setup, use the generic to get strong typing:
({id(property)id:"addon-name":'addon-name',shortDescription(property)shortDescription?:string|undefined:'une meilleure description de ce que fait votre add-on ;)',options(property)options:{who:Question<Record<"who",{readonlyquestion:"À qui cet add-on doit-il dire bonjour ?";readonlytype:"string";}>>;}:defineAddonOptions(alias)defineAddonOptions():OptionBuilder<{}>importdefineAddonOptions
Options for an addon.
Will be prompted to the user if there are not answered by args when calling the cli.
().add(method)add<"who",Question<Record<"who",{readonlyquestion:"À qui cet add-on doit-il dire bonjour ?";readonlytype:"string";}>>>(key:"who",question:Question<Record<"who",{readonlyquestion:"À qui cet add-on doit-il dire bonjour ?";readonlytype:"string";}>>):OptionBuilder<Record<"who",Question<Record<"who",{readonlyquestion:"À qui cet add-on doit-il dire bonjour ?";readonlytype:"string";}>>>>
This type is a bit complex, but in usage, it's quite simple!
The idea is to add() options one by one, with the key and the question.
.add('demo',{question:'Do you want to add a demo?',type:'boolean',// string, number, select, multiselectdefault:true,// condition: (o) => o.previousOption === 'ok',})
('who',{question(property)question:string:'À qui cet add-on doit-il dire bonjour ?',type(property)type:"string":'string'// boolean | number | select | multiselect}).build(method)build():{who:Question<Record<"who",{readonlyquestion:"À qui cet add-on doit-il dire bonjour ?";readonlytype:"string";}>>;}(),setup(property)setup?:((workspace:Workspace&{dependsOn:(name:keyofOfficialAddons)=>void;unsupported:(reason:string)=>void;runsAfter:(name:keyofOfficialAddons)=>void;addOption:<Kextendsstring>(key:K,question:BaseQuestion<any>&Question<any>)=>void;})=>MaybePromise<void>)|undefined:({dependsOn(parameter)dependsOn:(name:keyofOfficialAddons)=>void
On what official addons does this addon depend on?
On what official addons does this addon depend on?
('vitest');// ajoute dynamiquement des options (par ex. basé sur l'état du workspace ou des données récupérées) // addOption('key', { question: '...', type: 'boolean', default: true });
},run(property)run:(workspace:Workspace&{options:OptionValues<{who:Question<Record<"who",{readonlyquestion:"À qui cet add-on doit-il dire bonjour ?";readonlytype:"string";}>>;}>&Record<string,unknown>;sv:SvApi;cancel:(reason:string)=>void;})=>MaybePromise<void>:({isKit(parameter)isKit:boolean,cancel(parameter)cancel:(reason:string)=>void
Cancel the addon at any time!
,sv(parameter)sv:SvApi,options(parameter)options:OptionValues<{who:Question<Record<"who",{readonlyquestion:"À qui cet add-on doit-il dire bonjour ?";readonlytype:"string";}>>;}>&Record<string,unknown>
Add-on options (includes dynamically added options from setup)
,file(parameter)file:{viteConfig:"vite.config.js"|"vite.config.ts";svelteConfig:"svelte.config.js"|"svelte.config.ts";typeConfig:"jsconfig.json"|"tsconfig.json"|undefined;stylesheet:`${string}/layout.css`|"src/app.css";package:"package.json";gitignore:".gitignore";prettierignore:".prettierignore";prettierrc:".prettierrc";eslintConfig:"eslint.config.js";vscodeSettings:".vscode/settings.json";vscodeExtensions:".vscode/extensions.json";getRelative:({from,to}:{from?:string;to:string;})=>string;findUp:(filename:string)=>string;},language(parameter)language:"ts"|"js",directory(parameter)directory:{src:string;lib:string;kitRoutes:string;}})=>{ // Ajoute "Bonjour [who] !" sur la page racine
sv(parameter)sv:SvApi.file(property)file:(path:string,edit:(content:string)=>string|false)=>void
Edit a file in the workspace. (will create it if it doesn't exist)
Return false from the callback to abort - the original content is returned unchanged.
sv-utils = what to do to content, sv = where and when to do it.
Each transform wraps: parse -> callback({ast/data, utils}) -> generateCode().
The parser choice is baked into the transform type - you can't accidentally
parse a vite config as svelte because you never call a parser yourself.
Transforms are curried: call with the callback to get a (content: string) => string
function that plugs directly into sv.file().
import{transforms}from'@sveltejs/sv-utils';// use with sv.file() - curried form plugs in directlysv.file(files.viteConfig,transforms.script(({ast,js})=>{js.vite.addPlugin(ast,{code:'kitRoutes()'});}));// standalone usage / testingconstresult=transforms.script(({ast,js})=>{js.imports.addDefault(ast,{as:'foo',from:'foo'});})(fileContent);
Return false from the callback to abort - the original content is returned unchanged.
(({ast(parameter)ast:AST.Root,svelte(parameter)svelte:typeofindex_d_exports$4})=>{svelte(parameter)svelte:typeofindex_d_exports$4.addFragment(alias)index_d_exports$4.addFragment(ast:AST.Root,content:string,options?:{mode?:"append"|"prepend";language?:"ts"|"js";}):voidexportindex_d_exports$4.addFragment(ast(parameter)ast:AST.Root,`<p>Bonjour${options(parameter)options:OptionValues<{who:Question<Record<"who",{readonlyquestion:"À qui cet add-on doit-il dire bonjour ?";readonlytype:"string";}>>;}>&Record<string,unknown>
Add-on options (includes dynamically added options from setup)
.who(property)who:unknown}!</p>`);}));},nextSteps(property)nextSteps?:((workspace:Workspace&{options:OptionValues<{who:Question<Record<"who",{readonlyquestion:"À qui cet add-on doit-il dire bonjour ?";readonlytype:"string";}>>;}>&Record<string,unknown>;})=>string[])|undefined:({options(parameter)options:OptionValues<{who:Question<Record<"who",{readonlyquestion:"À qui cet add-on doit-il dire bonjour ?";readonlytype:"string";}>>;}>&Record<string,unknown>})=>['profitez de cet add-on!']});
Le CLI est divisé en deux paquets avec un frontière claire :
sv = où et quand. Ce paquet gère les paths, la détection de workspace, le suivi de
dépendances, et l’I/O de fichier. Le moteur orchestre l’exécution de l’add-on.
@sveltejs/sv-utils = quoi. Ce paquet fournit des parsers, de l’outillage de
language, et des transformations typées. Tout ici est pur — pas de système de fichiers, pas de
conscience du workspace.
Cette séparation implique que les transformations sont testables sans aucun workspace, et
composables entre add-ons.
Développement
Vous pouvez exécuter votre add-on localement avec le protocole file: :
Ceci vous permet d’itérer rapidement sans publier sur npm.
Le protocole file: fonctionne également pour les add-ons privés ou personnalisés que vous n’avez
pas l’intention de publier — par exemple, pour standardiser la mise en place d’un projet au sein de
votre équipe ou de votre organisation.
Le scipt demo-add compile automatiquement votre add-on avant de l’exécuter.
Tests
Le module sv/testing fournit des utilitaires pour tester votre add-on. createSetupTest est une
usine qui prend vos imports vitest et renvoie une fonction setupTest. Elle crée des vrais projets
SvelteKit à partir de templates, exécute votre add-on, et vous donne accès aux fichiers ainsi
générés.
Returns true if searchString appears as a substring of the result of converting this
object to a String, at one or more positions that are
greater than or equal to position; otherwise, returns false.
searchString
search string
position
If position is undefined, 0 is assumed, so as to search all of the String.
Synchronously reads the entire contents of a file.
path
A path to a file. If a URL is provided, it must use the file: protocol.
If a file descriptor is provided, the underlying file will not be closed automatically.
options
Either the encoding for the result, or an object that contains the encoding and an optional flag.
If a flag is not provided, it defaults to 'r'.
The right-most parameter is considered {to}. Other parameters are considered an array of {from}.
Starting from leftmost {from} parameter, resolves {to} to an absolute path.
If {to} isn't already absolute, {from} arguments are prepended in right to left order,
until an absolute path is found. If after using all {from} paths still no absolute path is found,
the current working directory is used as well. The resulting path is normalized,
and trailing slashes are removed unless the path gets resolved to the root directory.
paths
A sequence of paths or path segments.
{TypeError} if any of the arguments is not a string.
(cwdconstcwd:string,'src/routes/+page.svelte'),'utf8');expectimportexpect(pageconstpage:string).toContainany('Bonjour tout le monde !');});
Votre fichier vitest.config.js doit contenir la configuration globale de sv/testing :
The URL interface is used to parse, construct, normalize, and encode URLs. It works by providing properties which allow you to easily read and modify the components of a URL.
Les add-on communautaires sont compilés avec tsdown en un seul fichier. Tout
est compilé, à l’exception de sv (qui est une dépendance-paire, fournie lors de l’exécution.)
package.json
Votre add-on doit avoir sv comme dépendance-paire et aucune dépendance dans votre
package.json :
{"name":"@my-org/sv","version":"1.0.0","type":"module",// point d'entrée compilé (tsdown génère des .mjs pour les ESM)"exports":{".":{"default":"./dist/index.mjs"}},"publishConfig":{"access":"public"},// ne peut pas avoir de dépendances"dependencies":{},"peerDependencies":{// la version minimum requise pour exécuter cet add-on"sv":"^0.13.0"},// Ajoutez le mot-clé "sv-add" afin que les gens puissent trouver votre add-on avec https://www.npmx.dev/search?q=keyword:sv-add"keywords":["sv-add","svelte","sveltekit"]}
Noms de paquets
Packages must be published under an npm org:
# ✓ BIENnpxsvadd @my-org/svnpxsvadd @my-org/core# ✗ PAS BIENnpxsvaddmy-lib
Si votre paquet est publié avec le scope sv, celui-ci peut être omis. Les exemples suivants sont
tous résolus vers le même paquet :
prepublishOnly exécute automatiquement le build avant de publier.
Prochaines étapes
Vous pouvez de manière optionnelle afficher des indications à afficher lors de l’exécution de votre
add-on :
import{color(alias)constcolor:{addon:(str:ColorInput)=>string;command:(str:ColorInput)=>string;env:(str:ColorInput)=>string;path:(str:ColorInput)=>string;route:(str:ColorInput)=>string;website:(str:ColorInput)=>string;optional:(str:ColorInput)=>string;dim:(str:ColorInput)=>string;success:(str:ColorInput)=>string;warning:(str:ColorInput)=>string;error:(str:ColorInput)=>string;hidden:(str:ColorInput)=>string;}importcolor}from'@sveltejs/sv-utils';exportdefaultdefineAddonany({ // ...
nextSteps(property)nextSteps:({options}:{options:any;})=>string[]:({options(parameter)options:any})=>[`Lancez${color(alias)constcolor:{addon:(str:ColorInput)=>string;command:(str:ColorInput)=>string;env:(str:ColorInput)=>string;path:(str:ColorInput)=>string;route:(str:ColorInput)=>string;website:(str:ColorInput)=>string;optional:(str:ColorInput)=>string;dim:(str:ColorInput)=>string;success:(str:ColorInput)=>string;warning:(str:ColorInput)=>string;error:(str:ColorInput)=>string;hidden:(str:ColorInput)=>string;}importcolor.command(property)command:(str:ColorInput)=>string('npm run dev')}pour commencer le développement`,`Retrouvez la documentation sur https://...`]});
Compatibilité de version
Votre add-on doit préciser la version minimale de sv requises dans vos peerDependencies. Si la
version de sv d’un utilisateur ou d’un utilisatrice a une majeure différente de celle pour
laquelle votre add-on a été conçu, ils et elles verront un avertissement de compatibilité.