Compare commits

...

24 Commits

Author SHA1 Message Date
11bde9d756 1.1.42 2024-06-23 16:43:24 +02:00
eac26521c6 fix(aidoc_classes): Improve commit message generation by handling empty diffs and updating changelog instructions 2024-06-23 16:43:23 +02:00
e1323569f5 1.1.41 2024-06-23 13:49:15 +02:00
41e4bd6689 fix(aidoc_classes): Improve commit message generation by handling empty diffs and updating changelog instructions 2024-06-23 13:49:14 +02:00
164a58ec59 1.1.40 2024-06-23 13:04:48 +02:00
e1c0f82fe8 fix(core): update 2024-06-23 13:04:47 +02:00
8a0046818b 1.1.39 2024-06-23 12:38:58 +02:00
97fa9db32f fix(core): update 2024-06-23 12:38:58 +02:00
d61de9b615 1.1.38 2024-06-23 12:27:27 +02:00
fba54035ea fix(core): update 2024-06-23 12:27:26 +02:00
9a3d8588a8 1.1.37 2024-06-23 12:20:07 +02:00
eb8f8fa70a fix(core): update 2024-06-23 12:20:06 +02:00
afe7b5e99e 1.1.36 2024-06-23 12:11:07 +02:00
e074562362 fix(core): update 2024-06-23 12:11:06 +02:00
240d6bb314 1.1.35 2024-06-23 12:03:26 +02:00
2d0839a1da fix(core): update 2024-06-23 12:03:25 +02:00
9f250ae2b3 1.1.34 2024-06-23 11:59:39 +02:00
1223bb8567 fix(core): update 2024-06-23 11:59:38 +02:00
9395cfc166 1.1.33 2024-06-22 21:21:53 +02:00
3b4c6bd97f fix(core): update 2024-06-22 21:21:52 +02:00
5d2c9e6158 1.1.32 2024-06-22 19:13:58 +02:00
89977038ec fix(core): update 2024-06-22 19:13:57 +02:00
b753c206b0 1.1.31 2024-06-22 13:20:56 +02:00
1965bd9b47 fix(core): update 2024-06-22 13:20:55 +02:00
14 changed files with 147 additions and 67 deletions

4
changelog.md Normal file
View File

@ -0,0 +1,4 @@
# Changelog
## 1.1.41
- fix(aidoc_classes): Improve commit message generation by handling empty diffs and updating changelog instructions

View File

@ -1,12 +1,13 @@
{
"name": "@git.zone/tsdoc",
"version": "1.1.30",
"version": "1.1.42",
"private": false,
"description": "An advanced TypeScript documentation tool using AI to generate and enhance documentation for TypeScript projects.",
"main": "dist_ts/index.js",
"typings": "dist_ts/index.d.ts",
"type": "module",
"author": "Lossless GmbH",
"exports": {
".": "./dist_ts/index.js"
},
"author": "Task Venture Capital GmbH",
"license": "MIT",
"bin": {
"tsdoc": "cli.js"

View File

@ -1,4 +1,5 @@
# @git.zone/tsdoc
An advanced TypeScript documentation tool using AI to generate and enhance documentation for TypeScript projects.
## Install
@ -62,7 +63,7 @@ const tsconfigPath = plugins.path.join(__dirname, 'tsconfig.json');
const outputPath = plugins.path.join(__dirname, 'docs');
await plugins.smartshellInstance.exec(
`typedoc --tsconfig ${tsconfigPath} --out ${outputPath} index.ts`
`typedoc --tsconfig ${tsconfigPath} --out ${outputPath} index.ts`,
);
```
@ -243,7 +244,7 @@ import * as plugins from './plugins';
export const packageDir = plugins.path.join(
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
'../'
'../',
);
export const cwd = process.cwd();
export const binDir = plugins.path.join(packageDir, './node_modules/.bin');
@ -273,7 +274,7 @@ import { AiDoc } from './classes.aidoc';
export const run = async () => {
const tsdocCli = new plugins.smartcli.Smartcli();
tsdocCli.standardCommand().subscribe(async argvArg => {
tsdocCli.standardCommand().subscribe(async (argvArg) => {
switch (true) {
case await TypeDoc.isTypeDocDir(paths.cwd):
tsdocCli.triggerCommand('typedoc', argvArg);
@ -283,14 +284,14 @@ export const run = async () => {
}
});
tsdocCli.addCommand('typedoc').subscribe(async argvArg => {
tsdocCli.addCommand('typedoc').subscribe(async (argvArg) => {
const typeDocInstance = new TypeDoc(paths.cwd);
await typeDocInstance.compile({
publicSubdir: argvArg.publicSubdir
publicSubdir: argvArg.publicSubdir,
});
});
tsdocCli.addCommand('aidoc').subscribe(async argvArg => {
tsdocCli.addCommand('aidoc').subscribe(async (argvArg) => {
const aidocInstance = new AiDoc(argvArg);
await aidocInstance.start();
await aidocInstance.buildReadme(paths.cwd);

View File

@ -8,20 +8,32 @@ let aidocs: tsdocs.AiDoc;
tap.test('should create an AIdocs class', async () => {
aidocs = new tsdocs.AiDoc({
'OPENAI_TOKEN': await testQenv.getEnvVarOnDemand('OPENAI_TOKEN')
OPENAI_TOKEN: await testQenv.getEnvVarOnDemand('OPENAI_TOKEN'),
});
expect(aidocs).toBeInstanceOf(tsdocs.AiDoc);
});
tap.test('should start AIdocs', async () => {
await aidocs.start();
});
tap.skip.test('should start AIdocs', async () => {
await aidocs.buildReadme('./');
})
});
tap.test('should start AIdocs', async () => {
await aidocs.start();
tap.skip.test('should start AIdocs', async () => {
await aidocs.buildDescription('./');
})
});
tap.test('should build commit object', async () => {
const commitObject = await aidocs.buildNextCommitObject('./');
console.log(commitObject);
expect(commitObject).not.toBeUndefined();
expect(commitObject).toHaveProperty('recommendedNextVersion');
expect(commitObject).toHaveProperty('recommendedNextVersionLevel');
expect(commitObject).toHaveProperty('recommendedNextVersionScope');
expect(commitObject).toHaveProperty('recommendedNextVersionMessage');
})
tap.start();

View File

@ -1,8 +1,8 @@
/**
* autocreated commitinfo by @pushrocks/commitinfo
* autocreated commitinfo by @push.rocks/commitinfo
*/
export const commitinfo = {
name: '@git.zone/tsdoc',
version: '1.1.30',
version: '1.1.42',
description: 'An advanced TypeScript documentation tool using AI to generate and enhance documentation for TypeScript projects.'
}

View File

@ -2,6 +2,14 @@ import * as plugins from '../plugins.js';
import { AiDoc } from '../classes.aidoc.js';
import { ProjectContext } from './projectcontext.js';
export interface INextCommitObject {
recommendedNextVersionLevel: 'fix' | 'feat' | 'BREAKING CHANGE'; // the recommended next version level of the project
recommendedNextVersionScope: string; // the recommended scope name of the next version, like "core" or "cli", or specific class names.
recommendedNextVersionMessage: string; // the commit message. Don't put fix() feat() or BREAKING CHANGE in the message. Please just the message itself.
recommendedNextVersion: string; // the recommended next version of the project, x.x.x
changelog?: string; // the changelog for the next version
}
export class Commit {
private aiDocsRef: AiDoc;
private projectDir: string;
@ -11,9 +19,23 @@ export class Commit {
this.projectDir = projectDirArg;
}
public async build() {
public async buildNextCommitObject(): Promise<INextCommitObject> {
const smartgitInstance = new plugins.smartgit.Smartgit();
await smartgitInstance.init();
const gitRepo = await plugins.smartgit.GitRepo.fromOpeningRepoDir(
smartgitInstance,
this.projectDir
);
const diffString = await gitRepo.getUncommittedDiff();
const projectContext = new ProjectContext(this.projectDir);
const contextString = await projectContext.update();
let contextString = await projectContext.update();
contextString = `
${contextString}
Below is the diff of the uncommitted changes. If nothing is changed, there are no changes:
${diffString || 'No changes.'}
`;
let result = await this.aiDocsRef.openaiInstance.chat({
systemMessage: `
@ -28,9 +50,10 @@ Your answer should be parseable with JSON.parse() without modifying anything.
Here is the structure of the JSON you should return:
{
recommendedNextVersionLevel: 'patch' | 'minor' | 'major'; // the recommended next version level of the project
recommendedNextVersion: string; // the recommended next version of the project
message: string; // the commit message. use conventional commits format
recommendedNextVersionLevel: 'fix' | 'feat' | 'BREAKING CHANGE'; // the recommended next version level of the project
recommendedNextVersionScope: string; // the recommended scope name of the next version, like "core" or "cli", or specific class names.
recommendedNextVersionMessage: string; // the commit message. Don't put fix() feat() or BREAKING CHANGE in the message. Please just the message itself.
recommendedNextVersion: string; // the recommended next version of the project, x.x.x
}
You are being given the files of the project. You should use them to create the commit message.
@ -41,15 +64,51 @@ Also you are given a diff
userMessage: contextString,
});
console.log(result.message);
const resultObject = JSON.parse(result.message.replace('```json', '').replace('```', ''));
// console.log(result.message);
const resultObject: INextCommitObject = JSON.parse(
result.message.replace('```json', '').replace('```', '')
);
const npmextraJson = (await projectContext.gatherFiles()).smartfilesNpmextraJSON;
const npmextraJsonContent = JSON.parse(npmextraJson.contents.toString());
// lets build the changelog based on that
const commitMessages = await gitRepo.getAllCommitMessages();
const previousChangelogPath = plugins.path.join(this.projectDir, 'changelog.md');
let previousChangelog: plugins.smartfile.SmartFile;
if (await plugins.smartfile.fs.fileExists(previousChangelogPath)) {
previousChangelog = await plugins.smartfile.SmartFile.fromFilePath(previousChangelogPath);
}
let result2 = await this.aiDocsRef.openaiInstance.chat({
messageHistory: [],
systemMessage: `
You are building a changelog file for the projext.
Omit commits and versions that lack relevant changes.
npmextraJsonContent.gitzone.module.commit = resultObject.message;
You are given
* the previous changelog file (if available)
* the commit messages of the project
npmextraJson.contents = Buffer.from(JSON.stringify(npmextraJsonContent, null, 2));
await npmextraJson.write();
Only return the changelog file, so it can be written directly to changelog.md
For the latest version, that is not yet part of the commit messages, add a placeholder entry that uses {{nextVersion}} and {{nextVersionMessage}} as variables to filled later.
Only output newer versions and their changes compared to ones already mentioned. We take of appending your output later.
`,
userMessage: `
The previous changelog file is:
${!previousChangelog ? 'No previous changelog file found' : previousChangelog.contents.toString()}
Here are the commit messages so far:
${commitMessages.join('\n\n')}
`,
});
if (previousChangelog) {
let newChangelog = result2.message;
newChangelog = newChangelog.replace('# Changelog\n\n', '');
let oldChangelog = previousChangelog.contents.toString().replace('# Changelog\n\n', '');
newChangelog = `# Changelog\n\n${newChangelog}\n\n${oldChangelog}`;
resultObject.changelog = newChangelog;
} else {
resultObject.changelog = result2.message;
}
return resultObject;
}
}

View File

@ -45,7 +45,7 @@ Don't wrap the JSON in three ticks json!!!
console.log(result.message);
const resultObject: IDescriptionInterface = JSON.parse(
result.message.replace('```json', '').replace('```', '')
result.message.replace('```json', '').replace('```', ''),
);
const npmextraJson = (await projectContext.gatherFiles()).smartfilesNpmextraJSON;

View File

@ -1,3 +1,4 @@
export * from './commit.js';
export * from './description.js';
export * from './projectcontext.js';
export * from './readme.js';

View File

@ -13,28 +13,28 @@ export class ProjectContext {
public async gatherFiles() {
const smartfilePackageJSON = await plugins.smartfile.SmartFile.fromFilePath(
plugins.path.join(this.projectDir, 'package.json'),
this.projectDir
this.projectDir,
);
const smartfilesReadme = await plugins.smartfile.SmartFile.fromFilePath(
plugins.path.join(this.projectDir, 'readme.md'),
this.projectDir
this.projectDir,
);
const smartfilesReadmeHints = await plugins.smartfile.SmartFile.fromFilePath(
plugins.path.join(this.projectDir, 'readme.hints.md'),
this.projectDir
this.projectDir,
);
const smartfilesNpmextraJSON = await plugins.smartfile.SmartFile.fromFilePath(
plugins.path.join(this.projectDir, 'npmextra.json'),
this.projectDir
this.projectDir,
);
const smartfilesMod = await plugins.smartfile.fs.fileTreeToObject(
this.projectDir,
'ts*/**/*.ts'
'ts*/**/*.ts',
);
const smartfilesTest = await plugins.smartfile.fs.fileTreeToObject(
this.projectDir,
'test/**/*.ts'
'test/**/*.ts',
);
return {
smartfilePackageJSON,
@ -47,10 +47,10 @@ export class ProjectContext {
}
public async convertFilesToContext(filesArg: plugins.smartfile.SmartFile[]) {
console.log(`Using the following files for the documentation:`)
filesArg.map(fileArg => {
console.log(`Using the following files for the documentation:`);
filesArg.map((fileArg) => {
console.log(` -> ${fileArg.relative}`);
})
});
return filesArg
.map((smartfile) => {
return `

View File

@ -3,7 +3,6 @@ import * as plugins from '../plugins.js';
import { ProjectContext } from './projectcontext.js';
export class Readme {
// INSTANCE
private aiDocsRef: AiDoc;
private projectDir: string;
@ -21,8 +20,10 @@ export class Readme {
const contextString = await projectContext.update();
// lets first check legal before introducung any cost
const npmExtraJson = JSON.parse(((await projectContext.gatherFiles()).smartfilesNpmextraJSON).contents.toString());
const legalInfo = npmExtraJson?.tsdoc?.legal
const npmExtraJson = JSON.parse(
(await projectContext.gatherFiles()).smartfilesNpmextraJSON.contents.toString(),
);
const legalInfo = npmExtraJson?.tsdoc?.legal;
if (!legalInfo) {
const error = new Error(`No legal information found in npmextra.json`);
console.log(error);
@ -68,11 +69,8 @@ The Readme should follow the following template:
userMessage: contextString,
});
finalReadmeString += result.message + '\n' + legalInfo;
console.log(`\n======================\n`);
console.log(result.message);
console.log(`\n======================\n`);

View File

@ -7,7 +7,7 @@ export class AiDoc {
public npmextraKV: plugins.npmextra.KeyValueStore;
public qenvInstance: plugins.qenv.Qenv;
public smartinteractInstance: plugins.smartinteract.SmartInteract;
public aidocInteract: plugins.smartinteract.SmartInteract;
public openaiInstance: plugins.smartai.OpenAiProvider;
argvArg: any;
@ -33,7 +33,7 @@ export class AiDoc {
public async start() {
// lets care about prerequisites
this.smartinteractInstance = new plugins.smartinteract.SmartInteract();
this.aidocInteract = new plugins.smartinteract.SmartInteract();
this.qenvInstance = new plugins.qenv.Qenv();
if (!(await this.qenvInstance.getEnvVarOnDemand('OPENAI_TOKEN'))) {
this.npmextraKV = new plugins.npmextra.KeyValueStore({
@ -51,9 +51,9 @@ export class AiDoc {
// lets try smartinteract
// wait for a second until OpenAI fixes punycode problem...
await plugins.smartdelay.delayFor(1000);
const answerObject = await this.smartinteractInstance.askQuestion({
const answerObject = await this.aidocInteract.askQuestion({
type: 'input',
message: `Please provide your OpenAI token`,
message: `Please provide your OpenAI token. This will be persisted in your home directory.`,
name: 'OPENAI_TOKEN',
default: '',
});
@ -85,8 +85,9 @@ export class AiDoc {
return await descriptionInstance.build();
}
public async buildNextCommit(projectDirArg: string) {
public async buildNextCommitObject(projectDirArg: string) {
const commitInstance = new aiDocsClasses.Commit(this, projectDirArg);
return await commitInstance.buildNextCommitObject();
}
public async getProjectContext(projectDirArg: string) {

View File

@ -20,15 +20,15 @@ export class TypeDoc {
public async compile(options?: { publicSubdir?: string }) {
const data = {
"compilerOptions": {
"experimentalDecorators": true,
"useDefineForClassFields": false,
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true,
compilerOptions: {
experimentalDecorators: true,
useDefineForClassFields: false,
target: 'ES2022',
module: 'NodeNext',
moduleResolution: 'NodeNext',
esModuleInterop: true,
verbatimModuleSyntax: true,
skipLibCheck: true,
},
include: [],
};
@ -51,7 +51,7 @@ export class TypeDoc {
targetDir = plugins.path.join(targetDir, options.publicSubdir);
}
await this.smartshellInstance.exec(
`typedoc --tsconfig ${paths.tsconfigFile} --out ${targetDir} ${startDirectory}/index.ts`
`typedoc --tsconfig ${paths.tsconfigFile} --out ${targetDir} ${startDirectory}/index.ts`,
);
plugins.smartfile.fs.remove(paths.tsconfigFile);
}

View File

@ -36,7 +36,7 @@ export const run = async () => {
logger.log('info', `Generating new keywords...`);
logger.log('info', `This may take some time...`);
aidocInstance.buildDescription(paths.cwd);
})
});
tsdocCli.addCommand('test').subscribe((argvArg) => {
tsdocCli.triggerCommand('typedoc', argvArg);

View File

@ -1,7 +1,10 @@
import * as plugins from './plugins.js';
// dirs
export const packageDir = plugins.path.join(plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url), '../');
export const packageDir = plugins.path.join(
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
'../',
);
export const cwd = process.cwd();
export const binDir = plugins.path.join(packageDir, './node_modules/.bin');
export const assetsDir = plugins.path.join(packageDir, './assets');