Skip to content

Commit 389a79c

Browse files
Merge pull request #50 from newtextdoc1111/feature/auto_format_blocklist
Feature/auto format blocklist
2 parents 79fb35f + 1c4e081 commit 389a79c

5 files changed

Lines changed: 305 additions & 18 deletions

File tree

tests/js/auto-formatter.test.js

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import {
2+
formatPromptText,
3+
__test__
4+
} from "../../web/js/auto-formatter.js";
5+
6+
const {
7+
shouldAutoFormat
8+
} = __test__;
9+
10+
describe('AutoFormatter Functions', () => {
11+
12+
describe('shouldAutoFormat', () => {
13+
const mockNodeInfo = (nodeType, inputName) => ({
14+
nodeType,
15+
inputName
16+
});
17+
18+
test('should return false for empty text', () => {
19+
expect(shouldAutoFormat('', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(false);
20+
expect(shouldAutoFormat(' ', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(false);
21+
});
22+
23+
test('should return false for blocklisted nodes', () => {
24+
expect(shouldAutoFormat('some text,', mockNodeInfo('Power Puter (rgthree)', 'code'))).toBe(false);
25+
expect(shouldAutoFormat('some text,', mockNodeInfo('LoraLoaderBlockWeight //Inspire', 'block_vector'))).toBe(false);
26+
});
27+
28+
test('should return false for numeric data or single-letter placeholders', () => {
29+
expect(shouldAutoFormat('0,0,0,1,1,1', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(false);
30+
expect(shouldAutoFormat('0.5, -1.2, 0.8', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(false);
31+
expect(shouldAutoFormat('A,B,R', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(false);
32+
expect(shouldAutoFormat('X, 1.5, Y', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(false);
33+
});
34+
35+
test('should return true for text with "word + comma" pattern', () => {
36+
expect(shouldAutoFormat('1girl, blue hair,', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(true);
37+
expect(shouldAutoFormat('tag1, tag2', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(true);
38+
});
39+
40+
test('should return false if "word + comma" pattern is not found', () => {
41+
expect(shouldAutoFormat('hello world', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(false);
42+
expect(shouldAutoFormat('tag1 tag2', mockNodeInfo('CLIPTextEncode', 'text'))).toBe(false);
43+
});
44+
});
45+
46+
describe('formatPromptText', () => {
47+
test('should format text by adding comma and space after tags', () => {
48+
const input = 'tag1,tag2,tag3';
49+
const expected = 'tag1, tag2, tag3, ';
50+
expect(formatPromptText(input)).toBe(expected);
51+
});
52+
53+
test('should remove extra spaces around tags', () => {
54+
const input = ' tag1 , tag2 ';
55+
const expected = 'tag1, tag2, ';
56+
expect(formatPromptText(input)).toBe(expected);
57+
});
58+
59+
test('should preserve special syntax like weights', () => {
60+
const input = '(tag1:1.2), [tag2]';
61+
// Note: The current implementation splits by comma.
62+
// If the input is "(tag1:1.2), [tag2]", it splits into "(tag1:1.2)" and "[tag2]".
63+
// Then joins with ", ".
64+
const expected = '(tag1:1.2), [tag2], ';
65+
expect(formatPromptText(input)).toBe(expected);
66+
});
67+
68+
test('should handle multiple lines', () => {
69+
const input = 'tag1, tag2\ntag3, tag4';
70+
const expected = 'tag1, tag2, \ntag3, tag4, ';
71+
expect(formatPromptText(input)).toBe(expected);
72+
});
73+
74+
test('should keep empty lines unchanged', () => {
75+
const input = 'tag1, tag2\n\ntag3, tag4';
76+
const expected = 'tag1, tag2, \n\ntag3, tag4, ';
77+
expect(formatPromptText(input)).toBe(expected);
78+
});
79+
80+
test('should handle empty input', () => {
81+
expect(formatPromptText('')).toBe('');
82+
expect(formatPromptText(null)).toBe(null);
83+
expect(formatPromptText(undefined)).toBe(undefined);
84+
});
85+
86+
test('should handle input with only spaces', () => {
87+
expect(formatPromptText(' ')).toBe(' ');
88+
});
89+
});
90+
});

web/js/auto-formatter.js

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,65 @@
11
import { settingValues } from './settings.js';
2+
import { NodeInfo } from './node-info.js';
3+
4+
5+
/**
6+
* Determines if the text content should be auto-formatted.
7+
*
8+
* Format conditions:
9+
* 1. Skip formatting if node is in blocklist
10+
* 2. Skip formatting if text contains only numbers or single letters (separated by commas)
11+
* 3. Format if text contains "word + comma" pattern at least twice
12+
* 4. Otherwise, don't format
13+
*
14+
* @param {NodeInfo} nodeInfo - The node information.
15+
* @returns {boolean} - True if the text should be formatted, false otherwise.
16+
*/
17+
function shouldAutoFormat(text, nodeInfo) {
18+
if (!text || text.trim().length === 0) return false;
19+
20+
// 1. Check if the node name is in the blocklist
21+
const blocklist = [
22+
["Power Puter (rgthree)", "code"],
23+
["LoraLoaderBlockWeight //Inspire", "block_vector"]
24+
];
25+
26+
const isBlocklisted = blocklist.some(([type, input]) =>
27+
type === nodeInfo.nodeType && input === nodeInfo.inputName
28+
);
29+
30+
if (isBlocklisted) {
31+
// console.debug(`[Autocomplete-Plus] auto-formatter on blur => nodeType: ${nodeInfo.nodeType}, inputName: ${nodeInfo.inputName} => blocklisted`);
32+
return false;
33+
} else {
34+
// console.debug(`[Autocomplete-Plus] auto-formatter on blur => nodeType: ${nodeInfo.nodeType}, inputName: ${nodeInfo.inputName}`);
35+
}
36+
37+
38+
const trimmedText = text.trim();
39+
40+
// 2. Check if the text is purely numeric data or single-letter placeholders with commas
41+
// (e.g., "0,0,0,1,1,1" or "0.5, -1.2, 0.8" or "A,B,R" for LoRA Block Weight)
42+
const elements = trimmedText.split(',').map(el => el.trim());
43+
const isSingleLetterOrNumeric = elements.every(el => {
44+
if (/^[A-Za-z]$/.test(el)) return true;
45+
if (/^-?\d+(\.\d+)?$/.test(el)) return true;
46+
return false;
47+
});
48+
49+
if (isSingleLetterOrNumeric && elements.length > 0) {
50+
return false; // Don't format numeric data or single-letter template patterns
51+
}
52+
53+
// 3. Check if the text contains the pattern "word + comma"
54+
const wordCommaPattern = /\w+\s*,/g;
55+
const matches = trimmedText.match(wordCommaPattern);
56+
57+
if (matches == null) {
58+
return false;
59+
}
60+
61+
return true; // Text should be formatted
62+
}
263

364
/**
465
* Format the prompt text: add a comma and space after each tag, and remove extra spaces.
@@ -79,12 +140,19 @@ export class AutoFormatterEventHandler {
79140
* Handle blur event to trigger auto-formatting
80141
* @param {Event} event - The blur event
81142
*/
82-
handleBlur(event) {
143+
handleBlur(event, nodeInfo) {
83144
if (
84145
settingValues.enableAutoFormat &&
146+
settingValues.autoFormatTrigger === 'auto' &&
85147
event.target.tagName === 'TEXTAREA'
86148
) {
87-
formatTextareaOnBlur(event.target);
149+
const textarea = event.target;
150+
const text = textarea.value;
151+
152+
// Check if the content should be auto-formatted
153+
if (shouldAutoFormat(text, nodeInfo)) {
154+
formatTextareaOnBlur(textarea);
155+
}
88156
}
89157
}
90158

@@ -95,4 +163,37 @@ export class AutoFormatterEventHandler {
95163
handleKeyUp(event) { }
96164
handleMouseMove(event) { }
97165
handleClick(event) { }
166+
167+
/**
168+
* Format textarea content via manual trigger (e.g., keyboard shortcut)
169+
* @param {HTMLTextAreaElement} textarea - The textarea element to format
170+
* @param {NodeInfo} nodeInfo - The node information
171+
* @returns {boolean} - True if formatting was performed, false otherwise
172+
*/
173+
applyFormatTextarea(textarea, nodeInfo) {
174+
if (!textarea || textarea.tagName !== 'TEXTAREA') {
175+
return false;
176+
}
177+
178+
if (!settingValues.enableAutoFormat) {
179+
return false;
180+
}
181+
182+
const text = textarea.value;
183+
184+
if (shouldAutoFormat(text, nodeInfo)) {
185+
formatTextareaOnBlur(textarea);
186+
return true;
187+
}
188+
189+
return false;
190+
}
98191
}
192+
193+
// Export functions for testing
194+
const isTestEnvironment = typeof process !== 'undefined' && process.env.NODE_ENV === 'test';
195+
export const __test__ = isTestEnvironment
196+
? {
197+
shouldAutoFormat
198+
}
199+
: undefined;

0 commit comments

Comments
 (0)