{args?.text}
+{/snippet} + + +
+ This story is static and isn't defined with a snippet. It will ignore any args
changes
+ because they are not passed in.
+
{args?.text}
+ {/snippet} +{args?.text}
+{/snippet} + + +
{args.id}
\\n{context.name}
\\n You clicked: {count}{args.id}
\\n{context.name}
\\n You clicked: {count}{args.id}
\\n{context.name}
\\n You clicked: {count}{args.id}
\\n{context.name}
\\n You clicked: {count}{args.id}
\\n{context.name}
\\n You clicked: {count}{args.id}
\\n{context.name}
\\n You clicked: {count}Warning: no story rendered. improve this message
+ {/if} +{/if} diff --git a/src/runtime/StoryRenderer.svelte b/src/runtime/StoryRenderer.svelte new file mode 100644 index 00000000..0bb0a0fb --- /dev/null +++ b/src/runtime/StoryRenderer.svelte @@ -0,0 +1,35 @@ + + +.
+ */
+ get name() {
+ const errorName = this.constructor.name;
+
+ return `${this.fullErrorCode} (${errorName})`;
+ }
+
+ /**
+ * Generates the error message along with additional documentation link (if applicable).
+ */
+ get message() {
+ let page: string | undefined;
+
+ if (this.documentation === true) {
+ page = `https://github.com/storybookjs/addon-svelte-csf/blob/v${StorybookSvelteCSFError.packageVersion}/ERRORS.md#${this.fullErrorCode}`;
+ } else if (typeof this.documentation === 'string') {
+ page = this.documentation;
+ } else if (Array.isArray(this.documentation)) {
+ page = `\n${this.documentation.map((doc) => `\t- ${doc}`).join('\n')}`;
+ }
+
+ return `${this.template()}${page != null ? `\n\nMore info: ${page}\n` : ''}`;
+ }
+
+ /**
+ * `*.stories.svelte` file path where the error has occurred.
+ */
+ readonly filename?: string;
+
+ /**
+ * Name of the ` ` component which caused the error.
+ */
+ readonly component?: Component;
+
+ constructor({
+ filename,
+ component: component,
+ }: {
+ filename?: StorybookSvelteCSFError['filename'];
+ component?: StorybookSvelteCSFError['component'];
+ }) {
+ super();
+
+ this.filename = filename;
+ this.component = component;
+ }
+
+ // WARN: I had to duplicate logic. We already have functions for it.
+ // But we can't import it, because it would create a cyclic-dependency.
+ protected get storyNameFromAttribute() {
+ if (this.component) {
+ for (const attribute of this.component?.attributes) {
+ if (
+ attribute.type === 'Attribute' &&
+ attribute.name === 'name' &&
+ attribute.value !== true
+ ) {
+ if (attribute.value[0].type === 'Text') {
+ return attribute.value[0].data;
+ }
+
+ if (
+ attribute.value[0].type === 'ExpressionTag' &&
+ attribute.value[0].expression.type === 'Literal' &&
+ typeof attribute.value[0].expression.value === 'string'
+ ) {
+ return attribute.value[0].expression.value;
+ }
+ }
+ }
+ }
+
+ return '';
+ }
+
+ public get filepathURL() {
+ if (this.filename) {
+ return url.pathToFileURL(this.filename);
+ } else {
+ return '';
+ }
+ }
+
+ public get quickStoryRawCodeIdentifier() {
+ return ` `;
+ }
+}
diff --git a/src/utils/error/parser/analyse/define-meta.ts b/src/utils/error/parser/analyse/define-meta.ts
new file mode 100644
index 00000000..f9a15077
--- /dev/null
+++ b/src/utils/error/parser/analyse/define-meta.ts
@@ -0,0 +1,164 @@
+import { StorybookSvelteCSFError } from '#utils/error';
+import dedent from 'dedent';
+import type { ArrayExpression, Identifier, Property, VariableDeclarator } from 'estree';
+
+export class InvalidComponentValueError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserAnalyseDefineMeta;
+ readonly code = 1;
+ public documentation = true;
+
+ public componentProperty: Property;
+
+ constructor({
+ filename,
+ componentProperty,
+ }: {
+ filename: StorybookSvelteCSFError['filename'];
+ componentProperty: InvalidComponentValueError['componentProperty'];
+ }) {
+ super({ filename });
+ this.componentProperty = componentProperty;
+ }
+
+ template(): string {
+ return dedent`
+ The 'component' property of 'defineMeta' must reference an imported Svelte component.
+ The current type of the property is '${this.componentProperty.value.type}'.
+
+ The issue occurred in Stories file: ${this.filepathURL}
+ `;
+ }
+}
+
+export class NoDestructuredDefineMetaCallError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserAnalyseDefineMeta;
+ readonly code = 2;
+ public documentation = true;
+
+ public defineMetaVariableDeclarator: VariableDeclarator;
+
+ constructor({
+ filename,
+ defineMetaVariableDeclarator,
+ }: {
+ filename: StorybookSvelteCSFError['filename'];
+ defineMetaVariableDeclarator: NoDestructuredDefineMetaCallError['defineMetaVariableDeclarator'];
+ }) {
+ super({ filename });
+ this.defineMetaVariableDeclarator = defineMetaVariableDeclarator;
+ }
+
+ template(): string {
+ return dedent`
+ The return value of the 'defineMeta' call was not destructured to { Story }.
+ The issue occurred in Stories file: ${this.filepathURL}
+
+ The current pattern type is: "${this.defineMetaVariableDeclarator.id.type}", and expected is "ObjectPattern".
+ `;
+ }
+}
+
+export class NoMetaIdentifierFoundError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserAnalyseDefineMeta;
+ readonly code = 3;
+ public documentation = true;
+
+ constructor(filename: StorybookSvelteCSFError['filename']) {
+ super({ filename });
+ }
+
+ template(): string {
+ return dedent`
+ Could not find 'meta' identifier in the compiled output of stories file: ${this.filepathURL}
+ This is most likely a bug in @storybook/addon-svelte-csf. Please open an issue on GitHub.
+ `;
+ }
+}
+
+export class NoStringLiteralError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserAnalyseDefineMeta;
+ readonly code = 4;
+ public documentation = true;
+
+ readonly property: Property;
+
+ constructor({
+ filename,
+ property,
+ }: {
+ filename: StorybookSvelteCSFError['filename'];
+ property: NoStringLiteralError['property'];
+ }) {
+ super({ filename });
+ this.property = property;
+ }
+
+ template(): string {
+ return dedent`
+ The '${(this.property.key as Identifier).name}' passed to 'defineMeta()' must be a static string literal.
+ But it is of type '${this.property.value.type}'.
+
+ This issue occurred in stories file: ${this.filepathURL}
+ `;
+ }
+}
+
+export class NoArrayExpressionError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserAnalyseDefineMeta;
+ readonly code = 5;
+ public documentation = true;
+
+ readonly property: Property;
+
+ constructor({
+ filename,
+ property,
+ }: {
+ filename: StorybookSvelteCSFError['filename'];
+ property: NoArrayExpressionError['property'];
+ }) {
+ super({ filename });
+ this.property = property;
+ }
+
+ template(): string {
+ return dedent`
+ The '${(this.property.key as Identifier).name}' passed to 'defineMeta()' must be a static array.
+ But it is of type '${this.property.value.type}'.
+
+ This issue occurred in stories file: ${this.filepathURL}
+ `;
+ }
+}
+
+export class ArrayElementNotStringError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserAnalyseDefineMeta;
+ readonly code = 6;
+ public documentation = true;
+
+ readonly property: Property;
+ readonly element: ArrayExpression['elements'][number];
+
+ constructor({
+ filename,
+ property,
+ element,
+ }: {
+ filename: StorybookSvelteCSFError['filename'];
+ property: ArrayElementNotStringError['property'];
+ element: ArrayElementNotStringError['element'];
+ }) {
+ super({ filename });
+ this.element = element;
+ this.property = property;
+ }
+
+ template(): string {
+ return dedent`
+ All entries in the '${(this.property.key as Identifier).name}' property passed to 'defineMeta()' must be static strings.
+ One of the elements is not a string but is instead of type '${this.element?.type}'.
+
+ This issue occurred in stories file: ${this.filepathURL}
+ `;
+ }
+}
diff --git a/src/utils/error/parser/analyse/story.ts b/src/utils/error/parser/analyse/story.ts
new file mode 100644
index 00000000..b05e054f
--- /dev/null
+++ b/src/utils/error/parser/analyse/story.ts
@@ -0,0 +1,214 @@
+import dedent from 'dedent';
+import type { Attribute } from 'svelte/compiler';
+
+import { StorybookSvelteCSFError } from '#utils/error';
+import type { ArrayExpression, Literal } from 'estree';
+import type { getStoryIdentifiers } from '#parser/analyse/story/attributes/identifiers';
+
+export class AttributeNotStringError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserAnalyseStory;
+ readonly code = 1;
+ public documentation = true;
+
+ public attribute: Attribute;
+
+ constructor({
+ filename,
+ attribute,
+ component,
+ }: {
+ filename: StorybookSvelteCSFError['filename'];
+ component: NonNullable;
+ attribute: AttributeNotStringError['attribute'];
+ }) {
+ super({ component, filename });
+ this.attribute = attribute;
+ }
+
+ template(): string {
+ return dedent`
+ In the stories file: ${this.filepathURL}
+
+ A '${this.quickStoryRawCodeIdentifier}' has a prop '${this.attribute.name}' whose value must be a static literal string.
+ `;
+ }
+}
+
+export class AttributeNotArrayError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserAnalyseStory;
+ readonly code = 2;
+ public documentation = true;
+
+ public attribute: Attribute;
+
+ constructor({
+ filename,
+ attribute,
+ component,
+ }: {
+ filename: StorybookSvelteCSFError['filename'];
+ component: NonNullable;
+ attribute: AttributeNotStringError['attribute'];
+ }) {
+ super({ component, filename });
+ this.attribute = attribute;
+ }
+
+ get valueType() {
+ const { value } = this.attribute;
+ if (value === true) {
+ return true;
+ }
+ if (value[0].type === 'Text') {
+ return value[0].data;
+ }
+
+ return (value[0].expression as Literal).value;
+ }
+
+ template(): string {
+ return dedent`
+ In the stories file: ${this.filepathURL}
+
+ A '${this.quickStoryRawCodeIdentifier}' has a prop'${this.attribute.name}' whose value was expected to be a static array.
+ Instead the value type is '${this.valueType}'.
+ `;
+ }
+}
+
+export class AttributeNotArrayOfStringsError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserAnalyseStory;
+ readonly code = 3;
+ public documentation = true;
+
+ public attribute: Attribute;
+ public element: ArrayExpression['elements'][number];
+
+ constructor({
+ filename,
+ attribute,
+ component,
+ element,
+ }: {
+ filename: StorybookSvelteCSFError['filename'];
+ component: NonNullable;
+ attribute: AttributeNotArrayOfStringsError['attribute'];
+ element: AttributeNotArrayOfStringsError['element'];
+ }) {
+ super({ component, filename });
+ this.attribute = attribute;
+ this.element = element;
+ }
+
+ get valueType() {
+ const { value } = this.attribute;
+ if (value === true) {
+ return true;
+ }
+ if (value[0].type === 'Text') {
+ return value[0].data;
+ }
+
+ return (value[0].expression as Literal).value;
+ }
+
+ template(): string {
+ return dedent`
+ In the stories file: ${this.filepathURL}
+
+ A '${this.quickStoryRawCodeIdentifier}' has attribute '${this.attribute.name}' whose value was expected to be an array expression.
+ All elements in the array must be static literal strings only, but one of the elements is of type '${this.valueType}'.
+ `;
+ }
+}
+
+export class NoStoryIdentifierError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserAnalyseStory;
+ readonly code = 4;
+ public documentation = true;
+
+ constructor({
+ filename,
+ component,
+ }: {
+ filename: StorybookSvelteCSFError['filename'];
+ component: NonNullable;
+ }) {
+ super({ component, filename });
+ }
+
+ template(): string {
+ return dedent`
+ Missing 'name' or 'exportName' attribute (prop) in a ' ' definition in the stories file: '${this.filepathURL}'.
+ All stories must either have a 'name' or an 'exportName' prop, or both.
+ `;
+ }
+}
+
+export class InvalidStoryExportNameError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserAnalyseStory;
+ readonly code = 5;
+ public documentation = true;
+
+ public value: string;
+
+ constructor({
+ filename,
+ component,
+ value,
+ }: {
+ filename: StorybookSvelteCSFError['filename'];
+ component: NonNullable;
+ value: InvalidStoryExportNameError['value'];
+ }) {
+ super({ component, filename });
+ this.value = value;
+ }
+
+ template(): string {
+ return dedent`
+ Invalid attribute 'exportName' value '${this.value}' found in ' ' component inside stories file: ${this.filepathURL}
+
+ 'exportName' value must be a valid JavaScript variable name.
+ It must start with a letter, $ or _, followed by letters, numbers, $ or _.
+ Reserved words like 'default' are also not allowed (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#reserved_words)
+ `;
+ }
+}
+
+export class DuplicateStoryIdentifiersError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserAnalyseStory;
+ readonly code = 6;
+ public documentation = true;
+
+ public identifiers: ReturnType;
+ public duplicateIdentifiers: NonNullable>;
+
+ constructor({
+ filename,
+ identifiers,
+ duplicateIdentifiers,
+ }: {
+ filename: StorybookSvelteCSFError['filename'];
+ identifiers: DuplicateStoryIdentifiersError['identifiers'];
+ duplicateIdentifiers: DuplicateStoryIdentifiersError['duplicateIdentifiers'];
+ }) {
+ super({ filename });
+ this.identifiers = identifiers;
+ this.duplicateIdentifiers = duplicateIdentifiers;
+ }
+
+ template(): string {
+ return dedent`
+ Duplicate exportNames found between two ' ' definitions in stories file: ${this.filepathURL}
+
+ First instance:
+ Second instance:
+
+ This can happen when 'exportName' is implicitly derived by 'name'.
+ Complex names will be simplified to a PascalCased, valid JavaScript variable name,
+ eg. 'Some story name!!' will be converted to 'SomeStoryName'.
+ You can fix this collision by providing a unique 'exportName' prop with .
+ `;
+ }
+}
diff --git a/src/utils/error/parser/extract/compiled.ts b/src/utils/error/parser/extract/compiled.ts
new file mode 100644
index 00000000..5c63054d
--- /dev/null
+++ b/src/utils/error/parser/extract/compiled.ts
@@ -0,0 +1,109 @@
+import dedent from 'dedent';
+
+import { StorybookSvelteCSFError } from '#utils/error';
+import type { extractStoriesNodesFromExportDefaultFn } from '#parser/extract/compiled/stories';
+
+export class MissingImportedDefineMetaError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserExtractCompiled;
+ readonly code = 1;
+ readonly documentation = true;
+
+ constructor(filename?: StorybookSvelteCSFError['filename']) {
+ super({ filename });
+ }
+
+ template() {
+ return dedent`
+ Could not find the import statement of 'defineMeta' from the "${StorybookSvelteCSFError.packageName}" in the compiled output of: ${this.filepathURL}
+ `;
+ }
+}
+
+export class MissingDefineMetaVariableDeclarationError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserExtractCompiled;
+ readonly code = 2;
+ readonly documentation = true;
+
+ constructor(filename?: StorybookSvelteCSFError['filename']) {
+ super({ filename });
+ }
+
+ template() {
+ return dedent`
+ Could not find variable declaration from 'defineMeta' call in the compiled output of the stories file: ${this.filepathURL}
+ `;
+ }
+}
+
+export class NoExportDefaultError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserExtractCompiled;
+ readonly code = 3;
+ readonly documentation = true;
+
+ constructor(filename?: StorybookSvelteCSFError['filename']) {
+ super({ filename });
+ }
+
+ template() {
+ return dedent`
+ Could not find 'export default' in the compiled output of the stories file: ${this.filepathURL}
+ `;
+ }
+}
+
+export class NoStoryIdentifierFoundError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserExtractCompiled;
+ readonly code = 4;
+ readonly documentation = true;
+
+ constructor(filename?: StorybookSvelteCSFError['filename']) {
+ super({ filename });
+ }
+
+ template() {
+ return dedent`
+ Could not find a 'Story' identifier in the compiled output of the stories file: ${this.filepathURL}
+ `;
+ }
+}
+
+export class NoStoriesFunctionDeclarationError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserExtractCompiled;
+ readonly code = 5;
+ readonly documentation = true;
+
+ constructor(filename?: StorybookSvelteCSFError['filename']) {
+ super({ filename });
+ }
+
+ template() {
+ return dedent`
+ Could not find the stories component '*.stories.svelte' function declaration compiled output of the stories file: ${this.filepathURL}
+ `;
+ }
+}
+
+export class NoCompiledStoryPropsObjectExpression extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserExtractCompiled;
+ readonly code = 6;
+ readonly documentation = true;
+
+ public node: Awaited>[number];
+
+ constructor({
+ filename,
+ node,
+ }: {
+ filename: StorybookSvelteCSFError['filename'];
+ node: NoCompiledStoryPropsObjectExpression['node'];
+ }) {
+ super({ filename });
+ this.node = node;
+ }
+
+ template() {
+ return dedent`
+ Failed to extract compiled Story component props as object expression in the compiled output of stories file: ${this.filepathURL}
+ `;
+ }
+}
diff --git a/src/utils/error/parser/extract/svelte.ts b/src/utils/error/parser/extract/svelte.ts
new file mode 100644
index 00000000..330f9873
--- /dev/null
+++ b/src/utils/error/parser/extract/svelte.ts
@@ -0,0 +1,214 @@
+import dedent from 'dedent';
+import type { Attribute } from 'svelte/compiler';
+
+import type { SvelteASTNodes } from '#parser/extract/svelte/nodes';
+import { StorybookSvelteCSFError } from '#utils/error';
+
+const BASE_INITIAL_SNIPPET = dedent`
+
+`;
+
+export class MissingModuleTagError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserExtractSvelte;
+ readonly code = 1;
+ public documentation = true;
+
+ constructor(filename?: string) {
+ super({ filename });
+ }
+
+ template() {
+ return dedent`
+ The file '${this.filepathURL}'
+ does not have a module context ().
+
+ defineMeta(...) should be called inside a module script tag, like so:
+
+ ${BASE_INITIAL_SNIPPET}
+ `;
+ }
+}
+
+export class DefaultOrNamespaceImportUsedError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserExtractSvelte;
+ readonly code = 2;
+ public documentation = true;
+
+ constructor(filename?: StorybookSvelteCSFError['filename']) {
+ super({ filename });
+ }
+
+ template() {
+ return dedent`
+ The file '${this.filepathURL}'
+ is using the default/namespace import from "${StorybookSvelteCSFError.packageName}".
+ Only named imports are supported.
+ `;
+ }
+}
+
+export class MissingDefineMetaImportError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserExtractSvelte;
+ readonly code = 3;
+ public documentation = true;
+
+ constructor(filename?: StorybookSvelteCSFError['filename']) {
+ super({ filename });
+ }
+
+ template() {
+ return dedent`
+ The file '${this.filepathURL}'
+ does not import defineMeta from "${StorybookSvelteCSFError.packageName}" inside the module context.
+
+ Make sure to import defineMeta from the package and use it inside the module context like so:
+
+ ${BASE_INITIAL_SNIPPET}
+ `;
+ }
+}
+
+export class MissingDefineMetaVariableDeclarationError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserExtractSvelte;
+ readonly code = 4;
+ public documentation = true;
+
+ constructor(filename?: StorybookSvelteCSFError['filename']) {
+ super({ filename });
+ }
+
+ template() {
+ return dedent`
+ The file '${this.filepathURL}'
+ does not store the result of calling defineMeta(). While defineMeta() might have been called,
+ it's return value needs to be stored and destructured for the parsing to succeed, eg.:
+
+ ${BASE_INITIAL_SNIPPET}
+ `;
+ }
+}
+
+export class NoStoryComponentDestructuredError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserExtractSvelte;
+ readonly code = 5;
+ public documentation = true;
+
+ public defineMetaImport: SvelteASTNodes['defineMetaImport'];
+
+ constructor({
+ filename,
+ defineMetaImport,
+ }: {
+ filename?: StorybookSvelteCSFError['filename'];
+ defineMetaImport: NoStoryComponentDestructuredError['defineMetaImport'];
+ }) {
+ super({ filename });
+ this.defineMetaImport = defineMetaImport;
+ }
+
+ template() {
+ return dedent`
+ The file '${this.filepathURL}'
+ does not destructure the Story component from the '${this.defineMetaImport.local.name}({ ... })' function call.
+ eg.:
+
+ ${BASE_INITIAL_SNIPPET}
+ `;
+ }
+}
+
+export class GetDefineMetaFirstArgumentError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserExtractSvelte;
+ readonly code = 6;
+ public documentation = true;
+
+ public defineMetaVariableDeclaration: SvelteASTNodes['defineMetaVariableDeclaration'];
+
+ constructor({
+ filename,
+ defineMetaVariableDeclaration,
+ }: {
+ filename?: StorybookSvelteCSFError['filename'];
+ defineMetaVariableDeclaration: SvelteASTNodes['defineMetaVariableDeclaration'];
+ }) {
+ super({ filename });
+ this.defineMetaVariableDeclaration = defineMetaVariableDeclaration;
+ }
+
+ template() {
+ return dedent`
+ The file '${this.filepathURL}'
+ passes an invalid first argument to the 'defineMeta' call.
+
+ The first argument must be an object expression with the meta properties set.
+ `;
+ }
+}
+
+export class InvalidStoryChildrenAttributeError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserExtractSvelte;
+ readonly code = 7;
+ public documentation = true;
+
+ public childrenAttribute: Attribute;
+
+ constructor({
+ filename,
+ component,
+ childrenAttribute,
+ }: {
+ filename?: StorybookSvelteCSFError['filename'];
+ component: NonNullable;
+ childrenAttribute: InvalidStoryChildrenAttributeError['childrenAttribute'];
+ }) {
+ super({ filename, component });
+ this.childrenAttribute = childrenAttribute;
+ }
+
+ template() {
+ return dedent`
+ Component '${this.quickStoryRawCodeIdentifier}' in the stories file '${this.filepathURL}'
+ has an invalid 'children'-prop.
+
+ When set, the 'children'-prop must be an expression with reference to a root-level snippet.
+
+ Eg.:
+
+ {#snippet template()}
+ ...
+ {/snippet}
+
+
+ `;
+ }
+}
+
+export class InvalidSetTemplateFirstArgumentError extends StorybookSvelteCSFError {
+ readonly category = StorybookSvelteCSFError.CATEGORY.parserExtractSvelte;
+ readonly code = 8;
+ public documentation = true;
+
+ public setTemplateCall: SvelteASTNodes['setTemplateCall'];
+
+ constructor({
+ filename,
+ setTemplateCall,
+ }: {
+ filename?: StorybookSvelteCSFError['filename'];
+ setTemplateCall: InvalidSetTemplateFirstArgumentError['setTemplateCall'];
+ }) {
+ super({ filename });
+ this.setTemplateCall = setTemplateCall;
+ }
+
+ template() {
+ return dedent`
+ The file '${this.filepathURL}'
+ has an invalid 'setTemplate' call. The first argument must reference a root-level snippet in the file.
+ `;
+ }
+}
diff --git a/src/utils/identifier-utils.test.ts b/src/utils/identifier-utils.test.ts
new file mode 100644
index 00000000..a2594c76
--- /dev/null
+++ b/src/utils/identifier-utils.test.ts
@@ -0,0 +1,32 @@
+import { it, expect } from 'vitest';
+import {
+ storyIdToExportName,
+ exportNameToStoryId,
+ storyNameToId,
+ storyNameToExportName,
+} from './identifier-utils';
+
+it('storyIdToExportName', () => {
+ expect(storyIdToExportName('single')).toBe('Single');
+ expect(storyIdToExportName('multiple-parts')).toBe('MultipleParts');
+});
+it('exportNameToStoryId', () => {
+ expect(exportNameToStoryId('Single')).toBe('single');
+ expect(exportNameToStoryId('MultipleParts')).toBe('multiple-parts');
+});
+it('storyNameToId', () => {
+ expect(storyNameToId('simple')).toBe('simple');
+ expect(storyNameToId('PascalCase')).toBe('pascal-case');
+ expect(storyNameToId('Start Case')).toBe('start-case');
+ expect(storyNameToId('With 2 illegal !! characters, a PascalCase and an ?')).toBe(
+ 'with-2-illegal-characters-a-pascal-case-and-an'
+ );
+});
+it('storyNameToExportName', () => {
+ expect(storyNameToExportName('simple')).toBe('Simple');
+ expect(storyNameToExportName('PascalCase')).toBe('PascalCase');
+ expect(storyNameToExportName('Start Case')).toBe('StartCase');
+ expect(storyNameToExportName('With 2 illegal !! characters, a PascalCase and an ?')).toBe(
+ 'With2IllegalCharactersAPascalCaseAndAn'
+ );
+});
diff --git a/src/utils/identifier-utils.ts b/src/utils/identifier-utils.ts
new file mode 100644
index 00000000..bcf299aa
--- /dev/null
+++ b/src/utils/identifier-utils.ts
@@ -0,0 +1,56 @@
+import { sanitize } from '@storybook/csf';
+
+/**
+ * @example storyIdToExportName('some-story') => 'SomeStory'
+ */
+export const storyIdToExportName = (storyId: string) =>
+ storyId
+ .split('-')
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
+ .join('');
+
+/**
+ * @example exportNameToStoryId('SomeStory') => 'some-story'
+ */
+export const exportNameToStoryId = (exportName: string) =>
+ exportName.replace(/([a-z0β9])([A-Z])/g, '$1-$2').toLowerCase();
+
+/**
+ * @example storyNameToId('Some Long Story Name!') => 'some-long-story-name'
+ */
+export const storyNameToId = (name: string) =>
+ // add a space before all caps and use utility from @storybook/csf to sanitize the resulting string
+ sanitize(name.replace(/([A-Z])/g, ' $1').trim());
+
+/**
+ * @example storyNameToExportName('Some Long Story Name!') => 'SomeLongStoryName'
+ */
+export const storyNameToExportName = (name: string) => storyIdToExportName(storyNameToId(name));
+
+/**
+ * Check if a string is a valid JavaScript variable name
+ * @example isValidVariableName('SomeStory') => true
+ * @example isValidVariableName('Some_Story') => true
+ * @example isValidVariableName('Some Story') => false
+ * @example isValidVariableName('Some-Story') => false
+ * @example isValidVariableName('default') => false
+ *
+ * @see https://github.com/shinnn/is-var-name
+ */
+export const isValidVariableName = (str: string) => {
+ if (typeof str !== 'string') {
+ return false;
+ }
+
+ if (str.trim() !== str) {
+ return false;
+ }
+
+ try {
+ new Function(str, 'var ' + str);
+ } catch (_) {
+ return false;
+ }
+
+ return true;
+};
diff --git a/stories/ArgsTableView.svelte b/stories/ArgsTableView.svelte
deleted file mode 100644
index c81fb057..00000000
--- a/stories/ArgsTableView.svelte
+++ /dev/null
@@ -1,67 +0,0 @@
-
-
-{JSON.stringify(preview, null, ' ')}
-
-
-
-
- /** Close description */ dispatch('close')}/>
-
-
-
-
-
-
\ No newline at end of file
diff --git a/stories/Button.svelte b/stories/Button.svelte
deleted file mode 100644
index c628b898..00000000
--- a/stories/Button.svelte
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-
diff --git a/stories/Counter.svelte b/stories/Counter.svelte
deleted file mode 100644
index ecaea220..00000000
--- a/stories/Counter.svelte
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
- Counter
- You clicked {count} times
-
-
-
diff --git a/stories/addon-actions.stories.svelte b/stories/addon-actions.stories.svelte
deleted file mode 100644
index 5fbffcc7..00000000
--- a/stories/addon-actions.stories.svelte
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/stories/argstable.stories.svelte b/stories/argstable.stories.svelte
deleted file mode 100644
index 3af8cdf4..00000000
--- a/stories/argstable.stories.svelte
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/stories/button.stories.svelte b/stories/button.stories.svelte
deleted file mode 100644
index 7f529fa5..00000000
--- a/stories/button.stories.svelte
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/stories/context.stories.svelte b/stories/context.stories.svelte
deleted file mode 100644
index 9380e813..00000000
--- a/stories/context.stories.svelte
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
- StoryContext.name = {context.name}
- StoryContext.id = {context.id}
-
diff --git a/stories/interaction.stories.svelte b/stories/interaction.stories.svelte
deleted file mode 100644
index 8a0921d8..00000000
--- a/stories/interaction.stories.svelte
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
-
-
-
-
- {
-
- const { canvasElement } = storyContext;
- const canvas = within(canvasElement);
- const p = canvas.getByTestId('count');
- expect(p.textContent).toEqual('0');
- i++;
- await tick();
- expect(p.textContent).toEqual('1');
- }}
->
- {i}
-
diff --git a/stories/metaexport.stories.svelte b/stories/metaexport.stories.svelte
deleted file mode 100644
index 4780ab8c..00000000
--- a/stories/metaexport.stories.svelte
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/stories/metaexport_override_descr.stories.svelte b/stories/metaexport_override_descr.stories.svelte
deleted file mode 100644
index 2ad110ce..00000000
--- a/stories/metaexport_override_descr.stories.svelte
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/stories/metaexport_without_descr.stories.svelte b/stories/metaexport_without_descr.stories.svelte
deleted file mode 100644
index cc7567fa..00000000
--- a/stories/metaexport_without_descr.stories.svelte
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/stories/templates.stories.svelte b/stories/templates.stories.svelte
deleted file mode 100644
index 0981172a..00000000
--- a/stories/templates.stories.svelte
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
- Template 1 {text}
-
-
-
- Template 2 {text}
-
-
-
-
diff --git a/tests/__compiled__/pre-transform/Example.stories.dev.js b/tests/__compiled__/pre-transform/Example.stories.dev.js
new file mode 100644
index 00000000..aee3b0fa
--- /dev/null
+++ b/tests/__compiled__/pre-transform/Example.stories.dev.js
@@ -0,0 +1,153 @@
+import 'svelte/internal/disclose-version';
+
+$.mark_module_start();
+Example_stories.filename = 'stories/Example.stories.svelte';
+
+import * as $ from 'svelte/internal/client';
+
+var Example_default = $.add_locations(
+ $.template(`
`, 1),
+ Example_stories.filename,
+ [
+ [45, 4],
+ [46, 4],
+ [47, 24],
+ ]
+);
+var Example_default_1 = $.add_locations($.template(`Label`, 1), Example_stories.filename, []);
+var root = $.add_locations($.template(` `, 1), Example_stories.filename, []);
+
+import { action } from '@storybook/addon-actions';
+import { defineMeta, setTemplate } from '@storybook/addon-svelte-csf';
+import Example from './Example.svelte';
+
+/**
+ * Description set explicitly in the comment above `defineMeta`.
+ *
+ * Multiline supported. And also Markdown syntax:
+ *
+ * * **Bold**,
+ * * _Italic_,
+ * * `Code`.
+ */
+const { Story } = defineMeta({
+ title: 'Example',
+ component: Example,
+ tags: ['autodocs'],
+ args: {
+ onclick: action('onclick'),
+ onmouseenter: action('onmouseenter'),
+ onmouseleave: action('onmouseleave'),
+ },
+});
+
+function Example_stories($$anchor, $$props) {
+ if (new.target === Example_stories)
+ throw new Error(
+ 'Instantiating a component with `new` is no longer valid in Svelte 5. See https://svelte-5-preview.vercel.app/docs/breaking-changes#components-are-no-longer-classes for more information'
+ );
+ $.push($$props, true, Example_stories);
+
+ var render = $.wrap_snippet(($$anchor, args = $.noop, context = $.noop) => {
+ var fragment = $.comment();
+ var node = $.first_child(fragment);
+
+ $.validate_component(Example)(
+ node,
+ $.spread_props(args, {
+ onclick: handleClick,
+ children: $.wrap_snippet(($$anchor, $$slotProps) => {
+ var fragment_1 = Example_default();
+ var p = $.first_child(fragment_1);
+ var text = $.child(p);
+ var p_1 = $.sibling($.sibling(p, true));
+ var text_1 = $.child(p_1);
+ var text_2 = $.sibling(p_1, true);
+ var br = $.sibling(text_2);
+
+ $.template_effect(() => {
+ $.set_text(text, args()?.id);
+ $.set_text(text_1, context().name);
+ $.set_text(text_2, ` You clicked: ${$.stringify($.get(count))}`);
+ });
+
+ $.append($$anchor, fragment_1);
+ }),
+ $$slots: { default: true },
+ })
+ );
+
+ $.append($$anchor, fragment);
+ });
+
+ $.validate_prop_bindings($$props, [], [], Example_stories);
+
+ let count = $.source(0);
+
+ function handleClick() {
+ $.set(count, $.get(count) + 1);
+ }
+
+ setTemplate(render);
+
+ var fragment_2 = root();
+ var node_1 = $.first_child(fragment_2);
+
+ $.validate_component(Story)(node_1, { name: 'Default' });
+
+ var node_2 = $.sibling($.sibling(node_1, true));
+
+ $.validate_component(Story)(node_2, { name: 'Rounded', args: { rounded: true } });
+
+ var node_3 = $.sibling($.sibling(node_2, true));
+
+ $.validate_component(Story)(node_3, { name: 'Square', args: { rounded: false } });
+
+ var node_4 = $.sibling($.sibling(node_3, true));
+
+ $.validate_component(Story)(node_4, {
+ name: 'Without template',
+ children: $.wrap_snippet(($$anchor, $$slotProps) => {
+ var fragment_3 = $.comment();
+ var node_5 = $.first_child(fragment_3);
+
+ $.validate_component(Example)(node_5, {
+ children: $.wrap_snippet(($$anchor, $$slotProps) => {
+ var fragment_4 = Example_default_1();
+
+ $.append($$anchor, fragment_4);
+ }),
+ $$slots: { default: true },
+ });
+
+ $.append($$anchor, fragment_3);
+ }),
+ $$slots: { default: true },
+ });
+
+ $.append($$anchor, fragment_2);
+ return $.pop({ ...$.legacy_api() });
+}
+
+if (import.meta.hot) {
+ const s = $.source(Example_stories);
+ const filename = Example_stories.filename;
+
+ Example_stories = $.hmr(s);
+ Example_stories.filename = filename;
+
+ if (import.meta.hot.acceptExports) {
+ import.meta.hot.acceptExports(['default'], (module) => {
+ $.set(s, module.default);
+ });
+ } else {
+ import.meta.hot.acceptExports(['default'], (module) => {
+ $.set(s, module.default);
+ });
+ }
+}
+
+export default Example_stories;
+
+$.mark_module_end(Example_stories);
+Example_stories.__docgen = { keywords: [], data: [], name: 'Example.stories.svelte' };
diff --git a/tests/stories/Actions.stories.svelte b/tests/stories/Actions.stories.svelte
new file mode 100644
index 00000000..a4907cef
--- /dev/null
+++ b/tests/stories/Actions.stories.svelte
@@ -0,0 +1,34 @@
+
+
+ {
+ const { args, canvasElement } = context;
+ const canvas = within(canvasElement);
+ const button = await canvas.findByRole('button');
+
+ expect(button).toBeInTheDocument();
+ await userEvent.click(button);
+ expect(args.onclick).toHaveBeenCalled();
+ }}
+>
+ {#snippet children(args)}
+
+ {/snippet}
+
diff --git a/tests/stories/BorderDecorator.svelte b/tests/stories/BorderDecorator.svelte
new file mode 100644
index 00000000..27e2f37c
--- /dev/null
+++ b/tests/stories/BorderDecorator.svelte
@@ -0,0 +1,14 @@
+
+
+
+ {@render children()}
+
+
+
diff --git a/tests/stories/Comparison.stories.svelte b/tests/stories/Comparison.stories.svelte
new file mode 100644
index 00000000..56cb99f5
--- /dev/null
+++ b/tests/stories/Comparison.stories.svelte
@@ -0,0 +1,39 @@
+
+
+
diff --git a/tests/stories/Comparison.stories.ts b/tests/stories/Comparison.stories.ts
new file mode 100644
index 00000000..645bccab
--- /dev/null
+++ b/tests/stories/Comparison.stories.ts
@@ -0,0 +1,36 @@
+import type { Meta, StoryObj } from '@storybook/svelte';
+
+import Comparison from './Comparison.svelte';
+
+/**
+ * A quick overview on how to write a stories file using **Regular CSF** format.
+ *
+ * ```js
+ * import Comparison from "./Comparison.svelte";
+ *
+ * const meta = {
+ * title: "Comparison/Regular CSF",
+ * component: Comparison,
+ * };
+ *
+ * export const Default = {
+ * args: { csf: 'regular' }
+ * };
+ * ```
+ */
+const meta = {
+ title: 'Comparison/Regular CSF',
+ component: Comparison,
+ argTypes: {
+ csf: { table: { disable: true } },
+ },
+ tags: ['autodocs', '!dev'],
+} satisfies Meta;
+
+export default meta;
+
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: { csf: 'regular' },
+};
diff --git a/tests/stories/Comparison.svelte b/tests/stories/Comparison.svelte
new file mode 100644
index 00000000..08171b2f
--- /dev/null
+++ b/tests/stories/Comparison.svelte
@@ -0,0 +1,8 @@
+
+
+
+ Using {csf}.
+
diff --git a/tests/stories/Controls.stories.svelte b/tests/stories/Controls.stories.svelte
new file mode 100644
index 00000000..42629b04
--- /dev/null
+++ b/tests/stories/Controls.stories.svelte
@@ -0,0 +1,37 @@
+
+
+
diff --git a/tests/stories/Controls.svelte b/tests/stories/Controls.svelte
new file mode 100644
index 00000000..a76491ce
--- /dev/null
+++ b/tests/stories/Controls.svelte
@@ -0,0 +1,141 @@
+
+
+
+ {#each Object.entries(properties) as [name, value]}
+ {name}: {JSON.stringify(value)}
+ {/each}
+
diff --git a/tests/stories/Decorators.stories.svelte b/tests/stories/Decorators.stories.svelte
new file mode 100644
index 00000000..ab9087b9
--- /dev/null
+++ b/tests/stories/Decorators.stories.svelte
@@ -0,0 +1,138 @@
+
+
+
+ {
+ const { args, canvasElement } = context;
+ const canvas = within(canvasElement);
+ const element = canvas.getByText(args.text);
+
+ expect(element).toBeInTheDocument();
+ expect(element.parentNode.style.borderColor).toBe('pink');
+ }}
+/>
+
+
+`' }}
+ decorators={[
+ () => ({
+ Component: BorderDecorator,
+ props: { color: 'blue' },
+ }),
+ ]}
+ play={async (context) => {
+ const { args, canvasElement } = context;
+ const canvas = within(canvasElement);
+ const element = canvas.getByText(args.text);
+
+ expect(element).toBeInTheDocument();
+ expect(element.parentNode.style.borderColor).toBe('blue');
+ expect(element.parentNode.parentNode.style.borderColor).toBe('pink');
+ }}
+/>
+
+
+`' }}
+ decorators={[
+ // NOTE: First one decorator is the most deeply nested children
+ () => ({ Component: BorderDecorator, props: { color: 'cyan' } }),
+ () => ({ Component: BorderDecorator, props: { color: 'darkorchid' } }),
+ // NOTE: The last one decorator wraps all of the above decorators
+ () => ({ Component: BorderDecorator, props: { color: 'gold' } }),
+ ]}
+ play={async (context) => {
+ const { args, canvasElement } = context;
+ const canvas = within(canvasElement);
+ const element = canvas.getByText(args.text);
+
+ expect(element).toBeInTheDocument();
+ expect(element.parentNode.style.borderColor).toBe('cyan');
+ expect(element.parentNode.parentNode.style.borderColor).toBe('darkorchid');
+ expect(element.parentNode.parentNode.parentNode.style.borderColor).toBe('gold');
+ expect(element.parentNode.parentNode.parentNode.parentNode.style.borderColor).toBe('pink');
+ }}
+/>
diff --git a/tests/stories/Example.stories.svelte b/tests/stories/Example.stories.svelte
new file mode 100644
index 00000000..1a19f4c6
--- /dev/null
+++ b/tests/stories/Example.stories.svelte
@@ -0,0 +1,62 @@
+
+
+
+
+{#snippet render(args: Args, context: StoryContext)}
+
+ {args.id}
+ {context.name}
+ You clicked: {count}
+
+{/snippet}
+
+
+
+
+
+
+
+
+
+
+
+ Label
+
diff --git a/tests/stories/Example.svelte b/tests/stories/Example.svelte
new file mode 100644
index 00000000..f28bd2ea
--- /dev/null
+++ b/tests/stories/Example.svelte
@@ -0,0 +1,32 @@
+
+
+
+
+
diff --git a/tests/stories/Interactions.stories.svelte b/tests/stories/Interactions.stories.svelte
new file mode 100644
index 00000000..9d312bb8
--- /dev/null
+++ b/tests/stories/Interactions.stories.svelte
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+ {
+ const { canvasElement } = context;
+ const canvas = within(canvasElement);
+ const p = canvas.getByTestId('count');
+
+ expect(p.textContent).toEqual('0');
+
+ i++;
+ await tick();
+ expect(p.textContent).toEqual('1');
+
+ i--;
+ await tick();
+ expect(p.textContent).toEqual('0');
+ }}
+>
+ {i}
+
diff --git a/tests/stories/Interactions.svelte b/tests/stories/Interactions.svelte
new file mode 100644
index 00000000..ef10d4b9
--- /dev/null
+++ b/tests/stories/Interactions.svelte
@@ -0,0 +1,10 @@
+
+
+
+ Counter
+ You clicked {count} times
+
+
+
diff --git a/tests/stories/Text.svelte b/tests/stories/Text.svelte
new file mode 100644
index 00000000..86ab4e0e
--- /dev/null
+++ b/tests/stories/Text.svelte
@@ -0,0 +1,6 @@
+
+
+{text}
diff --git a/tests/stories/test/Identifiers.stories.svelte b/tests/stories/test/Identifiers.stories.svelte
new file mode 100644
index 00000000..2b2833d9
--- /dev/null
+++ b/tests/stories/test/Identifiers.stories.svelte
@@ -0,0 +1,32 @@
+
+
+
+ Story with only a name
prop.
+
+
+
+ Story with only an exportName
prop.
+
+
+
+
+ Story with both an exportName
and a name
prop, "matching" each other.
+
+
+
+
+
+ Story with both an exportName
and a name
prop, not matching each other.
+
+
diff --git a/tests/stories/test/Overrides.stories.svelte b/tests/stories/test/Overrides.stories.svelte
new file mode 100644
index 00000000..9061ec26
--- /dev/null
+++ b/tests/stories/test/Overrides.stories.svelte
@@ -0,0 +1,45 @@
+
+
+ {
+ const { canvasElement } = context;
+ const canvas = within(canvasElement);
+ const p = canvas.getByTestId('test');
+
+ expect(p).toBeInTheDocument();
+ }}
+>
+
+ You can override
+ the following identifiers name that belongs to this Storybook addon:
+
+
+
+ -
+
imported `defineMeta` function
+
+
+ -
+
destructured `Story` from `defineMeta` (or whatever you renamed it to) call
+
+
+ -
+
destructured `meta` from `defineMeta` (or whatever you renamed it to) call
+
+
+
diff --git a/tests/stories/test/RequiredSnippet.stories.svelte b/tests/stories/test/RequiredSnippet.stories.svelte
new file mode 100644
index 00000000..bb7b8c7b
--- /dev/null
+++ b/tests/stories/test/RequiredSnippet.stories.svelte
@@ -0,0 +1,31 @@
+
+
+
+
+
+{#snippet children()}
+ This works
+{/snippet}
+
+
+
+
+
+ {#snippet children()}
+ This works
+ {/snippet}
+
+
+
+ This works
+
diff --git a/tests/stories/test/RequiredSnippet.svelte b/tests/stories/test/RequiredSnippet.svelte
new file mode 100644
index 00000000..82f17d2c
--- /dev/null
+++ b/tests/stories/test/RequiredSnippet.svelte
@@ -0,0 +1,13 @@
+
+
+
+ {@render children()}
+
diff --git a/tests/stories/test/StoryContext.stories.svelte b/tests/stories/test/StoryContext.stories.svelte
new file mode 100644
index 00000000..0b650140
--- /dev/null
+++ b/tests/stories/test/StoryContext.stories.svelte
@@ -0,0 +1,30 @@
+
+
+
+ {#snippet children(_args, context)}
+
+
+{JSON.stringify(context, replacer, 2)}
+
+
+ {/snippet}
+
diff --git a/tsconfig.json b/tsconfig.json
index 25930b8b..464f4b5e 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -4,17 +4,26 @@
"allowSyntheticDefaultImports": true,
"baseUrl": ".",
"esModuleInterop": true,
- "experimentalDecorators": true,
"incremental": false,
- "isolatedModules": true,
"lib": ["esnext", "dom"],
- "module": "es2020",
- "moduleResolution": "nodenext",
+ "module": "esnext",
+ "moduleResolution": "bundler",
"noImplicitAny": false,
+ "resolveJsonModule": true,
"rootDir": ".",
"skipLibCheck": true,
+ "strict": true,
"target": "esnext",
- "strict": true
+ "verbatimModuleSyntax": true,
+ "types": ["vitest/importMeta"],
+ "customConditions": ["development"],
+ "plugins": [
+ {
+ "name": "typescript-svelte-plugin",
+ "enabled": true,
+ "assumeIsSvelteProject": true
+ }
+ ]
},
- "include": ["src/**/*"]
+ "include": ["src/**/*", "examples/**/*", "tests/**/*"]
}
diff --git a/vite.config.ts b/vite.config.ts
index 9061b002..38cf26cc 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,6 +1,24 @@
+///
+
import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
+import inspect from 'vite-plugin-inspect';
export default defineConfig({
- plugins: [svelte({})],
+ // define: {
+ // 'import.meta.vitest': 'undefined',
+ // },
+ plugins: [
+ svelte(),
+ inspect({
+ dev: true,
+ build: true,
+ }),
+ ],
+ test: {
+ dir: './src/',
+ environment: 'jsdom',
+ globals: true,
+ // includeSource: ['**/*.ts'],
+ },
});
diff --git a/vitest.config.ts b/vitest.config.ts
deleted file mode 100644
index d17caab7..00000000
--- a/vitest.config.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { defineConfig } from 'vitest/config';
-import { svelte } from '@sveltejs/vite-plugin-svelte';
-
-export default defineConfig({
- plugins: [
- svelte({ hot: !process.env.VITEST }),
- ],
- test: {
- globals: true,
- environment: 'jsdom',
- dir: './src/'
- },
-});
\ No newline at end of file