Skip to content

Commit

Permalink
fix: relative declaration extension should match the extension of the…
Browse files Browse the repository at this point in the history
… code output (#264)
  • Loading branch information
cjpearson committed Jan 14, 2025
1 parent 0dc1c38 commit 6375e36
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 22 deletions.
6 changes: 2 additions & 4 deletions src/loaders/js.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { transform } from "esbuild";
import jiti from "jiti";

import type { Loader, LoaderResult } from "../loader";
import { getOutputExtension } from "../utils";

const DECLARATION_RE = /\.d\.[cm]?ts$/;
const CM_LETTER_RE = /(?<=\.)(c|m)(?=[jt]s$)/;
Expand Down Expand Up @@ -55,10 +56,7 @@ export const jsLoader: Loader = async (input, { options }) => {
.replace("module.exports = void 0;", "");
}

let extension = isCjs ? ".js" : ".mjs"; // TODO: Default to .cjs in next major version
if (options.ext) {
extension = options.ext.startsWith(".") ? options.ext : `.${options.ext}`;
}
const extension = getOutputExtension(options);

output.push({
contents,
Expand Down
9 changes: 7 additions & 2 deletions src/utils/dts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { findStaticImports, findExports, findTypeExports } from "mlly";
import { resolve } from "pathe";
import type { TSConfig } from "pkg-types";
import type { MkdistOptions } from "../make";
import { getOutputExtension } from "./index";
import type { CompilerHost, EmitResult } from "typescript";

export async function normalizeCompilerOptions(
Expand Down Expand Up @@ -65,7 +66,10 @@ export function extractDeclarations(
const dtsFilename = filename.replace(JSX_EXT_RE, ".d.$1ts");
let contents = vfs.get(dtsFilename) || "";
if (opts?.addRelativeDeclarationExtensions) {
const ext = filename.match(JS_EXT_RE)?.[0].replace(/ts$/, "js") || ".js";
const srcExt =
filename.match(JS_EXT_RE)?.[0].replace(/ts$/, "js") || ".js";
const ext = getOutputExtension(opts);

const imports = findStaticImports(contents);
const exports = findExports(contents);
const typeExports = findTypeExports(contents);
Expand All @@ -74,7 +78,8 @@ export function extractDeclarations(
continue;
}
const srcPath = resolve(filename, "..", spec.specifier);
const srcDtsPath = srcPath + ext.replace(JS_EXT_RE, ".d.$1ts");
const srcDtsPath = srcPath + srcExt.replace(JS_EXT_RE, ".d.$1ts");

let specifier = spec.specifier;
try {
if (!vfs.get(srcDtsPath)) {
Expand Down
10 changes: 10 additions & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { MkdistOptions } from "../make";

export function getOutputExtension(options: MkdistOptions) {
const isCjs = options.format === "cjs";
let ext = isCjs ? ".js" : ".mjs"; // TODO: Default to .cjs in next major version
if (options.ext) {
ext = options.ext.startsWith(".") ? options.ext : `.${options.ext}`;
}
return ext;
}
194 changes: 178 additions & 16 deletions test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,168 @@ describe("mkdist", () => {
"manual declaration",
);

expect(await readFile(resolve(rootDir, "dist/star/index.d.ts"), "utf8"))
.toMatchInlineSnapshot(`
"export * from "./other.mjs";
export type { Other } from "./other.mjs";
"
`);

expect(await readFile(resolve(rootDir, "dist/dir-export.d.ts"), "utf8"))
.toMatchInlineSnapshot(`
"export { default as bar } from "./bar.mjs";
export * from "./star/index.mjs";
"
`);

expect(
await readFile(resolve(rootDir, "dist/bar/esm.d.mts"), "utf8"),
).toMatch("declare");

expect(
await readFile(resolve(rootDir, "dist/components/index.d.ts"), "utf8"),
).toMatchInlineSnapshot(`
"export * as jsx from "./jsx.jsx.mjs";
export * as tsx from "./tsx.tsx.mjs";
export * as blank from "./blank.vue.mjs";
export * as scriptSetupTS from "./script-setup-ts.vue.mjs";
export * as scriptMultiBlock from "./script-multi-block.vue.mjs";
export * as ts from "./ts.vue.mjs";
"
`);

expect(
await readFile(resolve(rootDir, "dist/components/ts.vue.d.ts"), "utf8"),
).toMatchInlineSnapshot(`
"declare const _default: import("vue").DefineComponent<{}, {}, {
test: string;
str: "test";
}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
export default _default;
"
`);

expect(
await readFile(
resolve(rootDir, "dist/components/blank.vue.d.ts"),
"utf8",
),
).toMatchInlineSnapshot(`
"declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
export default _default;
"
`);

expect(
await readFile(
resolve(rootDir, "dist/components/script-multi-block.vue.d.ts"),
"utf8",
),
).toMatchInlineSnapshot(`
"interface MyComponentProps {
msg: string;
}
declare const _default: import("vue").DefineComponent<import("vue").ExtractPropTypes<__VLS_TypePropsToOption<MyComponentProps>>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToOption<MyComponentProps>>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
export default _default;
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
type __VLS_TypePropsToOption<T> = {
[K in keyof T]-?: {} extends Pick<T, K> ? {
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
} : {
type: import('vue').PropType<T[K]>;
required: true;
};
};
"
`);

expect(
await readFile(
resolve(rootDir, "dist/components/script-setup-ts.vue.d.ts"),
"utf8",
),
).toMatchInlineSnapshot(`
"import { Color } from "#prop-types";
type __VLS_Props = {
msg: string;
color: Color;
};
declare const _default: import("vue").DefineComponent<import("vue").ExtractPropTypes<__VLS_TypePropsToOption<__VLS_Props>>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_TypePropsToOption<__VLS_Props>>> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
export default _default;
type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;
type __VLS_TypePropsToOption<T> = {
[K in keyof T]-?: {} extends Pick<T, K> ? {
type: import('vue').PropType<__VLS_NonUndefinedable<T[K]>>;
} : {
type: import('vue').PropType<T[K]>;
required: true;
};
};
"
`);
}, 50_000);

it("mkdist (emit types) [js]", async () => {
const rootDir = resolve(__dirname, "fixture");
const { writtenFiles } = await mkdist({
rootDir,
declaration: true,
addRelativeDeclarationExtensions: true,
ext: "js",
});
expect(writtenFiles.sort()).toEqual(
[
"dist/README.md",
"dist/bar.d.ts",
"dist/bar.js",
"dist/demo.css",
"dist/dir-export.d.ts",
"dist/dir-export.js",
"dist/foo.js",
"dist/foo.d.ts",
"dist/index.js",
"dist/index.d.ts",
"dist/star/index.js",
"dist/star/index.d.ts",
"dist/star/other.js",
"dist/star/other.d.ts",
"dist/types.d.ts",
"dist/components/index.js",
"dist/components/index.d.ts",
"dist/components/blank.vue",
"dist/components/blank.vue.d.ts",
"dist/components/js.vue",
"dist/components/js.vue.d.ts",
"dist/components/script-multi-block.vue",
"dist/components/script-multi-block.vue.d.ts",
"dist/components/script-setup-ts.vue",
"dist/components/script-setup-ts.vue.d.ts",
"dist/components/ts.vue",
"dist/components/ts.vue.d.ts",
"dist/components/jsx.js",
"dist/components/tsx.js",
"dist/components/jsx.d.ts",
"dist/components/tsx.d.ts",
"dist/bar/index.js",
"dist/bar/index.d.ts",
"dist/bar/esm.js",
"dist/bar/esm.d.mts",
"dist/ts/test1.js",
"dist/ts/test2.js",
"dist/ts/test1.d.mts",
"dist/ts/test2.d.cts",
"dist/nested.css",
"dist/prop-types/index.js",
"dist/prop-types/index.d.ts",
]
.map((f) => resolve(rootDir, f))
.sort(),
);

expect(await readFile(resolve(rootDir, "dist/foo.d.ts"), "utf8")).toMatch(
"manual declaration",
);

expect(await readFile(resolve(rootDir, "dist/star/index.d.ts"), "utf8"))
.toMatchInlineSnapshot(`
"export * from "./other.js";
Expand Down Expand Up @@ -611,8 +773,8 @@ describe("mkdist with vue-tsc v1", () => {

expect(await readFile(resolve(rootDir, "dist/star/index.d.ts"), "utf8"))
.toMatchInlineSnapshot(`
"export * from "./other.js";
export type { Other } from "./other.js";
"export * from "./other.mjs";
export type { Other } from "./other.mjs";
"
`);
expect(
Expand All @@ -622,12 +784,12 @@ describe("mkdist with vue-tsc v1", () => {
expect(
await readFile(resolve(rootDir, "dist/components/index.d.ts"), "utf8"),
).toMatchInlineSnapshot(`
"export * as jsx from "./jsx.jsx.js";
export * as tsx from "./tsx.tsx.js";
export * as blank from "./blank.vue.js";
export * as scriptSetupTS from "./script-setup-ts.vue.js";
export * as scriptMultiBlock from "./script-multi-block.vue.js";
export * as ts from "./ts.vue.js";
"export * as jsx from "./jsx.jsx.mjs";
export * as tsx from "./tsx.tsx.mjs";
export * as blank from "./blank.vue.mjs";
export * as scriptSetupTS from "./script-setup-ts.vue.mjs";
export * as scriptMultiBlock from "./script-multi-block.vue.mjs";
export * as ts from "./ts.vue.mjs";
"
`);

Expand Down Expand Up @@ -868,8 +1030,8 @@ describe("mkdist with vue-tsc ~v2.0.21", () => {

expect(await readFile(resolve(rootDir, "dist/star/index.d.ts"), "utf8"))
.toMatchInlineSnapshot(`
"export * from "./other.js";
export type { Other } from "./other.js";
"export * from "./other.mjs";
export type { Other } from "./other.mjs";
"
`);
expect(
Expand All @@ -879,12 +1041,12 @@ describe("mkdist with vue-tsc ~v2.0.21", () => {
expect(
await readFile(resolve(rootDir, "dist/components/index.d.ts"), "utf8"),
).toMatchInlineSnapshot(`
"export * as jsx from "./jsx.jsx.js";
export * as tsx from "./tsx.tsx.js";
export * as blank from "./blank.vue.js";
export * as scriptSetupTS from "./script-setup-ts.vue.js";
export * as scriptMultiBlock from "./script-multi-block.vue.js";
export * as ts from "./ts.vue.js";
"export * as jsx from "./jsx.jsx.mjs";
export * as tsx from "./tsx.tsx.mjs";
export * as blank from "./blank.vue.mjs";
export * as scriptSetupTS from "./script-setup-ts.vue.mjs";
export * as scriptMultiBlock from "./script-multi-block.vue.mjs";
export * as ts from "./ts.vue.mjs";
"
`);

Expand Down

0 comments on commit 6375e36

Please sign in to comment.