From 377a47e49fbd31c937d905c5f9eacaf815c7ca39 Mon Sep 17 00:00:00 2001 From: hyper Date: Tue, 31 Mar 2026 15:49:05 +0800 Subject: [PATCH] fix: improve path handling for .d.ts file emission - Fix leading slash in relative path - Use .d.ts extension instead of .csv.d.ts - Support typesOutputDir option properly - Use ./ prefix for module declaration path Co-authored-by: Qwen-Coder --- dist/csv-loader/loader.d.mts | 4 +++ dist/csv-loader/loader.d.ts | 4 +++ dist/csv-loader/loader.js | 61 ++++++++++++++++++++++++++++++++++++ dist/csv-loader/loader.mjs | 51 ++++++++++++++++++++++++++++++ src/csv-loader/loader.ts | 22 +++++++++---- 5 files changed, 136 insertions(+), 6 deletions(-) diff --git a/dist/csv-loader/loader.d.mts b/dist/csv-loader/loader.d.mts index 65bbc8e..f3f881e 100644 --- a/dist/csv-loader/loader.d.mts +++ b/dist/csv-loader/loader.d.mts @@ -7,6 +7,10 @@ interface CsvLoaderOptions { bom?: boolean; comment?: string | false; trim?: boolean; + /** Generate TypeScript declaration file (.d.ts) */ + emitTypes?: boolean; + /** Output directory for generated type files (relative to output path) */ + typesOutputDir?: string; } declare function csvLoader(this: LoaderContext, content: string): string | Buffer; diff --git a/dist/csv-loader/loader.d.ts b/dist/csv-loader/loader.d.ts index 65bbc8e..f3f881e 100644 --- a/dist/csv-loader/loader.d.ts +++ b/dist/csv-loader/loader.d.ts @@ -7,6 +7,10 @@ interface CsvLoaderOptions { bom?: boolean; comment?: string | false; trim?: boolean; + /** Generate TypeScript declaration file (.d.ts) */ + emitTypes?: boolean; + /** Output directory for generated type files (relative to output path) */ + typesOutputDir?: string; } declare function csvLoader(this: LoaderContext, content: string): string | Buffer; diff --git a/dist/csv-loader/loader.js b/dist/csv-loader/loader.js index e24759f..062be01 100644 --- a/dist/csv-loader/loader.js +++ b/dist/csv-loader/loader.js @@ -1,7 +1,9 @@ "use strict"; +var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) @@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => { } return to; }; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/csv-loader/loader.ts @@ -354,6 +364,43 @@ function createValidator(schema) { } // src/csv-loader/loader.ts +var path = __toESM(require("path")); +function schemaToTypeString(schema) { + switch (schema.type) { + case "string": + return "string"; + case "number": + return "number"; + case "boolean": + return "boolean"; + case "array": + if (schema.element.type === "tuple") { + const tupleElements2 = schema.element.elements.map(schemaToTypeString); + return `[${tupleElements2.join(", ")}]`; + } + return `${schemaToTypeString(schema.element)}[]`; + case "tuple": + const tupleElements = schema.elements.map(schemaToTypeString); + return `[${tupleElements.join(", ")}]`; + default: + return "unknown"; + } +} +function generateTypeDefinition(resourceName, propertyConfigs, relativePath) { + const interfaceName = path.basename(resourceName, path.extname(resourceName)).replace(/[^a-zA-Z0-9_$]/g, "_").replace(/^(\d)/, "_$1"); + const properties = propertyConfigs.map((config) => ` ${config.name}: ${schemaToTypeString(config.schema)};`).join("\n"); + return `declare module "${relativePath}" { + export interface ${interfaceName} { +${properties} + } + + export type RowType = ${interfaceName}; + + const data: ${interfaceName}[]; + export default data; +} +`; +} function csvLoader(content) { const options = this.getOptions(); const delimiter = options?.delimiter ?? ","; @@ -362,6 +409,8 @@ function csvLoader(content) { const bom = options?.bom ?? true; const comment = options?.comment === false ? void 0 : options?.comment ?? "#"; const trim = options?.trim ?? true; + const emitTypes = options?.emitTypes ?? true; + const typesOutputDir = options?.typesOutputDir ?? ""; const records = (0, import_sync.parse)(content, { delimiter, quote, @@ -416,5 +465,17 @@ function csvLoader(content) { return obj; }); const json = JSON.stringify(objects, null, 2); + if (emitTypes) { + const context = this.context || ""; + let relativePath = this.resourcePath.replace(context, ""); + if (relativePath.startsWith("\\") || relativePath.startsWith("/")) { + relativePath = relativePath.substring(1); + } + relativePath = relativePath.replace(/\\/g, "/"); + const dtsFileName = relativePath.replace(/\.csv$/, ".d.ts"); + const outputPath = typesOutputDir ? path.join(typesOutputDir, dtsFileName) : dtsFileName; + const dtsContent = generateTypeDefinition(this.resourcePath, propertyConfigs, `./${relativePath}`); + this.emitFile?.(outputPath, dtsContent); + } return `export default ${json};`; } diff --git a/dist/csv-loader/loader.mjs b/dist/csv-loader/loader.mjs index cab3491..27ab9ca 100644 --- a/dist/csv-loader/loader.mjs +++ b/dist/csv-loader/loader.mjs @@ -330,6 +330,43 @@ function createValidator(schema) { } // src/csv-loader/loader.ts +import * as path from "path"; +function schemaToTypeString(schema) { + switch (schema.type) { + case "string": + return "string"; + case "number": + return "number"; + case "boolean": + return "boolean"; + case "array": + if (schema.element.type === "tuple") { + const tupleElements2 = schema.element.elements.map(schemaToTypeString); + return `[${tupleElements2.join(", ")}]`; + } + return `${schemaToTypeString(schema.element)}[]`; + case "tuple": + const tupleElements = schema.elements.map(schemaToTypeString); + return `[${tupleElements.join(", ")}]`; + default: + return "unknown"; + } +} +function generateTypeDefinition(resourceName, propertyConfigs, relativePath) { + const interfaceName = path.basename(resourceName, path.extname(resourceName)).replace(/[^a-zA-Z0-9_$]/g, "_").replace(/^(\d)/, "_$1"); + const properties = propertyConfigs.map((config) => ` ${config.name}: ${schemaToTypeString(config.schema)};`).join("\n"); + return `declare module "${relativePath}" { + export interface ${interfaceName} { +${properties} + } + + export type RowType = ${interfaceName}; + + const data: ${interfaceName}[]; + export default data; +} +`; +} function csvLoader(content) { const options = this.getOptions(); const delimiter = options?.delimiter ?? ","; @@ -338,6 +375,8 @@ function csvLoader(content) { const bom = options?.bom ?? true; const comment = options?.comment === false ? void 0 : options?.comment ?? "#"; const trim = options?.trim ?? true; + const emitTypes = options?.emitTypes ?? true; + const typesOutputDir = options?.typesOutputDir ?? ""; const records = parse(content, { delimiter, quote, @@ -392,6 +431,18 @@ function csvLoader(content) { return obj; }); const json = JSON.stringify(objects, null, 2); + if (emitTypes) { + const context = this.context || ""; + let relativePath = this.resourcePath.replace(context, ""); + if (relativePath.startsWith("\\") || relativePath.startsWith("/")) { + relativePath = relativePath.substring(1); + } + relativePath = relativePath.replace(/\\/g, "/"); + const dtsFileName = relativePath.replace(/\.csv$/, ".d.ts"); + const outputPath = typesOutputDir ? path.join(typesOutputDir, dtsFileName) : dtsFileName; + const dtsContent = generateTypeDefinition(this.resourcePath, propertyConfigs, `./${relativePath}`); + this.emitFile?.(outputPath, dtsContent); + } return `export default ${json};`; } export { diff --git a/src/csv-loader/loader.ts b/src/csv-loader/loader.ts index 756c54b..3f17ff6 100644 --- a/src/csv-loader/loader.ts +++ b/src/csv-loader/loader.ts @@ -152,16 +152,26 @@ export default function csvLoader( }); const json = JSON.stringify(objects, null, 2); - + // Emit type definition file if enabled if (emitTypes) { - const relativePath = this.resourcePath.replace(this.context, '').replace(/\\/g, '/'); - const dtsFileName = relativePath.replace(/\.csv$/, '.d.ts'); - const outputPath = path.join(typesOutputDir, dtsFileName); - const dtsContent = generateTypeDefinition(this.resourcePath, propertyConfigs, relativePath); + const context = this.context || ''; + // Get relative path from context, normalize to forward slashes + let relativePath = this.resourcePath.replace(context, ''); + if (relativePath.startsWith('\\') || relativePath.startsWith('/')) { + relativePath = relativePath.substring(1); + } + relativePath = relativePath.replace(/\\/g, '/'); + // Replace .csv with .d.ts for the output filename + const dtsFileName = relativePath.replace(/\.csv$/, '.d.ts'); + const outputPath = typesOutputDir + ? path.join(typesOutputDir, dtsFileName) + : dtsFileName; + const dtsContent = generateTypeDefinition(this.resourcePath, propertyConfigs, `./${relativePath}`); + this.emitFile?.(outputPath, dtsContent); } - + return `export default ${json};`; }