mirror of
				https://codeberg.org/yeentown/barkey.git
				synced 2025-10-31 21:44:12 +00:00 
			
		
		
		
	factor out common append-content-warning routine for use in both frontend and backend
This commit is contained in:
		
							parent
							
								
									7814c6e54e
								
							
						
					
					
						commit
						563e32316f
					
				
					 4 changed files with 219 additions and 12 deletions
				
			
		
							
								
								
									
										62
									
								
								packages/backend/src/misc/append-content-warning.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								packages/backend/src/misc/append-content-warning.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,62 @@ | |||
| /* | ||||
|  * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors | ||||
|  * SPDX-License-Identifier: AGPL-3.0-only | ||||
|  */ | ||||
| 
 | ||||
| /* | ||||
|  * Important Note: this file must be kept in sync with packages/frontend-shared/js/append-content-warning.ts | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  * Appends an additional content warning onto an existing one. | ||||
|  * The additional value will not be added if it already exists within the original input. | ||||
|  * @param original Existing content warning | ||||
|  * @param additional Content warning to append | ||||
|  * @param reverse If true, then the additional CW will be prepended instead of appended. | ||||
|  */ | ||||
| export function appendContentWarning(original: string | null | undefined, additional: string, reverse = false): string { | ||||
| 	// Easy case - if original is empty, then additional replaces it.
 | ||||
| 	if (!original) { | ||||
| 		return additional; | ||||
| 	} | ||||
| 
 | ||||
| 	// Easy case - if the additional CW is empty, then don't append it.
 | ||||
| 	if (!additional) { | ||||
| 		return original; | ||||
| 	} | ||||
| 
 | ||||
| 	// If the additional CW already exists in the input, then we *don't* append another copy!
 | ||||
| 	if (includesWholeWord(original, additional)) { | ||||
| 		return original; | ||||
| 	} | ||||
| 
 | ||||
| 	return reverse | ||||
| 		? `${additional}, ${original}` | ||||
| 		: `${original}, ${additional}`; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Emulates a regular expression like /\b(pattern)\b/, but with a raw non-regex pattern. | ||||
|  * We're checking to see whether the default CW appears inside the existing CW, but *only* if there's word boundaries on either side. | ||||
|  * @param input Input string to search | ||||
|  * @param target Target word / phrase to search for | ||||
|  */ | ||||
| function includesWholeWord(input: string, target: string): boolean { | ||||
| 	const parts = input.split(target); | ||||
| 
 | ||||
| 	// The additional string could appear multiple times within the original input.
 | ||||
| 	// We need to check each occurrence, since any of them could potentially match.
 | ||||
| 	for (let i = 0; i + 1 < parts.length; i++) { | ||||
| 		const before = parts[i]; | ||||
| 		const after = parts[i + 1]; | ||||
| 
 | ||||
| 		// If either the preceding or following tokens are a "word", then this "match" is actually just part of a longer word.
 | ||||
| 		// Likewise, if *neither* token is a word, then this is a real match and the CW already exists in the input.
 | ||||
| 		if (!/\w$/.test(before) && !/^\w/.test(after)) { | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// If we don't match, then there is no existing CW.
 | ||||
| 	return false; | ||||
| } | ||||
							
								
								
									
										92
									
								
								packages/backend/test/unit/misc/append-content-warning.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								packages/backend/test/unit/misc/append-content-warning.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,92 @@ | |||
| /* | ||||
|  * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors | ||||
|  * SPDX-License-Identifier: AGPL-3.0-only | ||||
|  */ | ||||
| 
 | ||||
| import { appendContentWarning } from '@/misc/append-content-warning.js'; | ||||
| 
 | ||||
| describe(appendContentWarning, () => { | ||||
| 	it('should return additional when original is null', () => { | ||||
| 		const result = appendContentWarning(null, 'additional'); | ||||
| 
 | ||||
| 		expect(result).toBe('additional'); | ||||
| 	}); | ||||
| 
 | ||||
| 	it('should return additional when original is undefined', () => { | ||||
| 		const result = appendContentWarning(undefined, 'additional'); | ||||
| 
 | ||||
| 		expect(result).toBe('additional'); | ||||
| 	}); | ||||
| 
 | ||||
| 	it('should return additional when original is empty', () => { | ||||
| 		const result = appendContentWarning('', 'additional'); | ||||
| 
 | ||||
| 		expect(result).toBe('additional'); | ||||
| 	}); | ||||
| 
 | ||||
| 	it('should return original when additional is empty', () => { | ||||
| 		const result = appendContentWarning('original', ''); | ||||
| 
 | ||||
| 		expect(result).toBe('original'); | ||||
| 	}); | ||||
| 
 | ||||
| 	it('should append additional when it does not exist in original', () => { | ||||
| 		const result = appendContentWarning('original', 'additional'); | ||||
| 
 | ||||
| 		expect(result).toBe('original, additional'); | ||||
| 	}); | ||||
| 
 | ||||
| 	it('should append additional when it exists in original but has preceeding word', () => { | ||||
| 		const result = appendContentWarning('notadditional', 'additional'); | ||||
| 
 | ||||
| 		expect(result).toBe('notadditional, additional'); | ||||
| 	}); | ||||
| 
 | ||||
| 	it('should append additional when it exists in original but has following word', () => { | ||||
| 		const result = appendContentWarning('additionalnot', 'additional'); | ||||
| 
 | ||||
| 		expect(result).toBe('additionalnot, additional'); | ||||
| 	}); | ||||
| 
 | ||||
| 	it('should append additional when it exists in original multiple times but has preceeding or following word', () => { | ||||
| 		const result = appendContentWarning('notadditional additionalnot', 'additional'); | ||||
| 
 | ||||
| 		expect(result).toBe('notadditional additionalnot, additional'); | ||||
| 	}); | ||||
| 
 | ||||
| 	it('should not append additional when it exists in original', () => { | ||||
| 		const result = appendContentWarning('an additional word', 'additional'); | ||||
| 
 | ||||
| 		expect(result).toBe('an additional word'); | ||||
| 	}); | ||||
| 
 | ||||
| 	it('should not append additional when original starts with it', () => { | ||||
| 		const result = appendContentWarning('additional word', 'additional'); | ||||
| 
 | ||||
| 		expect(result).toBe('additional word'); | ||||
| 	}); | ||||
| 
 | ||||
| 	it('should not append additional when original ends with it', () => { | ||||
| 		const result = appendContentWarning('an additional', 'additional'); | ||||
| 
 | ||||
| 		expect(result).toBe('an additional'); | ||||
| 	}); | ||||
| 
 | ||||
| 	it('should not append additional when it appears multiple times', () => { | ||||
| 		const result = appendContentWarning('an additional additional word', 'additional'); | ||||
| 
 | ||||
| 		expect(result).toBe('an additional additional word'); | ||||
| 	}); | ||||
| 
 | ||||
| 	it('should not append additional when it appears multiple times but some have preceeding or following', () => { | ||||
| 		const result = appendContentWarning('a notadditional additional additionalnot word', 'additional'); | ||||
| 
 | ||||
| 		expect(result).toBe('a notadditional additional additionalnot word'); | ||||
| 	}); | ||||
| 
 | ||||
| 	it('should prepend additional when reverse is true', () => { | ||||
| 		const result = appendContentWarning('original', 'additional', true); | ||||
| 
 | ||||
| 		expect(result).toBe('additional, original'); | ||||
| 	}); | ||||
| }); | ||||
							
								
								
									
										62
									
								
								packages/frontend-shared/js/append-content-warning.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								packages/frontend-shared/js/append-content-warning.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,62 @@ | |||
| /* | ||||
|  * SPDX-FileCopyrightText: hazelnoot and other Sharkey contributors | ||||
|  * SPDX-License-Identifier: AGPL-3.0-only | ||||
|  */ | ||||
| 
 | ||||
| /* | ||||
|  * Important Note: this file must be kept in sync with packages/backend/src/misc/append-content-warning.ts | ||||
|  */ | ||||
| 
 | ||||
| /** | ||||
|  * Appends an additional content warning onto an existing one. | ||||
|  * The additional value will not be added if it already exists within the original input. | ||||
|  * @param original Existing content warning | ||||
|  * @param additional Content warning to append | ||||
|  * @param reverse If true, then the additional CW will be prepended instead of appended. | ||||
|  */ | ||||
| export function appendContentWarning(original: string | null | undefined, additional: string, reverse = false): string { | ||||
| 	// Easy case - if original is empty, then additional replaces it.
 | ||||
| 	if (!original) { | ||||
| 		return additional; | ||||
| 	} | ||||
| 
 | ||||
| 	// Easy case - if the additional CW is empty, then don't append it.
 | ||||
| 	if (!additional) { | ||||
| 		return original; | ||||
| 	} | ||||
| 
 | ||||
| 	// If the additional CW already exists in the input, then we *don't* append another copy!
 | ||||
| 	if (includesWholeWord(original, additional)) { | ||||
| 		return original; | ||||
| 	} | ||||
| 
 | ||||
| 	return reverse | ||||
| 		? `${additional}, ${original}` | ||||
| 		: `${original}, ${additional}`; | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Emulates a regular expression like /\b(pattern)\b/, but with a raw non-regex pattern. | ||||
|  * We're checking to see whether the default CW appears inside the existing CW, but *only* if there's word boundaries on either side. | ||||
|  * @param input Input string to search | ||||
|  * @param target Target word / phrase to search for | ||||
|  */ | ||||
| function includesWholeWord(input: string, target: string): boolean { | ||||
| 	const parts = input.split(target); | ||||
| 
 | ||||
| 	// The additional string could appear multiple times within the original input.
 | ||||
| 	// We need to check each occurrence, since any of them could potentially match.
 | ||||
| 	for (let i = 0; i + 1 < parts.length; i++) { | ||||
| 		const before = parts[i]; | ||||
| 		const after = parts[i + 1]; | ||||
| 
 | ||||
| 		// If either the preceding or following tokens are a "word", then this "match" is actually just part of a longer word.
 | ||||
| 		// Likewise, if *neither* token is a word, then this is a real match and the CW already exists in the input.
 | ||||
| 		if (!/\w$/.test(before) && !/^\w/.test(after)) { | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// If we don't match, then there is no existing CW.
 | ||||
| 	return false; | ||||
| } | ||||
|  | @ -112,6 +112,7 @@ import * as Misskey from 'misskey-js'; | |||
| import insertTextAtCursor from 'insert-text-at-cursor'; | ||||
| import { toASCII } from 'punycode.js'; | ||||
| import { host, url } from '@@/js/config.js'; | ||||
| import { appendContentWarning } from '@@/js/append-content-warning.js'; | ||||
| import type { MenuItem } from '@/types/menu.js'; | ||||
| import type { PostFormProps } from '@/types/post-form.js'; | ||||
| import MkNoteSimple from '@/components/MkNoteSimple.vue'; | ||||
|  | @ -373,18 +374,8 @@ if ($i.defaultCW) { | |||
| 	if (!cw.value || $i.defaultCWPriority === 'default') { | ||||
| 		cw.value = $i.defaultCW; | ||||
| 	} else if ($i.defaultCWPriority !== 'parent') { | ||||
| 		// This is a fancy way of simulating /\bsearch\b/ without a regular expression. | ||||
| 		// We're checking to see whether the default CW appears inside the existing CW, but *only* if there's word boundaries. | ||||
| 		const parts = cw.value.split($i.defaultCW); | ||||
| 		const hasExistingDefaultCW = parts.length === 2 && !/\w$/.test(parts[0]) && !/^\w/.test(parts[1]); | ||||
| 		if (!hasExistingDefaultCW) { | ||||
| 			// We need to merge the CWs | ||||
| 			if ($i.defaultCWPriority === 'defaultParent') { | ||||
| 				cw.value = `${$i.defaultCW}, ${cw.value}`; | ||||
| 			} else if ($i.defaultCWPriority === 'parentDefault') { | ||||
| 				cw.value = `${cw.value}, ${$i.defaultCW}`; | ||||
| 			} | ||||
| 		} | ||||
| 		const putDefaultFirst = $i.defaultCWPriority === 'defaultParent'; | ||||
| 		cw.value = appendContentWarning(cw.value, $i.defaultCW, putDefaultFirst); | ||||
| 	} | ||||
| 	// else { do nothing, because existing CW takes priority. } | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue