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 <qwen-coder@alibabacloud.com>
This commit is contained in:
hyper
2026-03-31 15:49:05 +08:00
co-authored by Qwen-Coder
parent 452b600487
commit 377a47e49f
5 changed files with 136 additions and 6 deletions
+4
View File
@@ -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<CsvLoaderOptions>, content: string): string | Buffer;
+4
View File
@@ -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<CsvLoaderOptions>, content: string): string | Buffer;
+61
View File
@@ -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};`;
}
+51
View File
@@ -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 {