Merge branch 'develop' into fix/CW-6944

This commit is contained in:
Sivin Varghese
2026-05-05 14:19:18 +05:30
committed by GitHub
16 changed files with 260 additions and 93 deletions
@@ -49,7 +49,11 @@ const rules = computed(() => ({
props.attribute.regexPattern && {
regexValidation: value => {
if (!value) return true;
return getRegexp(props.attribute.regexPattern).test(value);
try {
return getRegexp(props.attribute.regexPattern).test(value);
} catch {
return false;
}
},
}),
},
@@ -102,13 +102,14 @@ export default {
return this.v$.editedValue.$error;
},
errorMessage() {
if (this.v$.editedValue.url) {
if (this.v$.editedValue.url?.$invalid) {
return this.$t('CUSTOM_ATTRIBUTES.VALIDATIONS.INVALID_URL');
}
if (!this.v$.editedValue.regexValidation) {
return this.regexCue
? this.regexCue
: this.$t('CUSTOM_ATTRIBUTES.VALIDATIONS.INVALID_INPUT');
if (this.v$.editedValue.regexValidation?.$invalid) {
return (
this.regexCue ||
this.$t('CUSTOM_ATTRIBUTES.VALIDATIONS.INVALID_INPUT')
);
}
return this.$t('CUSTOM_ATTRIBUTES.VALIDATIONS.REQUIRED');
},
@@ -134,9 +135,12 @@ export default {
editedValue: {
required,
regexValidation: value => {
return !(
this.attributeRegex && !getRegexp(this.attributeRegex).test(value)
);
if (!this.attributeRegex || !value) return true;
try {
return getRegexp(this.attributeRegex).test(value);
} catch {
return false;
}
},
},
};
@@ -13,6 +13,9 @@ import {
triggerCharacters,
} from '@chatwoot/prosemirror-schema/src/mentions/plugin';
import imagePastePlugin from '@chatwoot/prosemirror-schema/src/plugins/image';
import embedPreviewPlugin from '@chatwoot/prosemirror-schema/src/plugins/embedPreview';
import trailingParagraphPlugin from '@chatwoot/prosemirror-schema/src/plugins/trailingParagraph';
import { embeds as markdownEmbeds } from 'dashboard/helper/markdownEmbeds';
import { toggleMark } from 'prosemirror-commands';
import { wrapInList } from 'prosemirror-schema-list';
import { toggleBlockType } from '@chatwoot/prosemirror-schema/src/menu/common';
@@ -77,6 +80,8 @@ export default {
plugins: [
imagePastePlugin(this.handleImageUpload),
this.createSlashPlugin(),
embedPreviewPlugin(markdownEmbeds),
trailingParagraphPlugin(),
],
isTextSelected: false, // Tracks text selection and prevents unnecessary re-renders on mouse selection
showSlashMenu: false,
@@ -113,6 +118,12 @@ export default {
this.focusEditorInputField();
}
},
beforeUnmount() {
if (editorView) {
editorView.destroy();
editorView = null;
}
},
methods: {
createSlashPlugin() {
return suggestionsPlugin({
@@ -488,4 +499,9 @@ export default {
max-height: 7.5rem;
overflow: auto;
}
.ProseMirror .cw-embed-preview {
max-width: 36rem;
margin: 0.5rem 0 1rem;
}
</style>
@@ -123,6 +123,13 @@ export function cleanSignature(signature) {
}
}
// Strip `\<newline>` hardbreak markers trailing `--` after a signature slice
const stripDelimiterHardbreaks = body =>
body.replace(/(--)\s*(?:\\\s*)+$/, '$1');
// Strip standalone blank-paragraph markers (`\` on their own lines).
const stripTrailingBlankLine = body => body.replace(/\n(?:\s*\\\n)+$/, '');
/**
* Adds the signature delimiter to the beginning of the signature.
*
@@ -227,13 +234,19 @@ export function removeSignature(body, signature, channelType) {
// trimming will ensure any spaces or new lines before the signature are removed
// This means we will have the delimiter at the end
if (signatureIndex > -1) {
newBody = newBody.substring(0, signatureIndex).trimEnd();
newBody = stripDelimiterHardbreaks(
newBody.substring(0, signatureIndex)
).trimEnd();
}
// Remove delimiter if it's at the end
if (newBody.endsWith(SIGNATURE_DELIMITER)) {
// if the delimiter is at the end, remove it
newBody = newBody.slice(0, -SIGNATURE_DELIMITER.length);
// strip any trailing blank-line markers
if (signatureIndex > -1) {
newBody = stripTrailingBlankLine(newBody);
}
}
return newBody;
@@ -0,0 +1,11 @@
import config from '../../../../config/markdown_embeds.yml';
// Gists rely on document.write() and can't render inline in the editor.
const NON_PREVIEWABLE_EMBEDS = new Set(['github_gist']);
export const embeds = Object.entries(config)
.filter(([key]) => !NON_PREVIEWABLE_EMBEDS.has(key))
.map(([, { regex, template }]) => ({
regex: new RegExp(regex),
template,
}));
@@ -336,6 +336,38 @@ describe('removeSignature', () => {
'This is a test\n\n'
);
});
it('strips blank-paragraph marker before the delimiter', () => {
expect(removeSignature('hey\n\n\\\n--\n\nHello there', 'Hello there')).toBe(
'hey'
);
});
it('strips multiple consecutive blank-paragraph markers before the delimiter', () => {
expect(
removeSignature('wewe\n\n\\\n\\\n\\\n--\n\nHello there', 'Hello there')
).toBe('wewe');
});
it('strips dangling hardbreak when signature shared a paragraph with "--"', () => {
expect(removeSignature('hey\n\n--\\\nHello there', 'Hello there')).toBe(
'hey\n\n'
);
});
it('preserves trailing backslash in user text when appending', () => {
expect(appendSignature('The path is C:\\', 'Best\nAgent')).toContain(
'C:\\'
);
expect(appendSignature('C:\\\n', 'Best\nAgent')).toContain('C:\\');
expect(appendSignature('C:\\\n\n', 'Best\nAgent')).toContain('C:\\');
});
it('preserves trailing backslash in user text when removing', () => {
expect(removeSignature('C:\\\n--\n\nBest\nAgent', 'Best\nAgent')).toContain(
'C:\\'
);
expect(removeSignature('C:\\\n--', 'no matching sig')).toContain('C:\\');
expect(removeSignature('C:\\\nBest\\\nAgent', 'Best\nAgent')).toContain(
'C:\\'
);
expect(removeSignature('notes\n\\\n--', 'no matching sig')).toContain('\\');
});
});
describe('removeSignature with stripped signature', () => {
@@ -4,6 +4,7 @@ import { required, minLength } from '@vuelidate/validators';
import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import { convertToAttributeSlug } from 'dashboard/helper/commons.js';
import { normalizeRegexPattern } from 'shared/helpers/Validators';
import { ATTRIBUTE_MODELS, ATTRIBUTE_TYPES } from './constants';
import NextButton from 'dashboard/components-next/button/Button.vue';
@@ -99,19 +100,10 @@ export default {
},
validations: {
displayName: {
required,
minLength: minLength(1),
},
description: {
required,
},
attributeModel: {
required,
},
attributeType: {
required,
},
displayName: { required, minLength: minLength(1) },
description: { required },
attributeModel: { required },
attributeType: { required },
attributeKey: {
required,
isKey(value) {
@@ -151,9 +143,7 @@ export default {
attribute_display_type: this.attributeType,
attribute_key: this.attributeKey,
attribute_values: this.attributeListValues,
regex_pattern: this.regexPattern
? new RegExp(this.regexPattern).toString()
: null,
regex_pattern: normalizeRegexPattern(this.regexPattern),
regex_cue: this.regexCue,
});
this.alertMessage = this.$t('ATTRIBUTES_MGMT.ADD.API.SUCCESS_MESSAGE');
@@ -2,7 +2,7 @@
import { useVuelidate } from '@vuelidate/core';
import { useAlert } from 'dashboard/composables';
import { required, minLength } from '@vuelidate/validators';
import { getRegexp } from 'shared/helpers/Validators';
import { getRegexp, normalizeRegexPattern } from 'shared/helpers/Validators';
import { ATTRIBUTE_TYPES } from './constants';
import NextButton from 'dashboard/components-next/button/Button.vue';
import TagInput from 'dashboard/components-next/taginput/TagInput.vue';
@@ -41,16 +41,9 @@ export default {
};
},
validations: {
displayName: {
required,
},
attributeType: {
required,
},
description: {
required,
minLength: minLength(1),
},
displayName: { required },
attributeType: { required },
description: { required, minLength: minLength(1) },
attributeKey: {
required,
isKey(value) {
@@ -118,7 +111,7 @@ export default {
},
setFormValues() {
const regexPattern = this.selectedAttribute.regex_pattern
? getRegexp(this.selectedAttribute.regex_pattern).source
? getRegexp(this.selectedAttribute.regex_pattern).toString()
: null;
this.displayName = this.selectedAttribute.attribute_display_name;
this.description = this.selectedAttribute.attribute_description;
@@ -144,9 +137,7 @@ export default {
attribute_description: this.description,
attribute_display_name: this.displayName,
attribute_values: this.updatedAttributeListValues,
regex_pattern: this.regexPattern
? new RegExp(this.regexPattern).toString()
: null,
regex_pattern: normalizeRegexPattern(this.regexPattern),
regex_cue: this.regexCue,
});
this.alertMessage = this.$t('ATTRIBUTES_MGMT.EDIT.API.SUCCESS_MESSAGE');
@@ -42,6 +42,7 @@ const createMarkdownInstance = (linkify = true) => {
quotes: '\u201c\u201d\u2018\u2019',
maxNesting: 20,
})
.disable(['lheading'])
.use(mentionPlugin)
.use(imgResizeManager)
.use(mila, {
@@ -101,6 +101,22 @@ export const getRegexp = regexPatternValue => {
);
};
/**
* Normalises a user-entered regex pattern into canonical `/source/flags` form.
* Strips `/.../flags` wrapping if the user included it, so `new RegExp` does
* not double-escape the slashes on save.
*
* @param {string} pattern - Raw pattern string from the form.
* @returns {?string} Canonical `/source/flags` string, or null when empty.
*/
export const normalizeRegexPattern = pattern => {
if (!pattern) return null;
const match = pattern.match(/^\/(.+)\/([gimsuy]*)$/);
const source = match ? match[1] : pattern;
const flags = match ? match[2] : '';
return new RegExp(source, flags).toString();
};
/**
* Checks if a string is a valid slug (letters, numbers, hyphens only, no spaces or other symbols).
* @param {string} value - The slug to validate.
@@ -33,6 +33,13 @@ describe('#MessageFormatter', () => {
<h2>tool</h2>`
);
});
it('should not render a setext heading when text is followed by "--"', () => {
const message = 'hy\n\n\\\n\\-\\-\n\nHello there';
const result = new MessageFormatter(message).formattedMessage;
expect(result).not.toMatch('<h2>');
expect(result).not.toMatch('<h1>');
});
});
describe('content with image and has "cw_image_height" query at the end of URL', () => {
@@ -9,6 +9,7 @@ import {
isNumber,
isDomain,
getRegexp,
normalizeRegexPattern,
isValidSlug,
} from '../Validators';
@@ -155,6 +156,30 @@ describe('#getRegexp', () => {
});
});
describe('#normalizeRegexPattern', () => {
it('returns null for empty values', () => {
expect(normalizeRegexPattern('')).toBeNull();
expect(normalizeRegexPattern(null)).toBeNull();
expect(normalizeRegexPattern(undefined)).toBeNull();
});
it('canonicalises a bare source', () => {
expect(normalizeRegexPattern('^[0-9]+$')).toBe('/^[0-9]+$/');
});
it('strips slash wrapping the user may include', () => {
expect(normalizeRegexPattern('/^[0-9]+$/')).toBe('/^[0-9]+$/');
});
it('preserves flags on wrapped input', () => {
expect(normalizeRegexPattern('/hello/gi')).toBe('/hello/gi');
});
it('throws for an invalid regex source', () => {
expect(() => normalizeRegexPattern('[')).toThrow();
});
});
describe('#isValidSlug', () => {
it('should return true for valid slugs', () => {
expect(isValidSlug('abc')).toEqual(true);
@@ -140,24 +140,15 @@ export default {
},
},
methods: {
labelClass(input) {
const { state } = input.context;
const hasErrors = state.invalid;
return !hasErrors ? 'text-n-slate-12' : 'text-n-ruby-10';
},
inputClass(input) {
const { state, family: classification, type } = input.context;
const hasErrors = state.invalid;
if (classification === 'box' && type === 'checkbox') {
return '';
}
if (type === 'phoneInput') {
this.hasErrorInPhoneInput = hasErrors;
this.hasErrorInPhoneInput = state.invalid;
}
if (!hasErrors) {
return `mt-1 rounded w-full py-2 px-3`;
}
return `mt-1 rounded w-full py-2 px-3 error`;
return 'mt-1 rounded w-full py-2 px-3';
},
isContactFieldRequired(field) {
return this.preChatFields.find(option => option.name === field).required;
@@ -176,7 +167,12 @@ export default {
return this.formValues[name] || null;
},
getValidation({ type, name, field_type, regex_pattern }) {
let regex = regex_pattern ? getRegexp(regex_pattern) : null;
const regex = regex_pattern ? getRegexp(regex_pattern) : null;
// FormKit caches the RegExp and calls .test() across keystrokes, so
// drop stateful g/y flags to stop lastIndex mutation flipping validity.
const matchRegex = regex
? new RegExp(regex.source, regex.flags.replace(/[gy]/g, ''))
: null;
const validations = {
emailAddress: 'email',
phoneNumber: ['startsWithPlus', 'isValidPhoneNumber'],
@@ -186,27 +182,32 @@ export default {
select: null,
number: null,
checkbox: false,
contact_attribute: regex ? [['matches', regex]] : null,
conversation_attribute: regex ? [['matches', regex]] : null,
contact_attribute: matchRegex ? [['matches', matchRegex]] : null,
conversation_attribute: matchRegex ? [['matches', matchRegex]] : null,
};
const validationKeys = Object.keys(validations);
const isRequired = this.isContactFieldRequired(name);
const validation = isRequired ? ['required'] : ['optional'];
const baseRules = isRequired ? [['required']] : [['optional']];
if (
validationKeys.includes(name) ||
validationKeys.includes(type) ||
validationKeys.includes(field_type)
!validationKeys.includes(name) &&
!validationKeys.includes(type) &&
!validationKeys.includes(field_type)
) {
const validationType =
validations[type] || validations[name] || validations[field_type];
const allValidations = validationType
? validation.concat(validationType)
: validation;
return allValidations.join('|');
return '';
}
return '';
const validationType =
validations[type] || validations[name] || validations[field_type];
if (!validationType) return baseRules;
// Normalise into array-of-arrays so RegExp objects in `['matches', regex]`
// survive without being stringified by FormKit.
const extraRules = Array.isArray(validationType)
? validationType.map(rule => (Array.isArray(rule) ? rule : [rule]))
: [[validationType]];
return baseRules.concat(extraRules);
},
findFieldType(type) {
if (type === 'link') {
@@ -283,7 +284,7 @@ export default {
}
: undefined
"
:label-class="context => `text-sm font-medium ${labelClass(context)}`"
label-class="text-sm font-medium text-n-slate-12"
:input-class="context => inputClass(context)"
:validation-messages="{
startsWithPlus: $t(
@@ -302,7 +303,7 @@ export default {
v-if="!hasActiveCampaign"
name="message"
type="textarea"
:label-class="context => `text-sm font-medium ${labelClass(context)}`"
label-class="text-sm font-medium text-n-slate-12"
:input-class="context => inputClass(context)"
:label="$t('PRE_CHAT_FORM.FIELDS.MESSAGE.LABEL')"
:placeholder="$t('PRE_CHAT_FORM.FIELDS.MESSAGE.PLACEHOLDER')"
@@ -330,16 +331,21 @@ export default {
@apply mt-2;
.formkit-inner {
input.error,
textarea.error,
select.error {
@apply outline-n-ruby-8 dark:outline-n-ruby-8 hover:outline-n-ruby-9 dark:hover:outline-n-ruby-9 focus:outline-n-ruby-9 dark:focus:outline-n-ruby-9;
}
input[type='checkbox'] {
@apply size-4 outline-none;
}
}
&[data-invalid] {
.formkit-label {
@apply text-n-ruby-10;
}
.formkit-inner input,
.formkit-inner textarea,
.formkit-inner select {
@apply outline-n-ruby-8 dark:outline-n-ruby-8 hover:outline-n-ruby-9 dark:hover:outline-n-ruby-9 focus:outline-n-ruby-9 dark:focus:outline-n-ruby-9;
}
}
}
[data-invalid] .formkit-message {
+2 -1
View File
@@ -34,7 +34,7 @@
"@amplitude/analytics-browser": "^2.11.10",
"@breezystack/lamejs": "^1.2.7",
"@chatwoot/ninja-keys": "1.2.3",
"@chatwoot/prosemirror-schema": "1.3.10",
"@chatwoot/prosemirror-schema": "1.3.11",
"@chatwoot/utils": "^0.0.52",
"@formkit/core": "^1.7.2",
"@formkit/vue": "^1.7.2",
@@ -121,6 +121,7 @@
"@iconify-json/ri": "^1.2.6",
"@iconify-json/teenyicons": "^1.2.2",
"@intlify/eslint-plugin-vue-i18n": "^3.2.0",
"@rollup/plugin-yaml": "^4.1.2",
"@size-limit/file": "^8.2.4",
"@vitest/coverage-v8": "3.0.5",
"@vue/test-utils": "^2.4.6",
+65 -16
View File
@@ -26,8 +26,8 @@ importers:
specifier: 1.2.3
version: 1.2.3
'@chatwoot/prosemirror-schema':
specifier: 1.3.10
version: 1.3.10
specifier: 1.3.11
version: 1.3.11
'@chatwoot/utils':
specifier: ^0.0.52
version: 0.0.52
@@ -281,6 +281,9 @@ importers:
'@intlify/eslint-plugin-vue-i18n':
specifier: ^3.2.0
version: 3.2.0(eslint@8.57.0)
'@rollup/plugin-yaml':
specifier: ^4.1.2
version: 4.1.2(rollup@4.59.0)
'@size-limit/file':
specifier: ^8.2.4
version: 8.2.6(size-limit@8.2.6)
@@ -460,8 +463,8 @@ packages:
'@chatwoot/ninja-keys@1.2.3':
resolution: {integrity: sha512-xM8d9P5ikDMZm2WbaCTk/TW5HFauylrU3cJ75fq5je6ixKwyhl/0kZbVN/vbbZN4+AUX/OaSIn6IJbtCgIF67g==}
'@chatwoot/prosemirror-schema@1.3.10':
resolution: {integrity: sha512-MtOXqFPHptFHu/AoIPhQ9TskVXOxOXCgBY/tgAtCAQRut978F7I3QxozQBECBz83ubsoXnBecpNjGNq0OPgONw==}
'@chatwoot/prosemirror-schema@1.3.11':
resolution: {integrity: sha512-+GptIqY73/EtojrhAKX4UKwZF7NUB47DMzgYxmx8Vu07DLKCGe+8JnbHJnR9oBy8p5sn5VOO1ihNf/4Pg2RzIQ==}
'@chatwoot/utils@0.0.52':
resolution: {integrity: sha512-e57uVqyVW4tj1gql4YJPNMykqMJPkETn5Y9AmHdhc6Y7oxDXfRXBq27fZrrDadLkZdn5RYVCZjfIhXOumyYv2Q==}
@@ -1122,6 +1125,24 @@ packages:
'@rails/ujs@7.1.400':
resolution: {integrity: sha512-YwvXm3BR5tn+VCAKYGycLejMRVZE3Ionj5gFjEeGXCZnI0Rpi+7dKpmyu90kdUY7dRUFpHTdu9zZceEzFLl38w==}
'@rollup/plugin-yaml@4.1.2':
resolution: {integrity: sha512-RpupciIeZMUqhgFE97ba0s98mOFS7CWzN3EJNhJkqSv9XLlWYtwVdtE6cDw6ASOF/sZVFS7kRJXftaqM2Vakdw==}
engines: {node: '>=14.0.0'}
peerDependencies:
rollup: '>=4.59.0'
peerDependenciesMeta:
rollup:
optional: true
'@rollup/pluginutils@5.3.0':
resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==}
engines: {node: '>=14.0.0'}
peerDependencies:
rollup: '>=4.59.0'
peerDependenciesMeta:
rollup:
optional: true
'@rollup/rollup-android-arm-eabi@4.59.0':
resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==}
cpu: [arm]
@@ -3016,8 +3037,8 @@ packages:
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
hasBin: true
js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
js-yaml@4.1.1:
resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==}
hasBin: true
jsdom@20.0.3:
@@ -3551,6 +3572,10 @@ packages:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
picomatch@4.0.4:
resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
engines: {node: '>=12'}
pidtree@0.6.0:
resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==}
engines: {node: '>=0.10'}
@@ -4315,6 +4340,10 @@ packages:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
tosource@2.0.0-alpha.3:
resolution: {integrity: sha512-KAB2lrSS48y91MzFPFuDg4hLbvDiyTjOVgaK7Erw+5AmZXNq4sFRVn8r6yxSLuNs15PaokrDRpS61ERY9uZOug==}
engines: {node: '>=10'}
totalist@3.0.1:
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
engines: {node: '>=6'}
@@ -4976,7 +5005,7 @@ snapshots:
hotkeys-js: 3.8.7
lit: 2.2.6
'@chatwoot/prosemirror-schema@1.3.10':
'@chatwoot/prosemirror-schema@1.3.11':
dependencies:
markdown-it-sup: 2.0.0
prosemirror-commands: 1.7.1
@@ -5328,7 +5357,7 @@ snapshots:
globals: 13.24.0
ignore: 5.2.4
import-fresh: 3.3.0
js-yaml: 4.1.0
js-yaml: 4.1.1
minimatch: 3.1.5
strip-json-comments: 3.1.1
transitivePeerDependencies:
@@ -5342,7 +5371,7 @@ snapshots:
globals: 14.0.0
ignore: 5.2.4
import-fresh: 3.3.0
js-yaml: 4.1.0
js-yaml: 4.1.1
minimatch: 3.1.5
strip-json-comments: 3.1.1
transitivePeerDependencies:
@@ -5547,7 +5576,7 @@ snapshots:
ignore: 6.0.2
import-fresh: 3.3.0
is-language-code: 3.1.0
js-yaml: 4.1.0
js-yaml: 4.1.1
json5: 2.2.3
jsonc-eslint-parser: 2.4.0
lodash: 4.17.21
@@ -5689,6 +5718,22 @@ snapshots:
'@rails/ujs@7.1.400': {}
'@rollup/plugin-yaml@4.1.2(rollup@4.59.0)':
dependencies:
'@rollup/pluginutils': 5.3.0(rollup@4.59.0)
js-yaml: 4.1.1
tosource: 2.0.0-alpha.3
optionalDependencies:
rollup: 4.59.0
'@rollup/pluginutils@5.3.0(rollup@4.59.0)':
dependencies:
'@types/estree': 1.0.8
estree-walker: 2.0.2
picomatch: 4.0.4
optionalDependencies:
rollup: 4.59.0
'@rollup/rollup-android-arm-eabi@4.59.0':
optional: true
@@ -7184,7 +7229,7 @@ snapshots:
imurmurhash: 0.1.4
is-glob: 4.0.3
is-path-inside: 3.0.3
js-yaml: 4.1.0
js-yaml: 4.1.1
json-stable-stringify-without-jsonify: 1.0.1
levn: 0.4.1
lodash.merge: 4.6.2
@@ -7851,7 +7896,7 @@ snapshots:
argparse: 1.0.10
esprima: 4.0.1
js-yaml@4.1.0:
js-yaml@4.1.1:
dependencies:
argparse: 2.0.1
@@ -8421,6 +8466,8 @@ snapshots:
picomatch@2.3.1: {}
picomatch@4.0.4: {}
pidtree@0.6.0: {}
pify@2.3.0: {}
@@ -8723,7 +8770,7 @@ snapshots:
prosemirror-dropcursor@1.8.1:
dependencies:
prosemirror-state: 1.4.3
prosemirror-transform: 1.10.0
prosemirror-transform: 1.12.0
prosemirror-view: 1.34.1
prosemirror-gapcursor@1.3.2:
@@ -8736,14 +8783,14 @@ snapshots:
prosemirror-history@1.4.1:
dependencies:
prosemirror-state: 1.4.3
prosemirror-transform: 1.10.0
prosemirror-transform: 1.12.0
prosemirror-view: 1.34.1
rope-sequence: 1.3.2
prosemirror-inputrules@1.4.0:
dependencies:
prosemirror-state: 1.4.3
prosemirror-transform: 1.10.0
prosemirror-transform: 1.12.0
prosemirror-keymap@1.2.2:
dependencies:
@@ -8783,7 +8830,7 @@ snapshots:
prosemirror-keymap: 1.2.2
prosemirror-model: 1.22.3
prosemirror-state: 1.4.3
prosemirror-transform: 1.10.0
prosemirror-transform: 1.12.0
prosemirror-view: 1.34.1
prosemirror-transform@1.10.0:
@@ -9308,6 +9355,8 @@ snapshots:
dependencies:
is-number: 7.0.0
tosource@2.0.0-alpha.3: {}
totalist@3.0.1: {}
tough-cookie@4.1.4:
+3 -2
View File
@@ -22,6 +22,7 @@ import { defineConfig } from 'vite';
import ruby from 'vite-plugin-ruby';
import path from 'path';
import vue from '@vitejs/plugin-vue';
import yaml from '@rollup/plugin-yaml';
const isLibraryMode = process.env.BUILD_MODE === 'library';
const isTestMode = process.env.TEST === 'true';
@@ -34,12 +35,12 @@ const vueOptions = {
},
};
let plugins = [ruby(), vue(vueOptions)];
let plugins = [ruby(), vue(vueOptions), yaml()];
if (isLibraryMode) {
plugins = [];
} else if (isTestMode) {
plugins = [vue(vueOptions)];
plugins = [vue(vueOptions), yaml()];
}
export default defineConfig({