Skip to content

Commit

Permalink
feat: ignore values for validation checks + persist to companion file…
Browse files Browse the repository at this point in the history
… on save
  • Loading branch information
NGPixel committed Feb 19, 2025
1 parent 0c03890 commit 5fbb277
Show file tree
Hide file tree
Showing 10 changed files with 150 additions and 32 deletions.
21 changes: 16 additions & 5 deletions src-electron/handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import fs from 'node:fs/promises'
import path from 'node:path'
import { pick, orderBy } from 'lodash-es'
import { encode, decode } from '@msgpack/msgpack'
import { getExtraFilePath } from './helpers'

/**
* Show the Open Dialog
Expand All @@ -11,10 +12,10 @@ import { encode, decode } from '@msgpack/msgpack'
*/
export async function openDocument (mainWindow) {
const files = await dialog.showOpenDialog(mainWindow, {
title: 'Open RFC / Internet Draft...',
title: 'Open Internet Draft / RFC...',
filters: [
{
name: 'RFC/Internet Draft',
name: 'Internet Draft/RFC',
extensions: ['md', 'txt', 'xml']
}
],
Expand All @@ -35,12 +36,19 @@ export async function openDocument (mainWindow) {
*/
export async function loadDocument (mainWindow, filePath) {
const fileContents = await fs.readFile(filePath, 'utf8')
let fileExtra = {}
try {
fileExtra = JSON.parse(await fs.readFile(getExtraFilePath(filePath), 'utf8'))
} catch (err) {
console.info(`No _draftforge.json extra file found or invalid format for ${filePath}.`)
}
const pathInfo = path.parse(filePath)
mainWindow.webContents.send('openDocument', {
type: pathInfo.ext.slice(1),
path: filePath,
fileName: pathInfo.base,
data: fileContents
data: fileContents,
extra: fileExtra
})
app.addRecentDocument(filePath)
}
Expand All @@ -52,9 +60,12 @@ export async function loadDocument (mainWindow, filePath) {
* @param {string} filePath Path where to save the document
* @param {string} contents Contents of the file
*/
export async function saveDocument (mainWindow, filePath, contents) {
export async function saveDocument (mainWindow, filePath, contents, extra) {
try {
await fs.writeFile(filePath, contents, 'utf8')
if (extra && Object.keys(extra).length > 0) {
await fs.writeFile(getExtraFilePath(filePath), JSON.stringify(extra, null, 2), 'utf8')
}
mainWindow.webContents.send('notify', {
message: 'Saved successfully.',
color: 'positive',
Expand Down Expand Up @@ -211,7 +222,7 @@ export function registerCallbacks (mainWindow, mainMenu, auth, git, lsp, tlm, te
openDocument(mainWindow)
})
ipcMain.on('save', (ev, opts) => {
saveDocument(mainWindow, opts.path, opts.data)
saveDocument(mainWindow, opts.path, opts.data, opts.extra)
})
ipcMain.handle('promptSave', async (ev, opts) => {
return git.performFetch({ dir: opts.dir, remote: opts.remote })
Expand Down
9 changes: 9 additions & 0 deletions src-electron/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,12 @@ export function mergeWithHeaders (headers = {}, key, value) {
headers[key] = value
}
}

/**
* Get the file path for the extra _draftforge.json file based on a document file path
*
* @param {string} filePath Document file path
*/
export function getExtraFilePath (filePath) {
return filePath.substring(0, filePath.lastIndexOf('.')) + '_draftforge.json'
}
79 changes: 69 additions & 10 deletions src/components/DrawerChecks.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ q-list
q-icon(v-else-if='editorStore.validationChecks[chk.key] === 2' name='mdi-information' size='xs' color='light-blue-5')
q-icon(v-else-if='editorStore.validationChecks[chk.key] === -1' name='mdi-close-circle' size='xs' color='red-5')
q-icon(v-else-if='editorStore.validationChecks[chk.key] === -2' name='mdi-alert-circle' size='xs' color='orange-5')
q-menu(touch-position context-menu auto-close)
q-list.bg-dark-1(separator)
q-item(clickable, @click='resetIgnores(chk.key)')
q-item-section(side)
q-icon(name='mdi-cancel' size='xs' color='amber')
q-item-section Reset all ignores for this check
q-expansion-item.bg-dark-5(
v-if='editorStore.validationChecksDetails[chk.key].count > 0'
group='checks'
Expand All @@ -63,7 +69,7 @@ q-list
no-caps
outline
color='purple-3'
disabled
@click='resetIgnores(chk.key)'
)
q-space
q-btn.q-mr-sm(
Expand Down Expand Up @@ -95,8 +101,15 @@ q-list
q-item-section(v-if='dtl.group', side)
q-badge(color='purple' text-color='white' :label='dtl.group')
q-item-section.text-caption {{ dtl.message }}
q-item-section(v-if='dtl.range', side)
q-badge(color='dark-3' text-color='white' :label='dtl.range.startLineNumber + ":" + dtl.range.startColumn')
q-item-section(side)
q-badge(v-if='dtl.range',color='dark-3' text-color='white') {{ dtl.range.startLineNumber + ":" + dtl.range.startColumn }} #[q-icon.q-ml-xs(name='mdi-dots-horizontal')]
q-btn(v-else color='dark-3' text-color='white' icon='mdi-dots-horizontal' padding='none xs' size='xs' unelevated)
q-menu(self='top left', anchor='top right' auto-close)
q-list.bg-dark-1(separator)
q-item(clickable, @click='ignoreCheck(chk.key, dtl.value)')
q-item-section(side)
q-icon(name='mdi-playlist-remove' size='xs' color='purple-2')
q-item-section Ignore "{{ dtl.value }}" for this document
</template>

<script setup>
Expand Down Expand Up @@ -164,10 +177,56 @@ const valChecks = [
}
]
// METHODS
// IGNORES METHODS
function resetIgnores (key) {
if (docsStore.activeDocument.extra?.checks?.[key]?.ignores) {
docsStore.activeDocument.extra.checks[key].ignores = []
}
$q.notify({
message: 'Ignores cleared!',
caption: 'All ignores for this check have been reset.',
color: 'positive',
icon: 'mdi-playlist-remove'
})
}
function ignoreCheck (key, value) {
if (!docsStore.activeDocument.extra.checks) {
docsStore.activeDocument.extra.checks = {}
}
if (!docsStore.activeDocument.extra.checks[key]) {
docsStore.activeDocument.extra.checks[key] = {}
}
if (!docsStore.activeDocument.extra.checks[key].ignores) {
docsStore.activeDocument.extra.checks[key].ignores = [value]
} else if (docsStore.activeDocument.extra.checks[key].ignores.includes(value)) {
$q.notify({
message: 'Ignore already added.',
caption: 'Run the validation check again to use it.',
color: 'orange-8',
icon: 'mdi-alert'
})
return
} else {
docsStore.activeDocument.extra.checks[key].ignores.push(value)
}
$q.notify({
message: 'Ignore added!',
caption: 'Run the validation check again to use it.',
color: 'positive',
icon: 'mdi-playlist-plus'
})
}
function getIgnores (key) {
return docsStore.activeDocument.extra?.checks?.[key]?.ignores ?? []
}
// VALIDATION METHODS
function articlesCheck (silent) {
const results = checkArticles(modelStore[docsStore.activeDocument.id].getValue())
const results = checkArticles(modelStore[docsStore.activeDocument.id].getValue(), getIgnores('articles'))
if (results.count < 1) {
editorStore.setValidationCheckState('articles', 1)
editorStore.setValidationCheckDetails('articles', [])
Expand All @@ -186,7 +245,7 @@ function articlesCheck (silent) {
}
function hyphenationCheck (silent = false) {
const results = checkHyphenation(modelStore[docsStore.activeDocument.id].getValue())
const results = checkHyphenation(modelStore[docsStore.activeDocument.id].getValue(), getIgnores('hyphenation'))
if (results.count < 1) {
editorStore.setValidationCheckState('hyphenation', 1)
editorStore.setValidationCheckDetails('hyphenation', [])
Expand All @@ -205,7 +264,7 @@ function hyphenationCheck (silent = false) {
}
function inclusiveLangCheck (silent = false) {
const results = checkInclusiveLanguage(modelStore[docsStore.activeDocument.id].getValue())
const results = checkInclusiveLanguage(modelStore[docsStore.activeDocument.id].getValue(), getIgnores('inclusiveLanguage'))
if (results.count < 1) {
editorStore.setValidationCheckState('inclusiveLanguage', 1)
editorStore.setValidationCheckDetails('inclusiveLanguage', [])
Expand All @@ -224,7 +283,7 @@ function inclusiveLangCheck (silent = false) {
}
function nonAsciiCheck (silent = false) {
const infos = checkNonAscii(modelStore[docsStore.activeDocument.id].getValue())
const infos = checkNonAscii(modelStore[docsStore.activeDocument.id].getValue(), getIgnores('nonAscii'))
if (infos < 1) {
editorStore.setValidationCheckState('nonAscii', 1)
if (!silent) {
Expand All @@ -241,7 +300,7 @@ function nonAsciiCheck (silent = false) {
}
function placeholdersCheck (silent = false) {
const results = checkCommonPlaceholders(modelStore[docsStore.activeDocument.id].getValue())
const results = checkCommonPlaceholders(modelStore[docsStore.activeDocument.id].getValue(), getIgnores('placeholders'))
if (results.count < 1) {
editorStore.setValidationCheckState('placeholders', 1)
editorStore.setValidationCheckDetails('placeholders', [])
Expand All @@ -260,7 +319,7 @@ function placeholdersCheck (silent = false) {
}
function repeatedWordsCheck (silent) {
const results = checkRepeatedWords(modelStore[docsStore.activeDocument.id].getValue())
const results = checkRepeatedWords(modelStore[docsStore.activeDocument.id].getValue(), getIgnores('repeatedWords'))
if (results.count < 1) {
editorStore.setValidationCheckState('repeatedWords', 1)
editorStore.setValidationCheckDetails('repeatedWords', [])
Expand Down
4 changes: 3 additions & 1 deletion src/stores/docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export const useDocsStore = defineStore('docs', {
path: doc.path ?? '',
fileName: doc.fileName ?? 'untitled-draft.xml',
data: doc.data ?? '',
extra: doc.extra ?? {},
isModified: false,
lastModifiedAt: DateTime.utc(),
lastSavedVersion: modelStore[docId].getAlternativeVersionId(),
Expand Down Expand Up @@ -144,7 +145,8 @@ export const useDocsStore = defineStore('docs', {
} else {
window.ipcBridge.emit('save', {
path: this.activeDocument.path,
data: modelStore[this.activeDocument.id].getValue()
data: modelStore[this.activeDocument.id].getValue(),
extra: cloneDeep(this.activeDocument.extra),
})
this.activeDocument.data = modelStore[this.activeDocument.id].getValue()
this.activeDocument.isModified = false
Expand Down
32 changes: 26 additions & 6 deletions src/tools/articles.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { decorationsStore } from 'src/stores/models'
import { sortBy } from 'lodash-es'

export function checkArticles (text) {
export function checkArticles (text, ignores = []) {
const partARgx = /(?<!(?:[aA]ppendix|[cC]onnection|[lL]ink|[nN]ode|Operator)) (?!(?:[aA] (?:AAA|Europe|[oO]ne|U[A-Z]|U-label|[uU]biquitous|[uU]nicast|[uU]nicode|[uU]nidir|[uU]nif|[uU]nion|[uU]nique|[uU]nit|[uU]nivers|[uU]sable|[uU]sability|[uU]sage|[uU]se|[uU]tility)|a uCDN|A and))[aA] [aeiouAEIOU]/g
const partARRgx = /(?!(?:[aA] (?:RADIUS|RECEIVE|RECOMMENDED|REFER|RELOAD|RST|REALM|RESERVATION|REQUEST|RESET|ROUTE|RPL)))[aA] R[A-Z]/g
const partBRgx = / (?!(?:[aA]n (?:hour|honest|honor|Mtrace|x-coordinate|x coordinate|A[A-Z]|E[A-Z]|F[A-Z]|H[A-Z]|I[A-Z]|L[A-Z]|L[0-9][A-Z]|M[A-Z]|N[A-Z]|O[A-Z]|R[A-Z]|R[0-9]|S[A-Z]|X[A-Z]|X\.509|xTR)))[aA]n [b-df-hj-np-tv-zB-DF-HJ-NP-TV-Z]/g
Expand All @@ -24,6 +24,9 @@ export function checkArticles (text) {

for (const [lineIdx, line] of textLines.entries()) {
for (const match of line.matchAll(partARgx)) {
if (ignores.includes(match[0])) {
continue
}
decorations.push({
options: {
hoverMessage: {
Expand All @@ -50,11 +53,15 @@ export function checkArticles (text) {
startColumn: match.index + 2,
endLineNumber: lineIdx + 1,
endColumn: match.index + match[0].length
}
},
value: match[0]
})
addToTermCount(match[0])
}
for (const match of line.matchAll(partARRgx)) {
if (ignores.includes(match[0])) {
continue
}
decorations.push({
options: {
hoverMessage: {
Expand All @@ -81,11 +88,15 @@ export function checkArticles (text) {
startColumn: match.index + 2,
endLineNumber: lineIdx + 1,
endColumn: match.index + match[0].length
}
},
value: match[0]
})
addToTermCount(match[0])
}
for (const match of line.matchAll(partBRgx)) {
if (ignores.includes(match[0])) {
continue
}
decorations.push({
options: {
hoverMessage: {
Expand All @@ -112,11 +123,15 @@ export function checkArticles (text) {
startColumn: match.index + 2,
endLineNumber: lineIdx + 1,
endColumn: match.index + match[0].length
}
},
value: match[0]
})
addToTermCount(match[0])
}
for (const match of line.matchAll(partCRgx)) {
if (ignores.includes(match[0])) {
continue
}
decorations.push({
options: {
hoverMessage: {
Expand All @@ -143,11 +158,15 @@ export function checkArticles (text) {
startColumn: match.index + 2,
endLineNumber: lineIdx + 1,
endColumn: match.index + match[0].length
}
},
value: match[0]
})
addToTermCount(match[0])
}
for (const match of line.matchAll(partCLFRgx)) {
if (ignores.includes(match[0])) {
continue
}
decorations.push({
options: {
hoverMessage: {
Expand All @@ -174,7 +193,8 @@ export function checkArticles (text) {
startColumn: match.index + 2,
endLineNumber: lineIdx + 1,
endColumn: match.index + match[0].length
}
},
value: match[0]
})
addToTermCount(match[0])
}
Expand Down
11 changes: 8 additions & 3 deletions src/tools/hyphenation.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { repeat, sortBy } from 'lodash-es'
const hyphenTermRgx = /[a-z]+(?:-[a-z]+)+/gi
const targetPropRgx = / target="([^"]+?)"/gi

export function checkHyphenation (text) {
export function checkHyphenation (text, ignores = []) {
const textLines = text.split('\n').map(line => {
return line.replaceAll(targetPropRgx, (m, val) => {
return ` target="${repeat(' ', val.length)}"`
Expand All @@ -21,6 +21,9 @@ export function checkHyphenation (text) {
for (const match of line.matchAll(hyphenTermRgx)) {
if (match[0].length > 3) {
const termLower = match[0].toLowerCase()
if (ignores.includes(termLower)) {
continue
}
if (!hyphenTerms.includes(termLower)) {
hyphenTerms.push(termLower)
}
Expand Down Expand Up @@ -65,7 +68,8 @@ export function checkHyphenation (text) {
key: crypto.randomUUID(),
group: occIdx + 1,
message: `${term} has alternate term(s)`,
range: termOcc.range
range: termOcc.range,
value: term
})
}
if (termCount[term]) {
Expand Down Expand Up @@ -101,7 +105,8 @@ export function checkHyphenation (text) {
startColumn: match.index + 2,
endLineNumber: lineIdx + 1,
endColumn: match.index + match[0].length
}
},
value: matchLower
})
if (termCount[matchLower]) {
termCount[matchLower]++
Expand Down
Loading

0 comments on commit 5fbb277

Please sign in to comment.