140 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
			
		
		
	
	
			140 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
| /*
 | |
|  * Copyright 2025 coze-dev Authors
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
|  
 | |
| import path from 'path';
 | |
| 
 | |
| import {
 | |
|   Project,
 | |
|   SyntaxKind,
 | |
|   PropertyAssignment,
 | |
|   ShorthandPropertyAssignment,
 | |
|   SpreadAssignment,
 | |
|   VariableDeclarationKind,
 | |
|   TypeFormatFlags,
 | |
|   type VariableDeclarationStructure,
 | |
|   type OptionalKind,
 | |
| } from 'ts-morph';
 | |
| 
 | |
| interface TUpdateDTSParams {
 | |
|   inputFileName: string;
 | |
|   envVarName: string;
 | |
|   outputFileName: string;
 | |
| }
 | |
| 
 | |
| const updateDTS = ({
 | |
|   inputFileName,
 | |
|   envVarName,
 | |
|   outputFileName,
 | |
| }: TUpdateDTSParams) => {
 | |
|   // 初始化一个 ts-morph 项目
 | |
|   const project = new Project({
 | |
|     compilerOptions: {
 | |
|       incremental: true,
 | |
|       allowJs: false,
 | |
|       skipLibCheck: true,
 | |
|       strictNullChecks: true,
 | |
|       noEmitOnError: true,
 | |
|     },
 | |
|   });
 | |
|   // 添加想要解析的文件
 | |
|   const file = project.addSourceFileAtPath(inputFileName);
 | |
| 
 | |
|   // 获取你想要解析的变量
 | |
|   const envs = file.getVariableDeclarationOrThrow(envVarName);
 | |
|   // 获取 envs 变量的初始值
 | |
|   const initializer = envs.getInitializerIfKindOrThrow(
 | |
|     SyntaxKind.ObjectLiteralExpression,
 | |
|   );
 | |
|   // 获取 envs 对象的属性
 | |
|   const properties = initializer.getProperties();
 | |
| 
 | |
|   const baseDir = path.resolve(__dirname, '../');
 | |
|   // 创建一个新的文件,用来保存生成的类型定义
 | |
|   const typeDefs = project.createSourceFile(
 | |
|     outputFileName,
 | |
|     `/* eslint-disable */
 | |
| /* prettier-ignore */
 | |
| // 基于${path.relative(baseDir, inputFileName)}自动生成,请勿手动修改`,
 | |
|     {
 | |
|       overwrite: true,
 | |
|     },
 | |
|   );
 | |
| 
 | |
|   const declarations: OptionalKind<VariableDeclarationStructure>[] = [];
 | |
| 
 | |
|   const addDeclaration = (name: string, type: string) => {
 | |
|     declarations.push({
 | |
|       name,
 | |
|       type,
 | |
|     });
 | |
|   };
 | |
| 
 | |
|   // 遍历每一个属性
 | |
|   properties.forEach(property => {
 | |
|     if (
 | |
|       property instanceof PropertyAssignment ||
 | |
|       property instanceof ShorthandPropertyAssignment
 | |
|     ) {
 | |
|       addDeclaration(property.getName(), property.getType().getText());
 | |
|     } else if (property instanceof SpreadAssignment) {
 | |
|       const expression = property.getExpression();
 | |
|       const type = expression.getType();
 | |
| 
 | |
|       if (type.isObject()) {
 | |
|         // 如果类型是一个对象类型,获取其属性
 | |
|         const spreadProperties = type.getProperties();
 | |
|         // 遍历属性
 | |
|         for (const spreadProperty of spreadProperties) {
 | |
|           const declaration = spreadProperty.getDeclarations()?.[0];
 | |
|           if (declaration) {
 | |
|             addDeclaration(
 | |
|               spreadProperty.getName(),
 | |
|               declaration
 | |
|                 .getType()
 | |
|                 .getText(
 | |
|                   undefined,
 | |
|                   TypeFormatFlags.UseSingleQuotesForStringLiteralType,
 | |
|                 ),
 | |
|             );
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   });
 | |
|   // 保存文件
 | |
|   typeDefs.addVariableStatements(
 | |
|     declarations
 | |
|       .sort((a, b) => (a.name > b.name ? 1 : -1))
 | |
|       .map(d => ({
 | |
|         declarationKind: VariableDeclarationKind.Const,
 | |
|         hasDeclareKeyword: true,
 | |
|         declarations: [d],
 | |
|       })),
 | |
|   );
 | |
|   typeDefs.saveSync();
 | |
| };
 | |
| 
 | |
| export const build = () => {
 | |
|   const start = Date.now();
 | |
|   const root = path.resolve(__dirname, '../src');
 | |
|   updateDTS({
 | |
|     inputFileName: path.resolve(root, 'index.ts'),
 | |
|     envVarName: 'envs',
 | |
|     outputFileName: path.resolve(root, 'typings.d.ts'),
 | |
|   });
 | |
|   console.info(`DTS generated in  ${Date.now() - start} ms`);
 | |
| };
 |