User:Nardog/ExpandContractions.js

['edit', 'submit'].includes(mw.config.get('wgAction')) && $.ajax(	'//tools-static.wmflabs.org/meta/scripts/pathoschild.templatescript.js',	{ dataType: 'script', cache: true } ).then(function expandContractions {	let re;	let edit = editor => {		let escaped = [];		let escape = $0 => `\x7f\x7f\x7f${escaped.push($0) - 1}\x7f\x7f\x7f`;		let unescapeRe = /\x7f{3}(\d+)\x7f{3}/g;		let unescape = ($0, $1) => escaped[$1];		let reps = new Set;		let makeCallback = (w, c) => ($0, $1) => {			reps.add(c);			return $1 + ' ' + w;		};		let orig = editor.get;		let repl = orig			.replace(re, escape)			.replace( /|]*\/>|<(blockquote|ref|poem)(?:\s?[^>]*)?>[^]+?<\/\1>|\[\^\[\+?\]\]|["“].+?["”]|(''+).+?\2|^===?\s*(?:References|Sources|Bibliography|Further reading|External links)\s*==[^]+|^=+.+=/gim, escape )			.replace( /\|\s*(?:explain|filename|image|name|reason|song|title)\d*\s*=[^|}]+?(?=[|}])/gi, escape )			.replace( /\b([Hh]e|[Ss]he|[Ii]t|[TWtw]hat|[Tt]here)['’]s(?= (?:(?:not|n?ever|n?either|again|all|almost|also|always|just|often|perhaps|quite|rather|sometimes|soon|still|too|(?!(?:ally|anomaly|apply|assembly|belly|bully|butterfly|chilly|comply|costly|cuddly|curly|disassembly|family|firefly|folly|gainly|gnarly|gully|holy|hurly|imply|jelly|lily|lonely|measly|melancholy|monopoly|multiply|oily|panoply|rally|reassembly|rely|reply|sally|scholarly|silly|sully|supply|surly|tally|ugly|unholy|unruly) )[a-z]{2,}ly) )*(?:appeared|become|been|begun|belonged|come|consisted|existed|got|gotten|had|happened|lasted|occurred|remained|seemed)\b)/g, makeCallback('has', 's') )			.replace( /\b([Hh]e|[Ss]he|[Ii]t|[TWtw]hat|[Tt]here)['’]s\b/g, makeCallback('is', 's') )			.replace(/\b([Cc])an['’]t\b/g, '$1annot')			.replace(/\b([Ww])on['’]t\b/g, '$1ill not')			.replace(/\b((?![Aa]i)[A-Z]?[a-z]+)n['’]t\b/g, '$1 not')			.replace( /\b([Ww]e|[Hh]e|[Ss]he|[Ii]t|[Tt]hey|[TWtw]hat|[Tt]here)['’]d(?= (?:(?:not|n?ever|n?either|again|all|almost|also|always|just|often|perhaps|quite|rather|sometimes|soon|still|too|(?!(?:ally|anomaly|apply|assembly|belly|bully|butterfly|chilly|comply|costly|cuddly|curly|disassembly|family|firefly|folly|gainly|gnarly|gully|holy|hurly|imply|jelly|lily|lonely|measly|melancholy|monopoly|multiply|oily|panoply|rally|reassembly|rely|reply|sally|scholarly|silly|sully|supply|surly|tally|ugly|unholy|unruly) )[a-z]{2,}ly) )*(?:agreed|arisen|awoken|been|begun|blown|bought|broken|brought|built|caught|chosen|dealt|decreed|disagreed|done|drawn|driven|drunk|eaten|fallen|fed|felt|fled|foreseen|forgiven|forgot|forgotten|fought|found|freed|given|gone|got|gotten|grown|guaranteed|had|heard|held|hidden|hurt|kept|known|learnt|led|left|lost|made|meant|met|misheard|mistaken|misunderstood|overheard|overseen|overtaken|paid|rebuilt|rewritten|ridden|risen|said|sat|seen|sent|shot|shown|shrunk|slept|sold|spent|spoken|stolen|stood|struck|stuck|sung|sworn|taken|taught|thought|thrown|told|torn|undergone|understood|undone|woken|won|worn|written|(?![^aeiou]+ed\b|embed\b)[a-z]+[^e]ed)\b)/g, makeCallback('had', 'd') )			.replace( /\b([Ww]e|[Hh]e|[Ss]he|[Ii]t|[Tt]hey|[TWtw]hat|[Tt]here)['’]d\b/g, makeCallback('would', 'd') )			.replace(/([a-z])['’]re\b/g, '$1 are')			.replace(/([a-z])['’]ve\b/g, '$1 have')			.replace(/([a-z])['’]ll\b/g, '$1 will')			.replace(unescapeRe, unescape)			.replace(unescapeRe, unescape)			.replace(unescapeRe, unescape);		if (repl === orig) {			mw.notify('No change.');			return;		}		let iw = mw.config.get('wgWikiID') === 'enwiki' ? '' : 'w:en:';		editor			.set(repl)			.appendEditSummary(`expanded contractions using script`)			.options({ minor: true })			.clickDiff;		if (reps.size) {			mw.notify( `Replacements include "'${[...reps].join(`" and "'`)}". Review them before saving.`, { type: 'warn' } );		}	};	let clicked;	window.pathoschild.TemplateScript.add([{ name: 'Expand contractions', script: editor => { if (clicked) { if (re) edit(editor); return; }			clicked = true; let templates = [ 'Blockquote', 'Cquote', 'Quote frame', 'Rquote', 'Quote box', 'Poem', 'Poem quote', 'About', 'For', 'Other uses', 'Redirect', 'Distinguish', 'Main', 'Further', 'See also', 'Lang', 'Interlanguage link' ];			let prefix = mw.config.get('wgFormattedNamespaces')[10] + ':'; new mw.Api.get({				action: 'query',				titles: templates.map(n => prefix + n),				redirects: 1,				prop: 'redirects',				rdprop: 'title',				rdnamespace: 10,				rdshow: '!fragment',				rdlimit: 'max',				formatversion: 2			}).always(response => {				let set = new Set(templates);				(((response || {}).query || {}).pages || []).forEach(page => { [page, ...(page.redirects || [])].forEach(o => {						set.add(o.title.slice(prefix.length));					}); });				re = new RegExp( `\\{\\{\\s*(?:${						[...set].map(n => { n = mw.util.escapeRegExp(n); return n[0].toLowerCase === n[0] ? n								: '[' + n[0] + n[0].toLowerCase + ']' + n.slice(1); }).join('|').replace(/ /g, '[ _]')					})\\s*\\|(?:\\{\\{[^]+?\\}\\}|[^])*?\\}\\}`, 'g'				);				edit(editor);			}); }	}]); });