diff --git a/.prettierignore b/.prettierignore index 97dae2523..3caa6aac9 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,6 +2,7 @@ packages/svelte2tsx/*.d.ts packages/svelte2tsx/test/*/samples/*/*sx packages/svelte2tsx/test/*/samples/*/*.svelte packages/svelte2tsx/test/sourcemaps/samples/* +packages/svelte2tsx/test/emitDts/samples/*/expected/** packages/language-server/test/**/*.svelte packages/language-server/test/**/testfiles/**/*.ts packages/svelte-vscode/syntaxes/*.yaml diff --git a/packages/svelte2tsx/index.d.ts b/packages/svelte2tsx/index.d.ts index 629ee4c7d..74b6d4faf 100644 --- a/packages/svelte2tsx/index.d.ts +++ b/packages/svelte2tsx/index.d.ts @@ -47,3 +47,30 @@ export function svelte2tsx( mode?: 'tsx' | 'dts' } ): SvelteCompiledToTsx + +export interface EmitDtsConig { + /** + * Where to output the declaration files + */ + declarationDir: string; + /** + * Path to `svelte-shims.d.ts` of `svelte2tsx`. + * Example: `require.resolve('svelte2tsx/svelte-shims.d.ts')` + */ + svelteShimsPath: string; + /** + * If you want to emit types only for part of your project, + * then set this to the folder for which the types should be emitted. + * Most of the time you don't need this. For SvelteKit, this is for example + * set to `src/lib` by default. + */ + libRoot?: string; +} + +/** + * Searches for a jsconfig or tsconfig starting at `root` and emits d.ts files + * into `declarationDir` using the ambient file from `svelteShimsPath`. + * Note: Handwritten `d.ts` files are not copied over; TypeScript does not + * touch these files. + */ +export function emitDts(config: EmitDtsConig): Promise; diff --git a/packages/svelte2tsx/src/emitDts.ts b/packages/svelte2tsx/src/emitDts.ts new file mode 100644 index 000000000..81817918b --- /dev/null +++ b/packages/svelte2tsx/src/emitDts.ts @@ -0,0 +1,225 @@ +import * as path from 'path'; +import ts from 'typescript'; +import { svelte2tsx } from './svelte2tsx'; + +export interface EmitDtsConig { + declarationDir: string; + svelteShimsPath: string; + libRoot?: string; +} + +export async function emitDts(config: EmitDtsConig) { + const svelteMap = await createSvelteMap(config); + const { options, filenames } = loadTsconfig(config, svelteMap); + const host = await createTsCompilerHost(options, svelteMap); + const program = ts.createProgram(filenames, options, host); + program.emit(); +} + +function loadTsconfig(config: EmitDtsConig, svelteMap: SvelteMap) { + const libRoot = config.libRoot || process.cwd(); + + const jsconfigFile = ts.findConfigFile(libRoot, ts.sys.fileExists, 'jsconfig.json'); + let tsconfigFile = ts.findConfigFile(libRoot, ts.sys.fileExists); + + if (!tsconfigFile && !jsconfigFile) { + throw new Error('Failed to locate tsconfig or jsconfig'); + } + + tsconfigFile = tsconfigFile || jsconfigFile; + if (jsconfigFile && isSubpath(path.dirname(tsconfigFile), path.dirname(jsconfigFile))) { + tsconfigFile = jsconfigFile; + } + + tsconfigFile = path.isAbsolute(tsconfigFile) ? tsconfigFile : path.join(libRoot, tsconfigFile); + const basepath = path.dirname(tsconfigFile); + const { error, config: tsConfig } = ts.readConfigFile(tsconfigFile, ts.sys.readFile); + + if (error) { + throw new Error('Malformed tsconfig\n' + JSON.stringify(error, null, 2)); + } + + // Rewire includes and files. This ensures that only the files inside the lib are traversed and + // that the outputted types have the correct directory depth. + // This is a little brittle because we then may include more than the user wants + const libPathRelative = path.relative(basepath, libRoot).split(path.sep).join('/'); + if (libPathRelative) { + tsConfig.include = [`${libPathRelative}/**/*`]; + tsConfig.files = []; + } + + const { options, fileNames } = ts.parseJsonConfigFileContent( + tsConfig, + ts.sys, + basepath, + { sourceMap: false }, + tsconfigFile, + undefined, + [{ extension: 'svelte', isMixedContent: true, scriptKind: ts.ScriptKind.Deferred }] + ); + + const filenames = fileNames.map((name) => { + if (!isSvelteFilepath(name)) { + return name; + } + // We need to trick TypeScript into thinking that Svelte files + // are either TS or JS files in order to generate correct d.ts + // definition files. + const isTsFile = svelteMap.add(name); + return name + (isTsFile ? '.ts' : '.js'); + }); + + // Add ambient functions so TS knows how to resolve its invocations in the + // code output of svelte2tsx. + filenames.push(config.svelteShimsPath); + + return { + options: { + ...options, + noEmit: false, // Set to true in case of jsconfig, force false, else nothing is emitted + moduleResolution: ts.ModuleResolutionKind.NodeJs, // Classic if not set, which gives wrong results + declaration: true, // Needed for d.ts file generation + emitDeclarationOnly: true, // We only want d.ts file generation + declarationDir: config.declarationDir, // Where to put the declarations + allowNonTsExtensions: true + }, + filenames + }; +} + +async function createTsCompilerHost(options: any, svelteMap: SvelteMap) { + const host = ts.createCompilerHost(options); + // TypeScript writes the files relative to the found tsconfig/jsconfig + // which - at least in the case of the tests - is wrong. Therefore prefix + // the output paths. See Typescript issue #25430 for more. + const pathPrefix = path.relative(process.cwd(), path.dirname(options.configFilePath)); + + const svelteSys: ts.System = { + ...ts.sys, + fileExists(originalPath) { + const path = ensureRealSvelteFilepath(originalPath); + const exists = ts.sys.fileExists(path); + if (exists && isSvelteFilepath(path)) { + const isTsFile = svelteMap.add(path); + if ( + (isTsFile && !isTsFilepath(originalPath)) || + (!isTsFile && isTsFilepath(originalPath)) + ) { + return false; + } + } + return exists; + }, + readFile(path, encoding = 'utf-8') { + if (isVirtualSvelteFilepath(path) || isSvelteFilepath(path)) { + path = ensureRealSvelteFilepath(path); + return svelteMap.get(path); + } else { + return ts.sys.readFile(path, encoding); + } + }, + readDirectory(path, extensions, exclude, include, depth) { + const extensionsWithSvelte = (extensions || []).concat('.svelte'); + return ts.sys.readDirectory(path, extensionsWithSvelte, exclude, include, depth); + }, + writeFile(fileName, data, writeByteOrderMark) { + return ts.sys.writeFile( + pathPrefix ? path.join(pathPrefix, fileName) : fileName, + data, + writeByteOrderMark + ); + } + }; + + host.fileExists = svelteSys.fileExists; + host.readFile = svelteSys.readFile; + host.readDirectory = svelteSys.readDirectory; + host.writeFile = svelteSys.writeFile; + + host.resolveModuleNames = ( + moduleNames, + containingFile, + _reusedNames, + _redirectedReference, + compilerOptions + ) => { + return moduleNames.map((moduleName) => { + return resolveModuleName(moduleName, containingFile, compilerOptions); + }); + }; + + function resolveModuleName(name: string, containingFile: string, compilerOptions: any) { + // Delegate to the TS resolver first. + // If that does not bring up anything, try the Svelte Module loader + // which is able to deal with .svelte files. + const tsResolvedModule = ts.resolveModuleName( + name, + containingFile, + compilerOptions, + ts.sys + ).resolvedModule; + if (tsResolvedModule && !isVirtualSvelteFilepath(tsResolvedModule.resolvedFileName)) { + return tsResolvedModule; + } + + return ts.resolveModuleName(name, containingFile, compilerOptions, svelteSys) + .resolvedModule; + } + + return host; +} + +interface SvelteMap { + add: (path: string) => boolean; + get: (key: string) => string | undefined; +} + +/** + * Generates a map to which we add the transformed code of Svelte files + * early on when we first need to look at the file contents and can read + * those transformed source later on. + */ +async function createSvelteMap(config): Promise { + const svelteFiles = new Map(); + + function add(path: string): boolean { + const code = ts.sys.readFile(path, 'utf-8'); + const isTsFile = // svelte-preprocess allows default languages + ['ts', 'typescript'].includes(config.preprocess?.defaultLanguages?.script) || + /]*?lang=('|")(ts|typescript)('|")/.test(code); + const transformed = svelte2tsx(code, { + filename: path, + isTsFile, + mode: 'dts' + }).code; + svelteFiles.set(path, transformed); + return isTsFile; + } + + return { add, get: (key: string) => svelteFiles.get(key) }; +} + +function isSvelteFilepath(filePath: string) { + return filePath.endsWith('.svelte'); +} + +function isTsFilepath(filePath: string) { + return filePath.endsWith('.ts'); +} + +function isVirtualSvelteFilepath(filePath: string) { + return filePath.endsWith('.svelte.ts') || filePath.endsWith('svelte.js'); +} + +function toRealSvelteFilepath(filePath: string) { + return filePath.slice(0, -3); // -'.js'.length || -'.ts'.length +} + +function ensureRealSvelteFilepath(filePath: string) { + return isVirtualSvelteFilepath(filePath) ? toRealSvelteFilepath(filePath) : filePath; +} + +function isSubpath(maybeParent: string, maybeChild: string) { + const relative = path.relative(maybeParent, maybeChild); + return relative && !relative.startsWith('..') && !path.isAbsolute(relative); +} diff --git a/packages/svelte2tsx/src/index.ts b/packages/svelte2tsx/src/index.ts index 1c32f786b..ef3d5bcf2 100644 --- a/packages/svelte2tsx/src/index.ts +++ b/packages/svelte2tsx/src/index.ts @@ -1 +1,2 @@ export { svelte2tsx } from './svelte2tsx'; +export { emitDts } from './emitDts'; diff --git a/packages/svelte2tsx/test/emitDts/index.ts b/packages/svelte2tsx/test/emitDts/index.ts new file mode 100644 index 000000000..5469c88c3 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/index.ts @@ -0,0 +1,60 @@ +import * as assert from 'assert'; +import * as fs from 'fs'; +import { join } from 'path'; +import { emitDts } from '../../src'; + +function rimraf(path: string) { + ((fs as any).rmSync || fs.rmdirSync)(path, { recursive: true, force: true }); +} + +async function testEmitDts(sample: string) { + const cwd = join(__dirname, 'samples', sample); + + try { + const config = fs.existsSync(join(cwd, 'config.json')) + ? JSON.parse(fs.readFileSync(join(cwd, 'config.json'), 'utf-8')) + : {}; + await emitDts({ + declarationDir: 'package', + svelteShimsPath: require.resolve(join(process.cwd(), 'svelte-shims.d.ts')), + ...config, + libRoot: config.libRoot ? join(cwd, config.libRoot) : cwd + }); + const expectedFiles = fs.readdirSync(join(cwd, 'expected')); + const actual_files = fs.readdirSync(join(cwd, 'package')); + assert.strictEqual( + actual_files.length, + expectedFiles.length, + 'Contains a different number of files. Expected ' + + expectedFiles.join(',') + + ' , got ' + + actual_files.join(',') + ); + + for (const file of actual_files) { + assert.strictEqual( + expectedFiles.includes(file), + true, + `Did not expect file or folder ${file}` + ); + const expectedContent = fs.readFileSync(join(cwd, 'expected', file), 'utf-8'); + const actualContent = fs.readFileSync(join(cwd, 'package', file), 'utf-8'); + assert.strictEqual( + actualContent, + expectedContent, + `Expected equal file contents for ${file}` + ); + } + } finally { + rimraf(join(cwd, 'package')); + } +} + +describe('emitDts', async () => { + const samples = fs.readdirSync(join(__dirname, 'samples')); + let samplesToTest = samples.filter((s) => s.endsWith('.solo')); + samplesToTest = samplesToTest.length ? samplesToTest : samples; + for (const sample of samplesToTest) { + it(sample, async () => await testEmitDts(sample)).timeout(5000); + } +}); diff --git a/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/config.json b/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/config.json new file mode 100644 index 000000000..dd4044b7e --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/config.json @@ -0,0 +1,3 @@ +{ + "libRoot": "src/lib" +} diff --git a/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/expected/Test.svelte.d.ts b/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/expected/Test.svelte.d.ts new file mode 100644 index 000000000..3e176b43e --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/expected/Test.svelte.d.ts @@ -0,0 +1,36 @@ +/** @typedef {typeof __propDef.props} TestProps */ +/** @typedef {typeof __propDef.events} TestEvents */ +/** @typedef {typeof __propDef.slots} TestSlots */ +export default class Test extends SvelteComponentTyped<{ + astring: string; +}, { + event: CustomEvent; +} & { + [evt: string]: CustomEvent; +}, { + default: { + astring: string; + }; +}> { + get astring(): string; +} +export type TestProps = typeof __propDef.props; +export type TestEvents = typeof __propDef.events; +export type TestSlots = typeof __propDef.slots; +import { SvelteComponentTyped } from "svelte"; +declare const __propDef: { + props: { + astring: string; + }; + events: { + event: CustomEvent; + } & { + [evt: string]: CustomEvent; + }; + slots: { + default: { + astring: string; + }; + }; +}; +export {}; diff --git a/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/expected/index.d.ts b/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/expected/index.d.ts new file mode 100644 index 000000000..637e48200 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/expected/index.d.ts @@ -0,0 +1 @@ +export { default as Test } from "./Test.svelte"; diff --git a/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/jsconfig.json b/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/jsconfig.json new file mode 100644 index 000000000..edbf12661 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/jsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "checkJs": true + }, + "include": ["./src/**/*.d.ts", "./src/**/*.js", "./src/**/*.ts", "./src/**/*.svelte"] +} diff --git a/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/src/Test2.svelte b/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/src/Test2.svelte new file mode 100644 index 000000000..06a5a3408 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/src/Test2.svelte @@ -0,0 +1,6 @@ + diff --git a/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/src/lib/Test.svelte b/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/src/lib/Test.svelte new file mode 100644 index 000000000..31d118397 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/src/lib/Test.svelte @@ -0,0 +1,12 @@ + + + diff --git a/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/src/lib/index.js b/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/src/lib/index.js new file mode 100644 index 000000000..4c44188c3 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/javascript-libRoot/src/lib/index.js @@ -0,0 +1 @@ +export { default as Test } from './Test.svelte'; diff --git a/packages/svelte2tsx/test/emitDts/samples/javascript/expected/Test.svelte.d.ts b/packages/svelte2tsx/test/emitDts/samples/javascript/expected/Test.svelte.d.ts new file mode 100644 index 000000000..3e176b43e --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/javascript/expected/Test.svelte.d.ts @@ -0,0 +1,36 @@ +/** @typedef {typeof __propDef.props} TestProps */ +/** @typedef {typeof __propDef.events} TestEvents */ +/** @typedef {typeof __propDef.slots} TestSlots */ +export default class Test extends SvelteComponentTyped<{ + astring: string; +}, { + event: CustomEvent; +} & { + [evt: string]: CustomEvent; +}, { + default: { + astring: string; + }; +}> { + get astring(): string; +} +export type TestProps = typeof __propDef.props; +export type TestEvents = typeof __propDef.events; +export type TestSlots = typeof __propDef.slots; +import { SvelteComponentTyped } from "svelte"; +declare const __propDef: { + props: { + astring: string; + }; + events: { + event: CustomEvent; + } & { + [evt: string]: CustomEvent; + }; + slots: { + default: { + astring: string; + }; + }; +}; +export {}; diff --git a/packages/svelte2tsx/test/emitDts/samples/javascript/expected/Test2.svelte.d.ts b/packages/svelte2tsx/test/emitDts/samples/javascript/expected/Test2.svelte.d.ts new file mode 100644 index 000000000..d025bccbd --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/javascript/expected/Test2.svelte.d.ts @@ -0,0 +1,23 @@ +/** @typedef {typeof __propDef.props} Test2Props */ +/** @typedef {typeof __propDef.events} Test2Events */ +/** @typedef {typeof __propDef.slots} Test2Slots */ +export default class Test2 extends SvelteComponentTyped<{ + foo: boolean; +}, { + [evt: string]: CustomEvent; +}, {}> { +} +export type Test2Props = typeof __propDef.props; +export type Test2Events = typeof __propDef.events; +export type Test2Slots = typeof __propDef.slots; +import { SvelteComponentTyped } from "svelte"; +declare const __propDef: { + props: { + foo: import('./foo').Foo; + }; + events: { + [evt: string]: CustomEvent; + }; + slots: {}; +}; +export {}; diff --git a/packages/svelte2tsx/test/emitDts/samples/javascript/expected/TestNoTypes.svelte.d.ts b/packages/svelte2tsx/test/emitDts/samples/javascript/expected/TestNoTypes.svelte.d.ts new file mode 100644 index 000000000..4b00e8db8 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/javascript/expected/TestNoTypes.svelte.d.ts @@ -0,0 +1,37 @@ +/** @typedef {typeof __propDef.props} TestNoTypesProps */ +/** @typedef {typeof __propDef.events} TestNoTypesEvents */ +/** @typedef {typeof __propDef.slots} TestNoTypesSlots */ +export default class TestNoTypes extends SvelteComponentTyped<{ + noType: any; + initializer?: string; +}, { + event: CustomEvent; +} & { + [evt: string]: CustomEvent; +}, { + default: { + noType: any; + }; +}> { +} +export type TestNoTypesProps = typeof __propDef.props; +export type TestNoTypesEvents = typeof __propDef.events; +export type TestNoTypesSlots = typeof __propDef.slots; +import { SvelteComponentTyped } from "svelte"; +declare const __propDef: { + props: { + noType: any; + initializer?: string; + }; + events: { + event: CustomEvent; + } & { + [evt: string]: CustomEvent; + }; + slots: { + default: { + noType: any; + }; + }; +}; +export {}; diff --git a/packages/svelte2tsx/test/emitDts/samples/javascript/expected/index.d.ts b/packages/svelte2tsx/test/emitDts/samples/javascript/expected/index.d.ts new file mode 100644 index 000000000..637e48200 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/javascript/expected/index.d.ts @@ -0,0 +1 @@ +export { default as Test } from "./Test.svelte"; diff --git a/packages/svelte2tsx/test/emitDts/samples/javascript/jsconfig.json b/packages/svelte2tsx/test/emitDts/samples/javascript/jsconfig.json new file mode 100644 index 000000000..edbf12661 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/javascript/jsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "checkJs": true + }, + "include": ["./src/**/*.d.ts", "./src/**/*.js", "./src/**/*.ts", "./src/**/*.svelte"] +} diff --git a/packages/svelte2tsx/test/emitDts/samples/javascript/src/Test.svelte b/packages/svelte2tsx/test/emitDts/samples/javascript/src/Test.svelte new file mode 100644 index 000000000..31d118397 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/javascript/src/Test.svelte @@ -0,0 +1,12 @@ + + + diff --git a/packages/svelte2tsx/test/emitDts/samples/javascript/src/Test2.svelte b/packages/svelte2tsx/test/emitDts/samples/javascript/src/Test2.svelte new file mode 100644 index 000000000..06a5a3408 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/javascript/src/Test2.svelte @@ -0,0 +1,6 @@ + diff --git a/packages/svelte2tsx/test/emitDts/samples/javascript/src/TestNoTypes.svelte b/packages/svelte2tsx/test/emitDts/samples/javascript/src/TestNoTypes.svelte new file mode 100644 index 000000000..479de1d94 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/javascript/src/TestNoTypes.svelte @@ -0,0 +1,9 @@ + + + diff --git a/packages/svelte2tsx/test/emitDts/samples/javascript/src/foo.d.ts b/packages/svelte2tsx/test/emitDts/samples/javascript/src/foo.d.ts new file mode 100644 index 000000000..c941ad7b1 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/javascript/src/foo.d.ts @@ -0,0 +1 @@ +export type Foo = boolean; diff --git a/packages/svelte2tsx/test/emitDts/samples/javascript/src/index.js b/packages/svelte2tsx/test/emitDts/samples/javascript/src/index.js new file mode 100644 index 000000000..4c44188c3 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/javascript/src/index.js @@ -0,0 +1 @@ +export { default as Test } from './Test.svelte'; diff --git a/packages/svelte2tsx/test/emitDts/samples/typescript/expected/Test.svelte.d.ts b/packages/svelte2tsx/test/emitDts/samples/typescript/expected/Test.svelte.d.ts new file mode 100644 index 000000000..897acf8d2 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/typescript/expected/Test.svelte.d.ts @@ -0,0 +1,23 @@ +import { SvelteComponentTyped } from "svelte"; +declare const __propDef: { + props: { + astring: string; + }; + events: { + event: CustomEvent; + } & { + [evt: string]: CustomEvent; + }; + slots: { + default: { + astring: string; + }; + }; +}; +export declare type TestProps = typeof __propDef.props; +export declare type TestEvents = typeof __propDef.events; +export declare type TestSlots = typeof __propDef.slots; +export default class Test extends SvelteComponentTyped { + get astring(): string; +} +export {}; diff --git a/packages/svelte2tsx/test/emitDts/samples/typescript/expected/Test2.svelte.d.ts b/packages/svelte2tsx/test/emitDts/samples/typescript/expected/Test2.svelte.d.ts new file mode 100644 index 000000000..45e91c48b --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/typescript/expected/Test2.svelte.d.ts @@ -0,0 +1,17 @@ +import { SvelteComponentTyped } from "svelte"; +import type { Foo } from './foo'; +declare const __propDef: { + props: { + foo: Foo; + }; + events: { + [evt: string]: CustomEvent; + }; + slots: {}; +}; +export declare type Test2Props = typeof __propDef.props; +export declare type Test2Events = typeof __propDef.events; +export declare type Test2Slots = typeof __propDef.slots; +export default class Test2 extends SvelteComponentTyped { +} +export {}; diff --git a/packages/svelte2tsx/test/emitDts/samples/typescript/expected/index.d.ts b/packages/svelte2tsx/test/emitDts/samples/typescript/expected/index.d.ts new file mode 100644 index 000000000..4c44188c3 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/typescript/expected/index.d.ts @@ -0,0 +1 @@ +export { default as Test } from './Test.svelte'; diff --git a/packages/svelte2tsx/test/emitDts/samples/typescript/src/Test.svelte b/packages/svelte2tsx/test/emitDts/samples/typescript/src/Test.svelte new file mode 100644 index 000000000..b73d6e034 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/typescript/src/Test.svelte @@ -0,0 +1,9 @@ + + + diff --git a/packages/svelte2tsx/test/emitDts/samples/typescript/src/Test2.svelte b/packages/svelte2tsx/test/emitDts/samples/typescript/src/Test2.svelte new file mode 100644 index 000000000..aef3fb6f6 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/typescript/src/Test2.svelte @@ -0,0 +1,4 @@ + diff --git a/packages/svelte2tsx/test/emitDts/samples/typescript/src/foo.d.ts b/packages/svelte2tsx/test/emitDts/samples/typescript/src/foo.d.ts new file mode 100644 index 000000000..c941ad7b1 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/typescript/src/foo.d.ts @@ -0,0 +1 @@ +export type Foo = boolean; diff --git a/packages/svelte2tsx/test/emitDts/samples/typescript/src/index.ts b/packages/svelte2tsx/test/emitDts/samples/typescript/src/index.ts new file mode 100644 index 000000000..4c44188c3 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/typescript/src/index.ts @@ -0,0 +1 @@ +export { default as Test } from './Test.svelte'; diff --git a/packages/svelte2tsx/test/emitDts/samples/typescript/tsconfig.json b/packages/svelte2tsx/test/emitDts/samples/typescript/tsconfig.json new file mode 100644 index 000000000..5b465a5c9 --- /dev/null +++ b/packages/svelte2tsx/test/emitDts/samples/typescript/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "moduleResolution": "node", + "module": "es2020", + "lib": ["es2020", "DOM"], + "target": "es2019", + "isolatedModules": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "allowJs": true, + "checkJs": true + }, + "include": ["./src/**/*.d.ts", "./src/**/*.js", "./src/**/*.ts", "./src/**/*.svelte"] +} diff --git a/packages/svelte2tsx/test/test.ts b/packages/svelte2tsx/test/test.ts index df10cacbf..7e9512790 100644 --- a/packages/svelte2tsx/test/test.ts +++ b/packages/svelte2tsx/test/test.ts @@ -1,3 +1,6 @@ +const { dirname } = require('path'); +const { join } = require('path'); + require('ts-node').register({ project: 'test/tsconfig.json', transpileOnly: true @@ -13,7 +16,9 @@ if (process.env.CI) { } const test_folders = glob('*/index.ts', { cwd: 'test' }); -const solo_folders = test_folders.filter((folder) => /\.solo$/.test(folder)); +const solo_folders = test_folders.filter( + (folder) => glob('**/*.solo', { cwd: join('test', dirname(folder)) }).length +); if (solo_folders.length) { solo_folders.forEach((name) => require('./' + name));