Asper Header  1.0.22
The header injector extension
Loading...
Searching...
No Matches
commentGenerator.ts
Go to the documentation of this file.
1
60import * as vscode from 'vscode';
61import { minimatch } from 'minimatch';
62import { CodeConfig, CodeConfigType } from './processConfiguration';
63import { query } from './querier';
64import { logger } from './logger';
65import { getMessage } from './messageProvider';
66import { LazyFileLoader } from './lazyFileLoad';
67import { RandomLogo, logo } from './randomLogo';
68
76interface CommentStyle {
78 singleLine: string[];
80 multiLine: string[];
82 prompt_comment_opening_type: boolean;
84 language?: string;
85}
86
138export class CommentGenerator {
140 private Config: CodeConfigType = CodeConfig;
142 private randomLogo: RandomLogo = new RandomLogo();
144 private languageComment: LazyFileLoader | undefined = undefined;
146 private documentBody: vscode.TextDocument | undefined = undefined;
148 private filePath: string | undefined = undefined;
150 private fileName: string | undefined = undefined;
152 private fileExtension: string | undefined = undefined;
154 private languageId: string | undefined = undefined;
156 private documentEOL: vscode.EndOfLine | undefined = undefined;
158 private documentVersion: number | undefined = undefined;
160 private headerInnerStart: number | undefined = undefined;
162 private headerInnerEnd: number | undefined = undefined;
164 private maxScanLength: number = this.Config.get("maxScanLength");
166 private headerLogo: string[] = this.Config.get("headerLogo");
172 private headerLogoVersions: Record<string, string[]> = this.Config.get("headerLogoVersions");
179 private useHeaderLogoVersion: boolean = this.Config.get("useHeaderLogoVersion");
185 private headerLogoVersionReference: string = this.Config.get("headerLogoVersionReference");
187 private projectName: string = this.Config.get("extensionName");
189 private projectCopyRight: string = this.Config.get("projectCopyright");
191 private addBlankLineAfterMultiline: boolean = this.Config.get("headerAddBlankLineAfterMultiline");
193 private languagePrepend: Record<string, string> = this.Config.get("languagePrepend");
195 private languageAppend: Record<string, string> = this.Config.get("languageAppend");
197 private singleLineOverride: Record<string, string> = this.Config.get("languageSingleLineComment");
199 private multiLineOverride: Record<string, string[]> = this.Config.get("languageMultiLineComment");
201 private trimTrailingSpaces: boolean = this.Config.get("removeTrailingHeaderSpaces");
203 private preferSingleLineComments: boolean = this.Config.get("preferSingleLineComments");
204
214 constructor(languageComment: LazyFileLoader | undefined = undefined, editor: vscode.TextEditor | undefined = undefined, randomLogoInstance: RandomLogo | undefined = undefined) {
215 logger.debug(getMessage("inFunction", "constructor", "CommentGenerator"));
216 if (languageComment !== undefined) {
217 this.languageComment = languageComment;
218 logger.debug(getMessage("foundLanguageComment"));
219 } else {
220 logger.warning(getMessage("missingLanguageComment"));
221 }
222 if (!editor) {
223 logger.warning(getMessage("noFocusedEditors"));
224 } else {
225 this.updateFileInfo(editor.document);
226 logger.debug(getMessage("foundFocusEditor"));
227 }
228 if (!randomLogoInstance) {
229 logger.warning(getMessage("noLogoInstanceProvided"));
230 } else {
231 this.randomLogo = randomLogoInstance;
232 logger.debug(getMessage("foundLogoInstance"));
233 }
234 }
235
244 private determineNewLine(eol: vscode.EndOfLine): string {
245 logger.debug(getMessage("inFunction", "determineNewLine", "CommentGenerator"));
246 if (eol === vscode.EndOfLine.LF) {
247 logger.debug(getMessage("foundNewLine", "\\n"));
248 return "\n";
249 } else {
250 logger.debug(getMessage("foundNewLine", "\\r\\n"));
251 return "\r\n";
252 }
253 }
254
265 private headerOpener(comment: string, eol: vscode.EndOfLine, projectName: string = this.Config.get("extensionName")): string {
266 logger.debug(getMessage("inFunction", "headerOpener", "CommentGenerator"));
267 let final: string = comment + this.Config.get("headerOpenerDecorationOpen");
268 final += this.Config.get("telegraphBegin") + " ";
269 final += projectName;
270 final += this.Config.get("headerOpenerDecorationClose");
271 final += this.determineNewLine(eol);
272 return final;
273 }
274
283 private async determineCorrectComment(): Promise<CommentStyle> {
284 logger.debug(getMessage("inFunction", "determineCorrectComment", "CommentGenerator"));
285 const primaryKey: string = "langs";
286 let commentStructure: CommentStyle = {
287 singleLine: [],
288 multiLine: [],
289 prompt_comment_opening_type: false,
290 language: undefined,
291 };
292 if (this.languageComment === undefined) {
293 logger.Gui.error(getMessage("missingFileError"));
294 return commentStructure;
295 }
296 const jsonContent = await this.languageComment?.get();
297 // logger.info(getMessage("jsonContent", JSON.stringify(jsonContent)));
298 if (!jsonContent || typeof jsonContent !== 'object' || jsonContent === null || (primaryKey in jsonContent) === false) {
299 logger.Gui.error(getMessage("unknownFileStructure"));
300 return commentStructure;
301 }
302 if (Array.isArray(jsonContent[primaryKey]) === false) {
303 logger.Gui.error(getMessage("unknownFileStructure"));
304 return commentStructure;
305 }
306 let index = 0;
307 const languageNodes = jsonContent[primaryKey];
308 let locatedName: string = "";
309 for (; index < languageNodes.length; index++) {
310 let nodeFound = false;
311 const node = languageNodes[index];
312
313 const nodeLangs: string[] = node.langs ?? [];
314 const nodeFileExtensions: Record<string, string[]> = node.fileExtensions ?? {};
315
316 for (let langIndex = 0; langIndex < nodeLangs.length; langIndex++) {
317 const langName = nodeLangs[langIndex].toLowerCase();
318 locatedName = langName;
319
320 if (langName === this.languageId?.toLowerCase()) {
321 nodeFound = true;
322 break;
323 }
324
325 if (this.fileExtension) {
326 const extensionsForLang = nodeFileExtensions[langName] ?? [];
327 for (let extIndex = 0; extIndex < extensionsForLang.length; extIndex++) {
328 let dot: string = "";
329 if (extensionsForLang[extIndex].length > 0 && extensionsForLang[extIndex][0] === ".") {
330 dot = ".";
331 }
332 if (extensionsForLang[extIndex] === `${dot}${this.fileExtension}`) {
333 nodeFound = true;
334 break;
335 }
336 }
337 }
338
339 if (nodeFound) {
340 break;
341 }
342 }
343
344 logger.debug(getMessage("arrayNodeContent", `Json[${primaryKey}]`, index, node));
345 if (nodeFound) {
346 logger.Gui.info(getMessage("identifiedLanguage", locatedName));
347 logger.info(getMessage("arrayNodeContent", `Json[${primaryKey}]`, index, node));
348 commentStructure.singleLine = node.singleLine ?? [];
349 commentStructure.multiLine = node.multiLine ?? [];
350 commentStructure.prompt_comment_opening_type = node.prompt_comment_opening_type ?? false;
351 commentStructure.language = locatedName ?? undefined;
352 return commentStructure;
353 }
354 }
355 logger.error(getMessage("languageNotFound", String(this.languageId), this.fileExtension));
356 return commentStructure;
357 }
358
366 private async determineHeaderDescription(): Promise<string[]> {
367 logger.debug(getMessage("inFunction", "determineHeaderDescription", "CommentGenerator"));
368 const rawAny = this.Config.get("projectDescription");
369 let intermediate: string = "";
370 if (Array.isArray(rawAny)) {
371 intermediate = rawAny.join(this.determineNewLine(this.documentEOL || vscode.EndOfLine.LF));
372 } else {
373 intermediate = String(rawAny ?? "");
374 }
375 if (intermediate.trim().length === 0) {
376 const usrResponse: string | undefined = await query.input(getMessage("getHeaderDescription"));
377 intermediate = (usrResponse || "");
378 } else {
379 logger.debug(getMessage("configDescriptionUsed"));
380 }
381 const final = intermediate.split(/\r?\n/);
382 return final;
383 }
384
392 private async determineHeaderTags(): Promise<string[]> {
393 logger.debug(getMessage("inFunction", "determineHeaderTags", "CommentGenerator"));
394 let final: string[] = [];
395 const usrResponse: string | undefined = await query.input(getMessage("getHeaderTags"));
396 final.push(usrResponse || "");
397 return final;
398 }
399
407 private async determineHeaderPurpose(): Promise<string[]> {
408 logger.debug(getMessage("inFunction", "determineHeaderPurpose", "CommentGenerator"));
409 let final: string[] = [];
410 const usrResponse: string | undefined = await query.input(getMessage("getHeaderPurpose"));
411 final.push(usrResponse || "");
412 return final;
413 }
414
425 private async getSingleCommentOption(commentOptions: string[]): Promise<string> {
426 logger.debug(getMessage("inFunction", "getSingleCommentOption", "CommentGenerator"));
427 if (commentOptions.length === 0) {
428 logger.Gui.error(getMessage("noCommentToShow"));
429 throw Error(getMessage("noCommentToShow"));
430 }
431 if (commentOptions.length === 1) {
432 logger.info(getMessage("noProvidedCommentOptions"));
433 return commentOptions[0];
434 }
435 const response: string | undefined = await query.quickPick(commentOptions, getMessage("chooseSingleLineCommentOption"));
436 return response || commentOptions[0];
437 }
438
446 private addKeyDefinitionSeparator(): string {
447 logger.debug(getMessage("inFunction", "addKeyDefinitionSeparator", "CommentGenerator"));
448 const userSettingDefinedElement: string = this.Config.get("headerKeyDefinitionSeparator");
449 return userSettingDefinedElement || this.Config.get("headerKeyDefinitionSeparator");
450 }
451
461 private addCreationDate(comment: string, eol: vscode.EndOfLine) {
462 logger.debug(getMessage("inFunction", "addCreationDate", "CommentGenerator"));
463 const now = new Date();
464 const day = String(now.getDate()).padStart(2, "0");
465 const month = String(now.getMonth() + 1).padStart(2, "0"); // Months are 0-based
466 const year = now.getFullYear();
467 const separatorDay: string = this.Config.get("headerDateSeperatorDay");
468 const separatorMonth: string = this.Config.get("headerDateSeperatorMonth");
469 const separatorYear: string = this.Config.get("headerDateSeperatorYear");
470 let final: string = comment + this.Config.get("headerCreationDateKey") + this.addKeyDefinitionSeparator();
471 final += `${day}${separatorDay}${month}${separatorMonth}${year}${separatorYear}`;
472 final += this.determineNewLine(eol);
473 return final;
474 }
475
486 private addLastModifiedDate(comment: string, eol: vscode.EndOfLine) {
487 logger.debug(getMessage("inFunction", "addLastModifiedDate", "CommentGenerator"));
488 const now: Date = new Date();
489 const day: string = String(now.getDate()).padStart(2, "0");
490 const month: string = String(now.getMonth() + 1).padStart(2, "0"); // Months are 0-based
491 const year: number = now.getFullYear();
492 const hour: number = now.getHours();
493 const minute: number = now.getMinutes();
494 const seconds: number = now.getSeconds();
495 const separatorDay: string = this.Config.get("headerDateSeperatorDay");
496 const separatorMonth: string = this.Config.get("headerDateSeperatorMonth");
497 const separatorYear: string = this.Config.get("headerDateSeperatorYear");
498 const separatorTimeAndDate: string = this.Config.get("headerTimeAndDateSeperator");
499 const separatorSecond: string = this.Config.get("headerTimeSeperatorSecond");
500 const separatorMinute: string = this.Config.get("headerTimeSeperatorMinute");
501 const separatorHour: string = this.Config.get("headerTimeSeperatorHour");
502 let final: string = comment + this.Config.get("headerLastModifiedKey") + this.addKeyDefinitionSeparator();
503 final += `${hour}${separatorHour}${minute}${separatorMinute}${seconds}${separatorSecond}${separatorTimeAndDate}${day}${separatorDay}${month}${separatorMonth}${year}${separatorYear}`;
504 final += this.determineNewLine(eol);
505 return final;
506 }
507
517 private mySmartTrimmer(content: string): string {
518 if (this.trimTrailingSpaces) {
519 return content.trimEnd();
520 }
521 return content;
522 }
523
536 private addMultilineKey(comment: string, eol: vscode.EndOfLine, tagName: string, tagDefinition: string[]): string {
537 logger.debug(getMessage("inFunction", "addMultilineKey", "CommentGenerator"));
538 const eolStr: string = this.determineNewLine(eol);
539 const keyLine: string = comment + tagName + this.mySmartTrimmer(this.addKeyDefinitionSeparator()) + eolStr;
540 let final: string = keyLine;
541 for (let i = 0; i < tagDefinition.length; i++) {
542 final += comment + tagDefinition[i] + eolStr;
543 }
544 final += comment + this.Config.get("telegraphBlockStop") + eolStr;
545 if (this.addBlankLineAfterMultiline) {
546 final += comment + eolStr;
547 }
548 return final;
549 }
550
561 private addSingleLineKey(comment: string, eol: vscode.EndOfLine, tagName: string, tagDefinition: string): string {
562 logger.debug(getMessage("inFunction", "addSingleLineKey", "CommentGenerator"));
563 let final: string = comment + tagName + this.addKeyDefinitionSeparator();
564 final += tagDefinition + this.determineNewLine(eol);
565 return final;
566 }
567
577 private beforeHeaderCloser(comment: string, eol: vscode.EndOfLine): string {
578 logger.debug(getMessage("inFunction", "beforeHeaderCloser", "CommentGenerator"));
579 return comment + this.Config.get("telegraphEndOfTransmission") + this.determineNewLine(eol);
580 }
581
592 private headerCloser(comment: string, eol: vscode.EndOfLine, projectName: string = this.Config.get("extensionName")): string {
593 logger.debug(getMessage("inFunction", "headerCloser", "CommentGenerator"));
594 let final: string = comment + this.Config.get("headerOpenerDecorationOpen");
595 final += this.Config.get("telegraphEnd") + " ";
596 final += projectName;
597 final += this.Config.get("headerOpenerDecorationClose");
598 final += this.determineNewLine(eol);
599 return final;
600 }
601
610 private updateFileInfo(document: vscode.TextDocument) {
611 logger.debug(getMessage("inFunction", "updateFileInfo", "CommentGenerator"));
612 this.headerInnerEnd = undefined;
613 this.headerInnerStart = undefined;
614 this.documentBody = document;
615 // Refresh all configuration-derived caches dynamically so user settings changes apply without reload (1.0.22)
616 this.headerLogo = this.Config.get("headerLogo");
617 this.headerLogoVersions = this.Config.get("headerLogoVersions");
618 this.useHeaderLogoVersion = this.Config.get("useHeaderLogoVersion");
619 this.headerLogoVersionReference = this.Config.get("headerLogoVersionReference");
620 this.languagePrepend = this.Config.get("languagePrepend");
621 this.languageAppend = this.Config.get("languageAppend");
622 this.singleLineOverride = this.Config.get("languageSingleLineComment");
623 this.multiLineOverride = this.Config.get("languageMultiLineComment");
624 this.trimTrailingSpaces = this.Config.get("removeTrailingHeaderSpaces");
625 this.preferSingleLineComments = this.Config.get("preferSingleLineComments");
626 if (this.Config.get("useWorkspaceNameWhenAvailable")) {
627 this.projectName = this.Config.get("workspaceName") || this.Config.get("extensionName");
628 } else {
629 this.projectName = this.Config.get("extensionName");
630 }
631 this.filePath = this.documentBody.uri.fsPath;
632 this.projectCopyRight = this.Config.get("projectCopyright");
633 this.addBlankLineAfterMultiline = this.Config.get("headerAddBlankLineAfterMultiline");
634 // Dynamic scan budget: base maxScanLength (user-configurable, fallback to defaultMaxScanLength via processConfiguration) + current logo height
635 const baseScanLength: number = this.Config.get("maxScanLength");
636 this.maxScanLength = baseScanLength;
637 if (this.useHeaderLogoVersion) {
639 logger.debug(getMessage("headerLogoReference", this.headerLogoVersionReference));
640 this.maxScanLength += this.headerLogoVersions[this.headerLogoVersionReference].length;
641 } else {
642 logger.error(getMessage("headerLogoReferenceNotFound", this.headerLogoVersionReference));
643 }
644 } else {
645 logger.debug(getMessage("headerLogoVersionDisabled"));
646 this.maxScanLength += this.headerLogo.length;
647 }
648 this.fileName = this.documentBody.uri.path.split('/').pop() || "unknown";
649 if (this.fileName.includes('.')) {
650 this.fileExtension = this.fileName.split('.').pop() || "none";
651 } else {
652 this.fileExtension = "none";
653 };
654 this.languageId = this.documentBody.languageId;
655 this.documentEOL = this.documentBody.eol;
656 this.documentVersion = this.documentBody.version;
657 }
658
675 private prependIfPresent(buildHeader: string[], eol: vscode.EndOfLine, languageId?: string): string[] {
676 if (languageId === undefined) {
677 return buildHeader;
678 }
679 const instance = this.languagePrepend[languageId];
680 if (instance !== undefined) {
681 let instanceCleaned: string = instance;
682 if (Array.isArray(instance)) {
683 instanceCleaned = instance.join(this.determineNewLine(eol));
684 }
685 buildHeader.push(instanceCleaned);
686 logger.debug(getMessage("languagePrependApplied", languageId, instanceCleaned));
687 }
688 return buildHeader;
689 }
690
708 private appendIfPresent(buildHeader: string[], eol: vscode.EndOfLine, languageId?: string): string[] {
709 if (languageId === undefined) {
710 return buildHeader;
711 }
712 const instance = this.languageAppend[languageId];
713 if (instance !== undefined) {
714 let instanceCleaned: string = instance;
715 if (Array.isArray(instance)) {
716 instanceCleaned = instance.join(this.determineNewLine(eol));
717 }
718 buildHeader.push(instanceCleaned);
719 logger.debug(getMessage("languageAppendApplied", languageId, instanceCleaned));
720 }
721 return buildHeader;
722 }
723
746 private getOverrideIfPresent(determinedComment: CommentStyle): CommentStyle {
747 // If the language is not known, nothing to override
748 if (!determinedComment.language) {
749 return determinedComment;
750 }
751
752 const languageId = determinedComment.language;
753
754 // Apply single-line override if present
755 const singleOverride = this.singleLineOverride[languageId];
756 if (singleOverride !== undefined) {
757 // Wrap the single string into an array since CommentStyle.singleLine expects string[]
758 if (Array.isArray(singleOverride)) {
759 determinedComment.singleLine = singleOverride;
760 } else {
761 determinedComment.singleLine = [singleOverride];
762 }
763 logger.debug(getMessage("singleLineCommentOverrideApplied", languageId, determinedComment.singleLine));
764 }
765
766 // Apply multi-line override if present
767 const multiOverride = this.multiLineOverride[languageId];
768 if (multiOverride !== undefined) {
769 // multiOverride is already a string[]
770 determinedComment.multiLine = multiOverride;
771 logger.debug(getMessage("multiLineCommentOverrideApplied", languageId, determinedComment.multiLine));
772 }
773
774 return determinedComment;
775 }
785 private async getCorrectCommentPrefix(determinedComment: CommentStyle): Promise<string[]> {
786 logger.debug(getMessage("inFunction", "getCorrectPrefix", "CommentGenerator"));
787 let commentOpener: string = "";
788 let commentMiddle: string = "";
789 let commentCloser: string = "";
790 const determinedComment_checked: CommentStyle = this.getOverrideIfPresent(determinedComment);
791 if (determinedComment_checked.multiLine.length >= 2 && this.preferSingleLineComments === false) {
792 commentOpener = determinedComment_checked.multiLine[0];
793 if (determinedComment_checked.multiLine.length >= 3) {
794 commentMiddle = determinedComment_checked.multiLine[1];
795 commentCloser = determinedComment_checked.multiLine[2];
796 } else {
797 commentMiddle = "";
798 commentCloser = determinedComment_checked.multiLine[1];
799 }
800 } else if (determinedComment_checked.singleLine.length > 0) {
801 if (determinedComment_checked.prompt_comment_opening_type) {
802 // Ask the user for the type to use based on the single comments that are present.
803 const commentString: string = await this.getSingleCommentOption(determinedComment_checked.singleLine);
804 commentOpener = commentString;
805 commentMiddle = commentString;
806 commentCloser = commentString;
807 } else {
808 commentOpener = determinedComment_checked.singleLine[0];
809 commentMiddle = determinedComment_checked.singleLine[0];
810 commentCloser = determinedComment_checked.singleLine[0];
811 }
812 } else {
813 commentOpener = "";
814 commentMiddle = "";
815 commentCloser = "";
816 }
817 commentOpener += this.Config.get("headerCommentSpacing");
818 commentMiddle += this.Config.get("headerCommentSpacing");
819 commentCloser += this.Config.get("headerCommentSpacing");
820
821 return [commentOpener, commentMiddle, commentCloser];
822 }
823
839 private async buildTheHeader(comments: string[], languageId?: string): Promise<string[]> {
840 logger.debug(getMessage("inFunction", "buildTheHeader", "CommentGenerator"));
841 const eol: vscode.EndOfLine = this.documentEOL || vscode.EndOfLine.LF;
842 const unknownTerm: string = getMessage("unknown");
843 const commentOpener: string = comments[0] || "";
844 const commentMiddle: string = comments[1] || "";
845 const commentCloser: string = comments[2] || "";
846 let buildHeader: string[] = [];
847 // Check wether there are elements required to be added before the header
848 buildHeader = this.prependIfPresent(buildHeader, eol, languageId);
849 // Preparing the header content so that it can be put in a comment and written.
850 if (commentOpener.length > 0) {
851 buildHeader.push(`${this.mySmartTrimmer(commentOpener)}${this.determineNewLine(eol)}`);
852 }
853 // Opening the header
854 buildHeader.push(this.headerOpener(commentMiddle, eol, this.projectName));
855 // The logo - fully dynamic (1.0.22): read fresh config so settings changes apply without reload
856 const freshLogo: string[] = this.Config.get("headerLogo");
857 const freshVersions: Record<string, string[]> = this.Config.get("headerLogoVersions");
858 const freshUseVersion: boolean = this.Config.get("useHeaderLogoVersion");
859 const freshRef: string = this.Config.get("headerLogoVersionReference");
860 // Keep caches in sync for callers that read them directly
861 this.headerLogo = freshLogo;
862 this.headerLogoVersions = freshVersions;
863 this.useHeaderLogoVersion = freshUseVersion;
864 this.headerLogoVersionReference = freshRef;
865 let logoContent = freshLogo;
866 if (this.Config.get("randomLogo") === true) {
867 try {
868 const gatheredLogo: logo = await this.randomLogo.getRandomLogoFromFolder();
869 if (gatheredLogo.logoContent !== undefined) {
870 logoContent = gatheredLogo.logoContent;
871 } else {
872 logger.error(getMessage("randomLogoGatheringFailed", getMessage("ramdomLogoGatheringLogoUndefined")));
873 }
874 } catch (e) {
875 logger.error(getMessage("randomLogoGatheringFailed", String(e)));
876 }
877 } else if (freshUseVersion === true) {
878 if (freshRef in freshVersions) {
879 logger.debug(getMessage("headerLogoReference", freshRef));
880 logoContent = freshVersions[freshRef];
881 } else {
882 logger.error(getMessage("headerLogoReferenceNotFound", freshRef));
883 logger.Gui.error(getMessage("headerLogoReferenceNotFoundGUI", freshRef));
884 }
885 }
886 buildHeader.push(this.addMultilineKey(commentMiddle, eol, this.Config.get("headerLogoKey"), logoContent));
887 // The project name
888 buildHeader.push(this.addSingleLineKey(commentMiddle, eol, this.Config.get("headerProjectKey"), this.projectName));
889 // The file name
890 buildHeader.push(this.addSingleLineKey(commentMiddle, eol, this.Config.get("headerFileKey"), this.fileName || unknownTerm));
891 // The Creation date
892 buildHeader.push(this.addCreationDate(commentMiddle, eol));
893 // The Last modified date
894 buildHeader.push(this.addLastModifiedDate(commentMiddle, eol));
895 // The description
896 buildHeader.push(this.addMultilineKey(commentMiddle, eol, this.Config.get("headerDescriptionKey"), await this.determineHeaderDescription()));
897 // The copyright
898 buildHeader.push(this.addSingleLineKey(commentMiddle, eol, this.Config.get("headerCopyrightKey"), this.projectCopyRight));
899 // The Tag
900 // buildHeader.push(this.addSingleLineKey(commentMiddle, eol, this.Config.get("headerTagKey"), (await this.determineHeaderTags()).join(",")));
901 // The Purpose
902 buildHeader.push(this.addSingleLineKey(commentMiddle, eol, this.Config.get("headerPurposeKey"), (await this.determineHeaderPurpose()).join(";")));
903 // End of transmission telegraph
904 buildHeader.push(this.beforeHeaderCloser(commentMiddle, eol));
905 // Closing the header
906 buildHeader.push(this.headerCloser(commentMiddle, eol, this.projectName));
907 if (commentCloser.length > 0) {
908 buildHeader.push(`${commentCloser}${this.determineNewLine(eol)}`);
909 }
910 // Check wether there are elements required to be added after the header
911 buildHeader = this.appendIfPresent(buildHeader, eol, languageId);
912 return buildHeader;
913 }
914
924 private async updateEditDate(document: vscode.TextDocument, comments: string[]) {
925 logger.debug(getMessage("inFunction", "updateEditDate", "CommentGenerator"));
926 const commentOpener: string = comments[0] || "";
927 const commentMiddle: string = comments[1] || "";
928 const commentCloser: string = comments[2] || "";
929 if (this.headerInnerStart === undefined || this.headerInnerEnd === undefined) {
930 const errMsg: string = getMessage("updateEditDateMissingBounds");
931 logger.error(errMsg);
932 logger.Gui.error(errMsg);
933 return;
934 }
935 if (!this.documentBody) {
936 const errMsg: string = getMessage("emptyDocument");
937 logger.error(errMsg);
938 logger.Gui.error(errMsg);
939 return;
940 }
941
942 const eol = this.documentEOL || vscode.EndOfLine.LF;
943 const lastModifiedKey = this.Config.get("headerLastModifiedKey");
944
945 // Build the new "Last Modified" line
946 const newLine = this.addLastModifiedDate(commentMiddle, eol).trimEnd();
947
948 let targetLine: number | undefined = undefined;
949
950 // Scan header block to locate the "Last Modified" line
951 for (let i = this.headerInnerStart; i <= this.headerInnerEnd; i++) {
952 const lineText = this.documentBody.lineAt(i).text;
953 if (lineText.includes(lastModifiedKey)) {
954 targetLine = i;
955 break;
956 }
957 }
958
959 if (targetLine === undefined) {
960 const errMsg: string = getMessage("lastModifiedLineNotFound");
961 logger.error(errMsg);
962 logger.Gui.error(errMsg);
963 return;
964 }
965
966 const edit = new vscode.WorkspaceEdit();
967 const range = document.lineAt(targetLine).range;
968 edit.replace(document.uri, range, newLine);
969 await vscode.workspace.applyEdit(edit);
970
971 const msg: string = getMessage("lastModifiedUpdated");
972 logger.info(msg);
973 logger.Gui.info(msg);
974 }
975
985 protected locateIfHeaderPresent(comments: string[]): boolean | undefined {
986 logger.debug(getMessage("inFunction", "locateIfHeaderPresent", "CommentGenerator"));
987 const commentOpener: string = comments[0] || "";
988 const commentMiddle: string = comments[1] || "";
989 const commentCloser: string = comments[2] || "";
990 this.headerInnerStart = undefined;
991 this.headerInnerEnd = undefined;
992 if (this.documentBody === undefined) {
993 logger.error(getMessage("emptyDocument"));
994 return undefined;
995 }
996 if (this.documentBody.isClosed) {
997 logger.warning(getMessage("closedDocument"));
998 return undefined;
999 }
1000 const documentTotalLines: number = this.documentBody.lineCount;
1001 const eol: vscode.EndOfLine = this.documentEOL ?? vscode.EndOfLine.LF;
1002 const opener: string = this.headerOpener(commentMiddle, eol, this.projectName).trimEnd();
1003 const closer: string = this.headerCloser(commentMiddle, eol, this.projectName).trimEnd();
1004 const scanLines: number = Math.min(this.maxScanLength, documentTotalLines);
1005 const graceLines: number = Math.min((this.maxScanLength * 2), documentTotalLines);
1006 let lineOpenerFound: boolean = false;
1007 let lineCloserFound: boolean = false;
1008 for (let i = 0; i < scanLines || (i < graceLines && lineOpenerFound && !lineCloserFound); i++) {
1009 const lineText = this.documentBody.lineAt(i).text;
1010 if (i >= scanLines) {
1011 logger.info(getMessage("graceLines"));
1012 }
1013
1014 // If we encounter a closer before any opener, the header is broken
1015 if (lineText === closer && !lineOpenerFound) {
1016 logger.Gui.warning(getMessage("brokenHeader"));
1017 return false;
1018 }
1019
1020 // If we encounter an opener after a closer was already found, header is broken
1021 if (lineText === opener && lineCloserFound) {
1022 logger.Gui.warning(getMessage("brokenHeader"));
1023 return false;
1024 }
1025
1026 // Detect opener
1027 if (lineText === opener && !lineOpenerFound) {
1028 lineOpenerFound = true;
1029 this.headerInnerStart = i;
1030 logger.info(getMessage("headerOpenerFound"));
1031 continue;
1032 }
1033
1034 // Detect closer (only valid if opener was already seen)
1035 if (lineText === closer && !lineCloserFound) {
1036 this.headerInnerEnd = i;
1037 lineCloserFound = true;
1038 }
1039
1040 if (lineCloserFound && lineOpenerFound) {
1041 logger.info(getMessage("headerOpenerAndCloserFound"));
1042 return true;
1043 }
1044 }
1045 logger.Gui.warning(getMessage("documentLineScanExceeded", this.maxScanLength));
1046 return false;
1047 }
1048
1064 private skipFirstLineInDocument(document: vscode.TextDocument): number {
1065 let insertLine = 0;
1066
1067 if (document.lineCount > 0) {
1068 const firstLine = document.lineAt(0).text;
1069 if (firstLine.startsWith("#!")) {
1070 insertLine = 1;
1071 }
1072 }
1073 return insertLine;
1074 }
1075
1085 private async writeHeaderToFile(document: vscode.TextDocument, comments: string[], languageId?: string): Promise<number> {
1086 logger.debug(getMessage("inFunction", "writeHeaderToFile", "CommentGenerator"));
1087
1088 const headerLines = await this.buildTheHeader(comments, languageId);
1089 const headerText = headerLines.join("");
1090 const edit = new vscode.WorkspaceEdit();
1091 const insertLine: number = this.skipFirstLineInDocument(document);
1092 edit.insert(
1093 document.uri,
1094 new vscode.Position(insertLine, 0),
1095 headerText
1096 );
1097
1098 await vscode.workspace.applyEdit(edit);
1099 return this.Config.get("statusSuccess");
1100 }
1101
1113 async injectHeader() {
1114 logger.debug(getMessage("inFunction", "injectHeader", "CommentGenerator"));
1115 const editor = vscode.window.activeTextEditor;
1116 if (editor === undefined) {
1117 logger.error(getMessage("noFocusedEditors"));
1118 logger.Gui.error(getMessage("openFileToApplyHeader"));
1119 return;
1120 }
1121 this.updateFileInfo(editor.document);
1122 // Checking that the meta data is filled out.
1123 if (
1124 this.documentBody === undefined || this.filePath === undefined
1125 || this.fileName === undefined || this.fileExtension === undefined
1126 || this.languageId === undefined || this.documentEOL === undefined
1127 || this.documentVersion === undefined
1128 ) {
1129 logger.error(getMessage("corruptedFileMetaData"));
1130 logger.Gui.error(getMessage("errorDuringFunctionCall", "injectHeader"));
1131 return;
1132 }
1133 // Making sure that the target document is still open.
1134 if (this.documentBody.isClosed) {
1135 logger.warning(getMessage("closedDocument"));
1136 logger.Gui.warning(getMessage("updateAbortedBecauseFileClosedSyncCancelled"));
1137 return;
1138 }
1139 // Some logging
1140 const msg = getMessage("inputArgs", JSON.stringify(this.documentBody), JSON.stringify(this.filePath), JSON.stringify(this.fileName), JSON.stringify(this.fileExtension), JSON.stringify(this.languageId), JSON.stringify(this.documentEOL), JSON.stringify(this.documentVersion));
1141 logger.Gui.debug(msg);
1142 logger.debug(msg);
1143 // Determining the correct comment prefix
1144 const determineComment: CommentStyle = await this.determineCorrectComment();
1145 const comments: string[] = await this.getCorrectCommentPrefix(determineComment);
1146 // attempt to locate the header
1147 let response: boolean | undefined = this.locateIfHeaderPresent(comments);
1148 if (response === undefined) {
1149 logger.Gui.warning(getMessage("updateAbortedBecauseFileClosedSyncCancelled"));
1150 return;
1151 }
1152 if (response === true) {
1153 logger.Gui.info(getMessage("updatingEditionDate"));
1154 await this.updateEditDate(editor.document, comments);
1155 return;
1156 }
1157 if (response === false) {
1158 let status: number = await this.writeHeaderToFile(editor.document, comments, determineComment.language);
1159 if (status === this.Config.get("statusError")) {
1160 logger.Gui.error(getMessage("headerWriteFailed"));
1161 return;
1162 }
1163 logger.Gui.info(getMessage("headerWriteSuccess"));
1164 }
1165 }
1166
1175 private async allowedToActivate(): Promise<boolean> {
1176 logger.debug(getMessage("inFunction", "allowedToActivate", "CommentGenerator"));
1177 const ignored: string[] = CodeConfig.get("extensionIgnore") ?? [];
1178
1179 for (const pattern of ignored) {
1180 if (
1181 this.fileExtension && minimatch(this.fileExtension, pattern) ||
1182 this.fileName && minimatch(this.fileName, pattern) ||
1183 this.filePath && minimatch(this.filePath, pattern)
1184 ) {
1185 return false;
1186 }
1187 }
1188
1189 return true;
1190 }
1191
1200 updateLogoInstanceRandomiser(randomLogoInstance: RandomLogo): void {
1201 logger.debug(getMessage("inFunction", "updateLogoInstanceRandomiser", "CommentGenerator"));
1202 this.randomLogo = randomLogoInstance;
1203 }
1204
1215 async refreshHeader(document: vscode.TextDocument | undefined) {
1216 logger.debug(getMessage("inFunction", "refreshHeader", "CommentGenerator"));
1217 const refreshOnSave: boolean = CodeConfig.get("refreshOnSave");
1218 const promptToCreateIfMissing: boolean = CodeConfig.get("promptToCreateIfMissing");
1219 if (!refreshOnSave) {
1220 return;
1221 }
1222 if (document === undefined) {
1223 logger.error(getMessage("noDocumentProvided"));
1224 return;
1225 }
1226 this.updateFileInfo(document);
1227 // Checking that the meta data is filled out.
1228 if (
1229 this.documentBody === undefined || this.filePath === undefined
1230 || this.fileName === undefined || this.fileExtension === undefined
1231 || this.languageId === undefined || this.documentEOL === undefined
1232 || this.documentVersion === undefined
1233 ) {
1234 logger.error(getMessage("corruptedFileMetaData"));
1235 logger.Gui.error(getMessage("errorDuringFunctionCall", "injectHeader"));
1236 return;
1237 }
1238 // Check that the file is not in the exclusion list.
1239 if (!await this.allowedToActivate()) {
1240 logger.info(getMessage("fileExcludedActivationDisabled"));
1241 return;
1242 }
1243 // Making sure that the target document is still open.
1244 if (this.documentBody.isClosed) {
1245 logger.warning(getMessage("closedDocument"));
1246 logger.Gui.warning(getMessage("updateAbortedBecauseFileClosedSyncCancelled"));
1247 return;
1248 }
1249 // Some logging
1250 const msg = getMessage("inputArgs", JSON.stringify(this.documentBody), JSON.stringify(this.filePath), JSON.stringify(this.fileName), JSON.stringify(this.fileExtension), JSON.stringify(this.languageId), JSON.stringify(this.documentEOL), JSON.stringify(this.documentVersion));
1251 logger.Gui.debug(msg);
1252 logger.debug(msg);
1253 // Determining the correct comment prefix
1254 const determineComment: CommentStyle = await this.determineCorrectComment();
1255 const comments: string[] = await this.getCorrectCommentPrefix(determineComment);
1256 // attempt to locate the header
1257 const response: boolean | undefined = this.locateIfHeaderPresent(comments);
1258 if (response === undefined) {
1259 logger.Gui.warning(getMessage("updateAbortedBecauseFileClosedSyncCancelled"));
1260 return;
1261 }
1262 if (response === false) {
1264 logger.Gui.info(getMessage("headerNotFound"));
1265 return;
1266 }
1267 logger.Gui.warning(getMessage("headerNotFound"));
1268 const questionResponse: boolean = await query.confirm(getMessage("headerInjectQuestion"));
1269 if (questionResponse === false) {
1270 logger.Gui.info(getMessage("headerInjectQuestionRefused"));
1271 return;
1272 }
1273 const status: number = await this.writeHeaderToFile(document, comments, determineComment.language);
1274 if (status === this.Config.get("statusError")) {
1275 logger.Gui.error(getMessage("headerWriteFailed"));
1276 return;
1277 }
1278 logger.Gui.info(getMessage("headerWriteSuccess"));
1279 }
1280 if (response === true) {
1281 logger.Gui.info(getMessage("updatingEditionDate"));
1282 await this.updateEditDate(document, comments);
1283 return;
1284 }
1285 }
1286}
Intelligent file header generation and management system.
constructor(languageComment:LazyFileLoader|undefined=undefined, editor:vscode.TextEditor|undefined=undefined, randomLogoInstance:RandomLogo|undefined=undefined)
Constructor for CommentGenerator class.
Generic lazy file loader with caching and type safety @template T The expected type of the loaded fil...
import *as vscode from vscode
export const languagePrepend
Array of the languages with the data to append.
Definition constants.ts:344
iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAAG0OVFdAAAAv3pUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHjabVBbEsMgCPznFD2CAho5jknTmd6gx qtNJMEqCKH4h lRj6dADxVZugptTqwzYer65UeIe5DWUctXFzIXEu5EdIHqrWYry UL6xZmlG7UnJa57b oHlEkAAAGEaUNDUElDQyBwcm9maWxlAAB4nH2RPUjDUBSFT1OlKhWHFhFxyFA72UVFHGsVilAh1AqtOpi89A aNCQpLo6Ca8HBn8Wqg4uzrg6ugiD4A IuOCm6SIn3JYUWsT64vI z3jncdx8gNCpMs3rigKbbZjqZELO5VTHwin4MU4UQlZllzElSCl3X1z18fL L8azu9 Ma56LLAM8NmJj1PHCYWix2sdDArmRrxNHFE1XTKF7Ieq5y3OGuVGmv1yV8YzOsry1ynGkMSi1iCBBEKaiijAhsx2nVSLKTpPNHFP r6JXIp5CqDkWMBVWiQXT yerVWYmvSSggmg98VxPsaBwC7QrDvO97HjNE8A zNwpbf91QYw KqFQAN7P6JtyQOgWGFjz5tY6x kDkKFZpW6Ag0MgWqTs9S7v7uuc2793WvP7AZKlcrMQx gGAAANcmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNC40LjAtRXhpdjIiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iCiAgICB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIgogICAgeG1sbnM6R0lNUD0iaHR0cDovL3d3dy5naW1wLm9yZy94bXAvIgogICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgIHhtcE1NOkRvY3VtZW50SUQ9ImdpbXA6ZG9jaWQ6Z2ltcDowOWQ3ODk3OS03YjNiLTRhMTgtODM5ZS1lMDgwOGNjMmUzY2EiCiAgIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTM2YWE3YmMtN2QzZS00ZDJkLWIxMjItYTFhZjQwMjkzYjI5IgogICB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6OTc2ZWEzNTgtNTNlNy00ODZkLWIzMzQtMjhmZWY1N2IyZWIzIgogICBHSU1QOkFQST0iMy4wIgogICBHSU1QOlBsYXRmb3JtPSJMaW51eCIKICAgR0lNUDpUaW1lU3RhbXA9IjE3NTg1MzI3OTM2NzA4NzIiCiAgIEdJTVA6VmVyc2lvbj0iMy4wLjQiCiAgIGRjOkZvcm1hdD0iaW1hZ2UvcG5nIgogICB0aWZmOk9yaWVudGF0aW9uPSIxIgogICB4bXA6Q3JlYXRvclRvb2w9IkdJTVAiCiAgIHhtcDpNZXRhZGF0YURhdGU9IjIwMjU6MDk6MjJUMTE6MTk6NTArMDI6MDAiCiAgIHhtcDpNb2RpZnlEYXRlPSIyMDI1OjA5OjIyVDExOjE5OjUwKzAyOjAwIj4KICAgPHhtcE1NOkhpc3Rvcnk CiAgICA8cmRmOlNlcT4KICAgICA8cmRmOmxpCiAgICAgIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiCiAgICAgIHN0RXZ0OmNoYW5nZWQ9Ii8iCiAgICAgIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6ZGE1MDJhZWEtNDM0MS00NjdjLTgwMzEtYjUwMmU2OGFhYjkwIgogICAgICBzdEV2dDpzb2Z0d2FyZUFnZW50PSJHSU1QIDMuMC40IChMaW51eCkiCiAgICAgIHN0RXZ0OndoZW49IjIwMjUtMDktMjJUMTE6MTk6NTMrMDI6MDAiLz4KICAgIDwvcmRmOlNlcT4KICAgPC94bXBNTTpIaXN0b3J5PgogIDwvcmRmOkRlc2NyaXB0aW9uPgogPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIAo8P3hwYWNrZXQgZW5kPSJ3Ij8 QZaInQAAAAZiS0dEAAAAAAAA UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB kJFgkTNb1wNOYAABokSURBVHja7V15dFRF1r9V7 WW7mwsAZJ0SJpElARhUBM0gKNwjsM2gIMw oF Ss4MHy5DmBEB56g4Is6ZIQGRJYownzIalCUzLnj0Cx7GBZhAWISIMGaTYIBgku5Od7 t7vdH8pruTifpzkaAd8 pk8573fWqbv3q3lu3bt1HEPEkAAyAThLf8uNBna2AQhfJW4EkSV2rgOd5SEpKavWF yv QjEZjq58rigLJyclAqfdZZMaMGbX5 fmDAQAIItb2jbnQWVK70KUK8Kp2IWAuYOcrSEpKAkJIwG0GQ5OtXekCBUDabss6qIABEAaEEKitrXVnZ2eLwaSy3w uPI2CLCtAgAMAgLFjx oqKyt59b7a3VZMbJYDzXJBp NAUZoFSWVlJa sKCgoK6NLgSXBSdOnGhseQAiImRnZ0u T21TFiAqmJgYj3PmzHF4ryiK7PuNDipAHDhwICIirly58kJ1daUz8L4XylarFX744YdW45CcnNzcmSvyAMrLy vqXOiKPBgEV4koXGXqmw0YOnQoDB06NKQK9u3bdz6YWdPpBqhGRWjoZsBQBkIxQBD12hA0y1vVBiOEgCIrYVmLXWxAs7z2teE4noPt27fbw7Gyg89PijA02RpETalWZ7N42rJlCzDlSl8kSYKpU6fqAAAEQYCHHnzIuWv3Lsvx48drb7311sGt6vO1zhARGWNotVrRarUiYwzbJwWLiz rSUyMR0QFRVFEH6mNR44caXK73aLH45EREQsKCjy JTMzEyPeiclJQVGjhwZYTQadZRSTpIkGDx4sCAIgtguB1TV0pZ6aY8DiIhlZWVNKjMREQVBUH7 ziBhdaEVB8KtINzva8qo29cH3dEAvKGHQGtA322AIivQG hs1QDGGAwdOhQoR0OSclarFbKysuq7zyZk4dmEiAoQgu16tXoNA1fHKPUrV5kDhBCQJAkYY73VABZQAEpKShyKokB fr49JPM80ESSJRmtVqufW7A9kywhYQhmZd3xk2qSqYYtImJCQkKHNdC2etbsEWABrljFb UkCBLwvB4I4bzM3L17d OpU6caEBFmzZrlfuaZZ wqOIOBlA JiCQnJLkddu0tS7Ytm2brCgKL8uy99Y777xD33vvvUhCCJyvOS lpqUq fv MREBE3btzoREQ8ePCgK3Ct0U4DWEgLE98GFBYWlvvenTRpknP8 PGNKp6C1dnFBiAmJibi7bff lPg9dTUVCmwjtWrVzcsW7bM3o3rAn9yu91gMplAkRU4 e1pXpZl0Ol03vsVFRVcQUGBpV05QCgJw RmV1bIwKCkpMSh1sHxnPfhJ0 etCMiBD682yXhkiVLdOqqWd0tYYzBiBEjotrqTLfoggiTBQAoHD582Hju3Dk3YzJyHIGH uvXrltuucXruAjJKmaMQXJyMlRVVYVsDwRzdQc2dO3atbWzZs1q5R g21KrgQBqiziO83 U16fK Bgc7OFtrgsCvdo9uTjVFiZaA7QGXPX9ght BDQGaAzQGKAx4GpSyEuSr7 Kysru7xDodK ffvOP LII GEEBgyZEj9oUOHYvsUAhDR6zP0vdZ1BjQvWhjKgKgA5Tg PyMi6ZR5r8mAnpIBPcZ7NegSA pSuSFfxTtzTffbLbZbKb09HRp0aJF5mPHjkWkp6db3n777foZM2Y4rxIDWBil60j45JNP6jdv3txYVVVVDwCg1 th vz5sRcvXoTDhw b6 rq3L0kAxjwPA83DU8FURSDOmWuqAraLq8REbZt2ybzvA4o5QGZKvlbj8mAAQN0c fONZ49e9Yv5Pf2228X586d22 hfqX3ieB47j DYcgu3tuN1uZenSpdx export const languageAppend
Array of the languages with the data to prepend.
Definition constants.ts:341
export const headerLogoVersionReference
Version key referencing an entry in headerLogoVersions
Definition constants.ts:295
export const preferSingleLineComments
Prefer single line comments when possible.
Definition constants.ts:361
export const promptToCreateIfMissing
Whether to prompt user to create header if missing during operations.
Definition constants.ts:315
export const useHeaderLogoVersion
Toggle to use a versioned logo instead of the latest default logo.
Definition constants.ts:283
export const export const headerLogoVersions
Versioned ASCII art logo collection for backward compatibility.
Definition constants.ts:203
export const randomLogo
Whether to use random logo selection instead of default logo.
Definition constants.ts:318
export const export const string[]
Definition constants.ts:203
export const refreshOnSave
Whether to automatically refresh headers when files are saved.
Definition constants.ts:312
Defines comment style configuration for different programming languages.
Structure representing a loaded ASCII art logo with metadata.
export const logger
Singleton logger instance providing unified logging interface for the entire extension.
Definition logger.ts:910
const instance
Singleton logger instance for application-wide use.
Definition logger.ts:870
export const getMessage
Exported function for direct message retrieval.
export type CodeConfigType
Type alias for the Configuration class.
export const CodeConfig
Exported configuration singleton for extension-wide access @export Primary configuration interface us...
export const query
Convenience singleton export for direct access to Query functionality @export Primary interface for u...
Definition querier.ts:345