1
0
mirror of https://github.com/salexdv/bsl_console.git synced 2025-03-11 14:50:01 +02:00

Merge pull request from salexdv/develop

Подсказки в языке запросов, явные ссылки в пользовательских объектах, разделение подсказок для ссылок и объектов
This commit is contained in:
Alexander Shkuraev 2020-09-30 21:23:16 +03:00 committed by GitHub
commit c9976af95a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 860 additions and 27 deletions

@ -83,6 +83,7 @@ define([], function () {
"name_en":"FindByCode",
"description":"Осуществляет поиск элемента по его коду.",
"returns":"СправочникСсылка.<Имя справочника>; Неопределено",
"ref": "catalogs:ref",
"signature":{
"default":{
"СтрокаПараметров":"(Код, ПоискПоПолномуКоду, Родитель, Владелец) : СправочникСсылка.<Имя справочника>; Неопределено",
@ -100,6 +101,7 @@ define([], function () {
"name_en":"FindByDescription",
"description":"Осуществляет поиск элемента по его наименованию.",
"returns":"СправочникСсылка.<Имя справочника>; Неопределено",
"ref": "catalogs:ref",
"signature":{
"default":{
"СтрокаПараметров":"(Наименование, ТочноеСоответствие?, Родитель?, Владелец?) : СправочникСсылка.<Имя справочника>; Неопределено",
@ -117,6 +119,7 @@ define([], function () {
"name_en":"FindByAttribute",
"description":"Осуществляет поиск элемента по значению реквизита.",
"returns":"СправочникСсылка.<Имя справочника>; Неопределено",
"ref": "catalogs:ref",
"signature":{
"default":{
"СтрокаПараметров":"(ИмяРеквизита, ЗначениеРеквизита, Родитель?, Владелец?) : СправочникСсылка.<Имя справочника>; Неопределено",
@ -176,6 +179,7 @@ define([], function () {
"name_en":"GetRef",
"description":"Формирует ссылку из значения типа УникальныйИдентификатор. Данный уникальный идентификатор может быть в дальнейшем получен из ссылки методом УникальныйИдентификатор.",
"returns":"СправочникСсылка",
"ref": "catalogs:ref",
"signature":{
"default":{
"СтрокаПараметров":"(УникальныйИдентификатор) : СправочникСсылка",
@ -285,19 +289,22 @@ define([], function () {
"name":"ПустаяСсылка",
"name_en":"EmptyRef",
"description":"Получает пустое значение ссылки на справочник данного вида.",
"returns":"СправочникСсылка"
"returns":"СправочникСсылка",
"ref": "catalogs:ref"
},
"СоздатьГруппу":{
"name":"СоздатьГруппу",
"name_en":"CreateFolder",
"description":"Создает новую группу справочника.",
"returns":"СправочникОбъект"
"returns":"СправочникОбъект",
"ref": "catalogs:obj"
},
"СоздатьЭлемент":{
"name":"СоздатьЭлемент",
"name_en":"CreateItem",
"description":"Создает новый элемент справочника.",
"returns":"СправочникОбъект"
"returns":"СправочникОбъект",
"ref": "catalogs:obj"
}
},
"objMethods":{
@ -384,7 +391,8 @@ define([], function () {
"name":"Скопировать",
"name_en":"Copy",
"description":"Создает новый элемент справочника копированием существующего",
"returns":"СправочникОбъект"
"returns":"СправочникОбъект",
"ref": "catalogs:obj"
},
"Удалить":{
"name":"Удалить",
@ -471,7 +479,8 @@ define([], function () {
"name":"Скопировать",
"name_en":"Copy",
"description":"Создает новый элемент справочника копированием существующего",
"returns":"СправочникОбъект"
"returns":"СправочникОбъект",
"ref": "catalogs:obj"
},
"Уровень":{
"name":"Уровень",
@ -483,7 +492,8 @@ define([], function () {
"name":"ПолучитьОбъект",
"name_en":"GetObject",
"description":"Получает по ссылке объект, предназначенный для модификации справочника.",
"returns":"СправочникОбъект/Неопределено, Неопределено - объекта в базе нет (например, при обмене данными или после непосредственного удаления объекта, на который есть ссылки)."
"returns":"СправочникОбъект/Неопределено, Неопределено - объекта в базе нет (например, при обмене данными или после непосредственного удаления объекта, на который есть ссылки).",
"ref": "catalogs:obj"
},
"Пустая":{
"name":"Пустая",
@ -551,6 +561,7 @@ define([], function () {
"name_en":"FindByNumber",
"description":"Осуществляет поиск документа по номеру.",
"returns":"ДокументСсылка.<Имя документа>; Неопределено.",
"ref": "documents:ref",
"signature":{
"default":{
"СтрокаПараметров":"(НомерДокумента, ДатаИнтервала) : ДокументСсылка.<Имя справочника>; Неопределено",
@ -566,6 +577,7 @@ define([], function () {
"name_en":"FindByAttribute",
"description":"Осуществляет поиск документа по реквизиту.",
"returns":"ДокументСсылка",
"ref": "documents:ref",
"signature":{
"default":{
"СтрокаПараметров":"(ИмяРеквизита, ЗначениеРеквизита) : ДокументСсылка",
@ -609,6 +621,7 @@ define([], function () {
"name_en":"GetRef",
"description":"Формирует ссылку из значения типа УникальныйИдентификатор. Данный уникальный идентификатор может быть в дальнейшем получен из ссылки методом УникальныйИдентификатор.",
"returns":"ДокументСсылка",
"ref": "documents:ref",
"signature":{
"default":{
"СтрокаПараметров":"(УникальныйИдентификатор) : ДокументСсылка",
@ -686,13 +699,15 @@ define([], function () {
"name":"ПустаяСсылка",
"name_en":"EmptyRef",
"description":"Получает пустое значение ссылки на документ данного вида.",
"returns":"ДокументСсылка"
"returns":"ДокументСсылка",
"ref": "documents:ref"
},
"СоздатьДокумент":{
"name":"СоздатьДокумент",
"name_en":"CreateDocument",
"description":"Создает новый документ.",
"returns":"ДокументОбъект"
"returns":"ДокументОбъект",
"ref": "documents:obj"
}
},
"objMethods":{
@ -808,7 +823,8 @@ define([], function () {
"name":"Скопировать",
"name_en":"Copy",
"description":"Создает новый документ копированием существующего.",
"returns":"ДокументОбъект"
"returns":"ДокументОбъект",
"ref": "documents:obj"
},
"Удалить":{
"name":"Удалить",
@ -908,7 +924,8 @@ define([], function () {
"name":"ПолучитьОбъект",
"name_en":"GetObject",
"description":"Получает по ссылке объект, предназначенный для модификации докумнгьа.",
"returns":"ДокументОбъект/Неопределено, Неопределено - объекта в базе нет (например, при обмене данными или после непосредственного удаления объекта, на который есть ссылки)."
"returns":"ДокументОбъект/Неопределено, Неопределено - объекта в базе нет (например, при обмене данными или после непосредственного удаления объекта, на который есть ссылки).",
"ref": "documents:obj"
},
"Пустая":{
"name":"Пустая",

441
src/bslQuery.js Normal file

@ -0,0 +1,441 @@
define([], function () {
bslQuery = {
"functions": {
"РазностьДат": {
"name": "РАЗНОСТЬДАТ",
"name_en": "DATEDIFF",
"description": "Функция предназначена для получения разницы между двумя датами. Рассчитывает календарную разницу между двумя датами, поэтому ее нельзя использовать в местах, где необходимо рассчитать количество банковских или рабочих дней между двумя датами.",
"returns": "Тип: Число. Разность между датами в заданном типе.",
"signature": {
"default": {
"СтрокаПараметров": "(ВичитаемаяДата, ИсходнаяДата, ТипРазности): Число",
"Параметры": {
"ВичитаемаяДата": "Дата, вычитаемая дата",
"ИсходнаяДата": "Дата, исходная дата",
"ТипРазности": "Тип разности, одно из: СЕКУНДА, МИНУТа, ЧАС, ДЕНЬ, МЕСЯЦ, КВАРТАЛ, ГОД"
}
}
}
},
"Год": {
"name": "ГОД",
"name_en": "YEAR",
"description": "Данная функция предназначена для вычисления номера года из значения типа Дата",
"returns": "Тип: Число. Год",
"signature": {
"default": {
"СтрокаПараметров": "(Дата): Число",
"Параметры": {
"Дата": "Выражение, имеющее тип Дата"
}
}
}
},
"Квартал": {
"name": "КВАРТАЛ",
"name_en": "QUARTER",
"description": "Данная функция предназначена для вычисления номера квартала из значения типа Дата",
"returns": "Тип: Число. Номер квартала находится в диапазоне 1 – 4",
"signature": {
"default": {
"СтрокаПараметров": "(Дата): Число",
"Параметры": {
"Дата": "Выражение, имеющее тип Дата"
}
}
}
},
"Месяц": {
"name": "МЕСЯЦ",
"name_en": "MONTH",
"description": "Данная функция предназначена для вычисления номера месяца из значения типа Дата",
"returns": "Тип: Число. Номер месяца находится в диапазоне 1 – 12",
"signature": {
"default": {
"СтрокаПараметров": "(Дата): Число",
"Параметры": {
"Дата": "Выражение, имеющее тип Дата"
}
}
}
},
"ДеньГода": {
"name": "ДЕНЬГОДА",
"name_en": "DAYOFYEAR",
"description": "Данная функция предназначена для вычисления дня года из значения типа Дата",
"returns": "Тип: Число. День года находится в диапазоне 1 – 366",
"signature": {
"default": {
"СтрокаПараметров": "(Дата): Число",
"Параметры": {
"Дата": "Выражение, имеющее тип Дата"
}
}
}
},
"День": {
"name": "ДЕНЬ",
"name_en": "DAY",
"description": "Данная функция предназначена для вычисления дня месяца из значения типа Дата",
"returns": "Тип: Число. День месяца находится в диапазоне 1 – 31",
"signature": {
"default": {
"СтрокаПараметров": "(Дата): Число",
"Параметры": {
"Дата": "Выражение, имеющее тип Дата"
}
}
}
},
"Неделя": {
"name": "НЕДЕЛЯ",
"name_en": "WEEK",
"description": "Данная функция предназначена для вычисления номера недели года из значения типа Дата",
"returns": "Тип: Число. Номер недели года",
"signature": {
"default": {
"СтрокаПараметров": "(Дата): Число",
"Параметры": {
"Дата": "Выражение, имеющее тип Дата"
}
}
}
},
"ДеньНедели": {
"name": "ДЕНЬНЕДЕЛИ",
"name_en": "WEEKDAY",
"description": "Данная функция предназначена для вычисления дня недели из значения типа Дата",
"returns": "Тип: Число. День недели находится в диапазоне 1 (понедельник) – 7 (воскресенье)",
"signature": {
"default": {
"СтрокаПараметров": "(Дата): Число",
"Параметры": {
"Дата": "Выражение, имеющее тип Дата"
}
}
}
},
"Час": {
"name": "ЧАС",
"name_en": "HOUR",
"description": "Данная функция предназначена для вычисления часа суток из значения типа Дата",
"returns": "Тип: Число. Час суток находится в диапазоне 0 – 23",
"signature": {
"default": {
"СтрокаПараметров": "(Дата): Число",
"Параметры": {
"Дата": "Выражение, имеющее тип Дата"
}
}
}
},
"Минута": {
"name": "МИНУТА",
"name_en": "MINUTE",
"description": "Данная функция предназначена для вычисления минуты часа из значения типа Дата",
"returns": "Тип: Число. Минута часа находится в диапазоне 0 – 59",
"signature": {
"default": {
"СтрокаПараметров": "(Дата): Число",
"Параметры": {
"Дата": "Выражение, имеющее тип Дата"
}
}
}
},
"Секунда": {
"name": "СЕКУНДА",
"name_en": "SECOND",
"description": "Данная функция предназначена для вычисления секунды минуты из значения типа Дата",
"returns": "Тип: Число. Секунда минуты находится в диапазоне 0 – 59",
"signature": {
"default": {
"СтрокаПараметров": "(Дата): Число",
"Параметры": {
"Дата": "Выражение, имеющее тип Дата"
}
}
}
},
"НачалоПериода": {
"name": "НАЧАЛОПЕРИОДА",
"name_en": "BEGINOFPERIOD",
"description": "Функция предназначена для получения даты начала периода по дате, принадлежащей этому периоду",
"returns": "Тип: Дата. Начало периода в заданном типе",
"signature": {
"default": {
"СтрокаПараметров": "(ДатаПериода, ТипПериода): Дата",
"Параметры": {
"ДатаПериода": "Дата, выражение, указывающее дату периода",
"ТипПериода": "Тип периода, одно из: МИНУТА, ЧАС, ДЕНЬ, НЕДЕЛЯ, МЕСЯЦ, КВАРТАЛ, ГОД, ДЕКАДА, ПОЛУГОДИЕ"
}
}
}
},
"КонецПериода": {
"name": "КОНЕЦПЕРИОДА",
"name_en": "ENDOFPERIOD",
"description": "Функция предназначена для получения даты окончания периода по дате, принадлежащей этому периоду",
"returns": "Тип: Дата. Конец периода в заданном типе",
"signature": {
"default": {
"СтрокаПараметров": "(ДатаПериода, ТипПериода): Дата",
"Параметры": {
"ДатаПериода": "Дата, выражение, указывающее дату периода",
"ТипПериода": "Тип периода, одно из: МИНУТА, ЧАС, ДЕНЬ, НЕДЕЛЯ, МЕСЯЦ, КВАРТАЛ, ГОД, ДЕКАДА, ПОЛУГОДИЕ"
}
}
}
},
"ДобавитьКДате": {
"name": "ДОБАВИТЬКДАТЕ",
"name_en": "DATEADD",
"description": "Функция предназначена для прибавления к дате некоторой величины.",
"returns": "Тип: Дата. Новое значение даты",
"signature": {
"default": {
"СтрокаПараметров": "(ИсходнаяДата, ТипПериода, ВеличинаУвеличения): Дата",
"Параметры": {
"ИсходнаяДата": "Дата, исходная дата, к значению которой требуется добавить заданную величину, определяемую вторым и третьим параметрами",
"ТипПериода": "тип увеличения – одно из: СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, НЕДЕЛЯ, МЕСЯЦ, КВАРТАЛ, ГОД, ДЕКАДА, ПОЛУГОДИЕ. При выборе значения ДЕКАДА к исходной дате будет добавлено количество дней, умноженное на 10",
"ВеличинаУвеличения": "Число, величина, на которую требуется увеличить дату, задаваемую первым параметром (дробная часть игнорируется)"
}
}
}
},
"Подстрока": {
"name": "ПОДСТРОКА",
"name_en": "SUBSTRING",
"description": "Данная функция предназначена для выделения подстроки из строки",
"returns": "Тип: Строка. Новое значение строки",
"signature": {
"default": {
"СтрокаПараметров": "(ИсходнаяСтрока, НачальныйНомер, ЧислоСимволов): Дата",
"Параметры": {
"ИсходнаяДата": "Строка, исходная строка, из которой необходимо получить подстроку",
"НачальныйНомер": "Число, позиция символа, с которого начинается выделяемая из строки подстрока",
"ЧислоСимволов": "Число, длина выделяемой подстроки"
}
}
}
},
"Сумма": {
"name": "СУММА",
"name_en": "SUM",
"description": "Функция вычисляет арифметическую сумму всех попавших в выборку значений поля",
"returns": "Тип: Число, Сумма всех числовых значений поля",
"signature": {
"default": {
"СтрокаПараметров": "(Число): Число",
"Параметры": {
"Число": "Числовое значение, сумму которого необходимо вычислить"
}
}
}
},
"Минимум": {
"name": "МИНИМУМ",
"name_en": "MIN",
"description": "Функция вычисляет минимальное значение из всех попавших в выборку значений поля",
"returns": "Минимальное полученное значение",
"signature": {
"default": {
"СтрокаПараметров": "(Значение): Произвольный",
"Параметры": {
"Значение": "В качестве параметра функции можно указывать выражения, содержащие значения любого типа. Не может применяться к выражениям с типом ХранилищеЗначения и Строкам неограниченной длины."
}
}
}
},
"Максимум": {
"name": "МАКСИМУМ",
"name_en": "MAX",
"description": "Функция вычисляет максимальное значение из всех попавших в выборку значений поля",
"returns": "Максимальное полученное значение",
"signature": {
"default": {
"СтрокаПараметров": "(Значение): Произвольный",
"Параметры": {
"Значение": "В качестве параметра функции можно указывать выражения, содержащие значения любого типа. Не может применяться к выражениям с типом ХранилищеЗначения и Строкам неограниченной длины."
}
}
}
},
"Среднее": {
"name": "СРЕДНЕЕ",
"name_en": "AVG",
"description": "Функция вычисляет среднее значение всех попавших в выборку значений поля.",
"returns": "Тип: Число, Среднее значение всех числовых значений поля",
"signature": {
"default": {
"СтрокаПараметров": "(Число): Число",
"Параметры": {
"Число": "Числовое значение, для которого необходимо вычислить среднее значение"
}
}
}
},
"Количество": {
"name": "КОЛИЧЕСТВО",
"name_en": "COUNT",
"description": "Функция подсчитывает количество значений поля, указанного в параметре, попавших в выборку. В отличие от других агрегатных функций функция КОЛИЧЕСТВО допускает три способа использования",
"returns": "Тип: Число, количество полученных значений",
"signature": {
"default": {
"СтрокаПараметров": "(Значение): Число",
"Параметры": {
"Значение": "Значение произвольного типа, количество которого необходимо подсчитать"
}
},
"Различные": {
"СтрокаПараметров": "(РАЗЛИЧНЫЕ Значение): Число",
"Параметры": {
"Значение": "Значение произвольного типа, количество различных которого необходимо подсчитать"
}
},
"ОбщееКоличество": {
"СтрокаПараметров": "(*): Число",
"Параметры": {
"*": "Для подсчета общего количества строк в запросе"
}
}
}
},
"АвтономерЗаписи": {
"name": "АВТОНОМЕРЗАПИСИ",
"name_en": "RECORDAUTONUMBER",
"description": "Данная функция может быть использована в списке выборки при создании временной таблицы для создания поля с уникальным, последовательно возрастающим значением во временной таблице",
"returns": "Тип: Число, Уникальный номер записи временной таблицы"
},
"ЕстьNull": {
"name": "ЕСТЬNULL",
"name_en": "ISNULL",
"description": "Функция предназначена для замены значения NULL на другое значение",
"returns": "Тип: Произвольный, значение первого параметра, в случае, если первый параметр не содержит значение NULL, значение второго параметра в противном случае.",
"signature": {
"default": {
"СтрокаПараметров": "(ПроверяемыйПараметр, ЗначениеЕслиNULL): Произвольный",
"Параметры": {
"ПроверяемыйПараметр": "Произвольный, значение проверяемого параметра, которое будет возвращено, если он не равен NULL",
"ЗначениеЕслиNULL": "Произвольный, значение, которое будет возвращено, если проверяемый параметр равен NULL"
}
}
}
},
"Представление": {
"name": "ПРЕДСТАВЛЕНИЕ",
"name_en": "PRESENTATION",
"description": "Данная функция предназначена для получения строкового представления значения произвольного типа. Результат работы функции не может быть использован внутри других функций, за исключением функции ПРЕДСТАВЛЕНИЕ",
"returns": "Тип: Строка, Строковое представление переданного значения",
"signature": {
"default": {
"СтрокаПараметров": "(Значение): Строка",
"Параметры": {
"Значение": "Произвольное значение, для которого необходимо получить строковое представление"
}
}
}
},
"ПредставлениеСсылки": {
"name": "ПРЕДСТАВЛЕНИЕССЫЛКИ",
"name_en": "REFPRESENTATION",
"description": "Позволяет получать представление ссылочного значения",
"returns": "Тип: Строка, Строковое представление переданной ссылки",
"signature": {
"default": {
"СтрокаПараметров": "(Ссылка): Строка",
"Параметры": {
"Ссылка": "Ссылка, для которой необходимо получить строковое представление"
}
}
}
},
"ТипЗначения": {
"name": "ТИПЗНАЧЕНИЯ",
"name_en": "VALUETYPE",
"description": "Функция определения типа значения в запросе.",
"returns": "Тип значения",
"signature": {
"default": {
"СтрокаПараметров": "(Значение): Тип",
"Параметры": {
"Значение": "Значение, для которого необходимо определить тип"
}
}
}
},
"СгриппированоПо": {
"name": "СГРУППИРОВАНОПО",
"name_en": "GROUPEDBY",
"description": "Функция предназначена для различения наборов, по которым ведется группировка.",
"returns": "Булево, ИСТИНА - для записей, которые были получены для группировки по этому полю, ЛОЖЬ - в противном случае",
"signature": {
"default": {
"СтрокаПараметров": "(Выражение): Булево",
"Параметры": {
"Выражение": "Столбец или выражение, которое содержит столбец в предложении СГРУППИРОВАТЬ ПО"
}
}
}
},
"ДатаВремя": {
"name": "ДАТАВРЕМЯ",
"name_en": "DATETIME",
"description": "Функция для получения даты на основании переданных значений года, месяца, дня месяца и т.д.",
"returns": "Дата, полученное значение даты",
"signature": {
"default": {
"СтрокаПараметров": "(Год, Месяц, ДеньМесяца, Час?, Минута?, Сукунда?): Дата",
"Параметры": {
"Год": "Число, значение года для получения даты",
"Месяц": "Число, значение месяца для получения даты (1-12)",
"ДеньМесяца": "Число, значение дня месяца для получения даты (1-31)",
"Час": "Число, значение часа для получения даты (0-23)",
"Минута": "Число, значение минуты для получения даты (0-59)",
"Сукунда": "Число, значение секунды для получения даты (0-59)"
}
}
}
},
"Значение": {
"name": "ЗНАЧЕНИЕ",
"name_en": "VALUE",
"description": "Функция для получения значений перечислений, а также предопределенных значений и пустых ссылок для справочников, планов видов характеристик, планов счетов, планов видов расчетов",
"returns": "Значение перечисления / предопределенное значение / пустая ссылка",
"signature": {
"default": {
"СтрокаПараметров": "(ПредставлениеЗначения): Произвольный",
"Параметры": {
"ПредставлениеЗначения": "Представление значения, для которого необходмо получить значение"
}
}
}
},
"Тип": {
"name": "ТИП",
"name_en": "TYPE",
"description": "Функция для получения типа по указанному имени типа",
"returns": "Тип",
"signature": {
"default": {
"СтрокаПараметров": "(ИмяТипа): Тип",
"Параметры": {
"ИмяТипа": "Имя примитивного типа, либо имя таблицы, тип ссылки которой нужно получить"
}
}
}
}
},
"values" : {
"Справочник": {
"ref": "catalogs"
},
"Документ": {
"ref": "documents"
},
"Перечисление": {
"ref": "enums"
}
}
}
});

@ -249,6 +249,36 @@ class bslHelper {
}
/**
* Determines if string contain query value constructor (ЗНАЧЕНИЕ|VALUE)
*
*
* @returns {bool}
*/
requireQueryValue() {
let exp = this.getFuncName();
return (exp == 'value' || exp == 'значение');
}
/**
* Removes from array of suggestions duplicated items
*
* @returns {array} suggestions
*/
deleteSuggesstionsDuplicate(suggestions) {
let i = 0;
while (i < suggestions.length) {
if (suggestions.some(suggest => (suggest.label === suggestions[i].label && suggest != suggestions[i])))
suggestions.splice(i, 1)
else
i++;
}
}
/**
* Fills array of completition for language keywords, classes, global functions,
* global variables and system enumarations
@ -367,7 +397,7 @@ class bslHelper {
* @param {object} obj object from BSL-JSON dictionary
* @param {sting} methodsName the name of node (objMethods, refMethods)
*/
getMetadataMethods(suggestions, obj, methodsName) {
getMetadataMethods(suggestions, obj, methodsName, metadataKey, medatadaName) {
if (obj.hasOwnProperty(methodsName)) {
@ -387,6 +417,12 @@ class bslHelper {
if (mvalue.hasOwnProperty('ref'))
ref = mvalue.ref;
if (ref && ref.indexOf(':') != -1) {
if (metadataKey && medatadaName) {
ref = metadataKey + '.' + medatadaName + '.' +((ref.indexOf(':obj') != -1) ? 'obj' : 'ref');
}
}
if (ref || signatures.length) {
// If the attribute contains a ref, we need to run the command to save the position of ref
command = { id: 'vs.editor.ICodeEditor:1:saveref', arguments: [{ "name": mvalue[this.nameField], "data": { "ref": ref, "sig": signatures } }] }
@ -424,7 +460,7 @@ class bslHelper {
let refArray = arrRefs[i].trim().split('.');
if (refArray.length == 2) {
if (refArray.length >= 2) {
let itemName = refArray[0];
let subItemName = refArray[1];
@ -436,9 +472,11 @@ class bslHelper {
}
else {
let methodsName = (refArray.length == 3 && refArray[2] == 'obj') ? 'objMethods' : 'refMethods'
if (this.objectHasProperties(bslMetadata, itemName, 'items', subItemName, 'properties')) {
this.fillSuggestionsForMetadataItem(suggestions, bslMetadata[itemName].items[subItemName]);
this.getMetadataMethods(suggestions, bslMetadata[itemName], 'refMethods');
this.getMetadataMethods(suggestions, bslMetadata[itemName], methodsName, itemName, subItemName);
}
}
@ -446,6 +484,10 @@ class bslHelper {
}
}
if (1 < arrRefs.length)
this.deleteSuggesstionsDuplicate(suggestions);
}
}
@ -454,7 +496,7 @@ class bslHelper {
* Fills the suggestions for reference-type object
* if a reference was found in the previous position
*
* @param {aaray} suggestions the list of suggestions
* @param {array} suggestions the list of suggestions
*/
getRefCompletition(suggestions) {
@ -538,7 +580,13 @@ class bslHelper {
for (const [ikey, ivalue] of Object.entries(value)) {
if (ikey.toLowerCase() == objName) {
this.fillSuggestionsForMetadataItem(suggestions, ivalue);
this.getMetadataMethods(suggestions, ivalue, 'methods', null, null);
if (ivalue.hasOwnProperty('ref'))
this.getRefSuggestions(suggestions, ivalue)
}
}
@ -784,6 +832,57 @@ class bslHelper {
}
/**
* Looks metadata's method by name in certain types of methods
* like 'methods' (CatalogsManager, DocumentsManages),
* 'objMethods' - methods belong to the object
* 'refMethods' - methods belong to the ref
*
* @param {object} metadataObj metadata objects from BSL-JSON dictionary
* @param {string} metadataFunc name of method (func)
*
* @returns {object} object of method or false
*/
findMetadataMethodByName(metadataObj, methodsName, metadataFunc) {
if (metadataObj.hasOwnProperty(methodsName)) {
for (const [key, value] of Object.entries(metadataObj[methodsName])) {
if (value[this.nameField].toLowerCase() == metadataFunc) {
return value;
}
}
}
return false;
}
/**
* Finds metadata's method by name
*
* @param {object} metadataObj metadata objects from BSL-JSON dictionary
* @param {string} metadataFunc name of method (func)
*
* @returns {object} object of method or false
*/
getMetadataMethodByName(metadataObj, metadataFunc) {
let method = this.findMetadataMethodByName(metadataObj, 'methods', metadataFunc);
if (!method)
method = this.findMetadataMethodByName(metadataObj, 'objMethods', metadataFunc);
if (!method)
method = this.findMetadataMethodByName(metadataObj, 'refMethods', metadataFunc);
return method;
}
/**
* Fills array of completition for metadata subitem like catalog of products
*
@ -828,9 +927,13 @@ class bslHelper {
for (const [ikey, ivalue] of Object.entries(value.items)) {
if (ikey.toLowerCase() == metadataItem) {
let methodDef = this.getMetadataMethodByName(value, metadataFunc);
let methodsName = (methodDef && methodDef.hasOwnProperty('ref') && methodDef.ref.indexOf(':obj') != -1) ? 'objMethods' : 'refMethods';
itemExists = true;
this.fillSuggestionsForMetadataItem(suggestions, ivalue);
this.getMetadataMethods(suggestions, value, 'objMethods');
this.getMetadataMethods(suggestions, value, methodsName, key, ikey);
}
}
@ -1171,15 +1274,132 @@ class bslHelper {
}
/**
* Completition provider for query language
* Fills array of completition for query values
*
* @param {object} langDef - query language definition
*
* @returns {array} array of completition
* @param {array} suggestions array of suggestions for provideCompletionItems
* @param {object} data objects from BSL-JSON dictionary
* @param {CompletionItemKind} kind - monaco.languages.CompletionItemKind (class, function, constructor etc.)
*/
getQueryCompletition(langDef) {
getQueryValuesCompletition(suggestions, data, kind) {
let expArray = this.getExpressioArray();
if (expArray) {
let regex = /\((.*?)\.(?:(.*?)\.)?/.exec(expArray[expArray.length - 1]);
let metadataName = regex && 1 < regex.length ? regex[1] : '';
let metadataItem = regex && 2 < regex.length ? regex[2] : '';
for (const [key, value] of Object.entries(data)) {
if (!metadataName) {
let suggestion = {
label: key,
kind: kind,
insertText: key,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
}
if (value.hasOwnProperty('ref')) {
suggestion.insertText += '.';
suggestion['command'] = { id: 'editor.action.triggerSuggest', title: 'suggest_type' };
}
else {
suggestion.insertText += '"';
}
suggestions.push(suggestion);
}
else {
if (key.toLowerCase() == metadataName) {
if (value.hasOwnProperty('ref') && bslMetadata.hasOwnProperty(value.ref) && bslMetadata[value.ref].hasOwnProperty('items')) {
if (metadataItem) {
for (const [mkey, mvalue] of Object.entries(bslMetadata[value.ref].items)) {
if (mkey.toLowerCase() == metadataItem) {
if (value.ref == 'enums' && mvalue.hasOwnProperty('properties')) {
for (const [ikey, ivalue] of Object.entries(bslMetadata[value.ref].items[mkey].properties)) {
suggestions.push({
label: ikey,
kind: kind,
insertText: ikey + ')',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
});
}
}
else if (mvalue.hasOwnProperty('predefined')) {
for (const [pkey, pvalue] of Object.entries(bslMetadata[value.ref].items[mkey].predefined)) {
suggestions.push({
label: pkey,
kind: kind,
insertText: pkey + ')',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
});
}
}
let EmptyRef = engLang ? 'EmptyRef' : 'ПустаяСсылка';
suggestions.push({
label: EmptyRef,
kind: kind,
insertText: EmptyRef + ')',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
});
}
}
}
else {
for (const [mkey, mvalue] of Object.entries(bslMetadata[value.ref].items)) {
suggestions.push({
label: mkey,
kind: kind,
insertText: mkey + '.',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
command: { id: 'editor.action.triggerSuggest', title: 'suggest_type' }
});
}
}
}
}
}
}
}
}
/**
* Fills array of completition for query language`s keywords
* and expressions
*
* @param {array} suggestions array of suggestions for provideCompletionItems
* @param {object} langDef query language definition
* @param {CompletionItemKind} kind - monaco.languages.CompletionItemKind (class, function, constructor etc.)
*/
getQueryCommonCompletition(suggestions, langDef, kind) {
let suggestions = [];
let word = this.word;
if (word) {
@ -1209,10 +1429,10 @@ class bslHelper {
expression = '';
}
if (expression) {
if (expression && !suggestions.some(suggest => suggest.label === expression)) {
suggestions.push({
label: expression,
kind: monaco.languages.CompletionItemKind.Function,
kind: kind,
insertText: expression,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
});
@ -1223,6 +1443,64 @@ class bslHelper {
}
}
/**
* Fills array of completition for params of query
*
* @param {array} suggestions array of suggestions for provideCompletionItems
* @param {CompletionItemKind} kind - monaco.languages.CompletionItemKind (class, function, constructor etc.)
*/
getQueryParamsCompletition(suggestions, kind) {
if (this.lastRawExpression.startsWith('&')) {
const matches = this.model.findMatches('&(.*?)[\\s\\n,]', true, true, false, null, true)
for (let idx = 0; idx < matches.length; idx++) {
let match = matches[idx];
let paramName = match.matches[match.matches.length - 1];
if (paramName && !suggestions.some(suggest => suggest.insertText === paramName)) {
suggestions.push({
label: '&' + paramName,
kind: kind,
insertText: paramName,
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet
});
}
}
}
}
/**
* Completition provider for query language
*
* @param {object} langDef - query language definition
*
* @returns {array} array of completition
*/
getQueryCompletition(langDef) {
let suggestions = [];
if (!this.requireQueryValue()) {
if (this.lastOperator != '"')
this.getCommonCompletition(suggestions, bslQuery.functions, monaco.languages.CompletionItemKind.Function, true);
this.getQueryCommonCompletition(suggestions, langDef, monaco.languages.CompletionItemKind.Module);
this.getQueryParamsCompletition(suggestions, monaco.languages.CompletionItemKind.Enum);
}
else {
this.getQueryValuesCompletition(suggestions, bslQuery.values, monaco.languages.CompletionItemKind.Enum);
}
if (suggestions.length)
return { suggestions: suggestions }
else
@ -1670,6 +1948,24 @@ class bslHelper {
}
/**
* Signature help provider for query language
*
* @returns {object} helper
*/
getQuerySigHelp() {
if (this.lastOperator != ')' && !this.requireQueryValue()) {
let helper = this.getCommonSigHelp(bslQuery.functions);
if (helper)
return new SignatureHelpResult(helper);
}
}
/**
* Updates bslMetadata from JSON-string which
* was received from 1C

@ -151,7 +151,7 @@ define([], function () {
'РАЗНОСТЬДАТ', 'DATEDIFF', 'СЕКУНДА', 'SECOND', 'СПЕЦСИМВОЛ',
'ESCAPE', 'СРЕДНЕЕ', 'AVG', 'ССЫЛКА', 'REFS', 'СТРОКА', 'STRING',
'СУММА', 'SUM', 'ТОГДА', 'THEN', 'УБЫВ', 'DESC', 'ЧАС', 'HOUR',
'ЧИСЛО', 'NUMBER', 'NULL'
'ЧИСЛО', 'NUMBER', 'NULL', 'КОГДА', 'WHEN'
],
queryOperators: /[=><+\-*\/%;,]+/,
// The main tokenizer for our languages
@ -357,7 +357,7 @@ define([], function () {
query: {
languageDef: query_language,
completionProvider: {
triggerCharacters: ['.', '"'],
triggerCharacters: ['.', '(', '&'],
provideCompletionItems: function (model, position) {
let bsl = new bslHelper(model, position);
return bsl.getQueryCompletition(query_language);
@ -367,7 +367,12 @@ define([], function () {
provideFoldingRanges: () => {}
},
signatureProvider: {
provideSignatureHelp: () => {}
signatureHelpTriggerCharacters: ['(', ','],
signatureHelpRetriggerCharacters: [')'],
provideSignatureHelp: (model, position) => {
let bsl = new bslHelper(model, position);
return bsl.getQuerySigHelp();
}
},
hoverProvider: {
provideHover: () => {}

@ -1,6 +1,6 @@
require.config( { 'vs/nls': { availableLanguages: { '*': "ru" } } } );
define(['bslGlobals', 'bslMetadata', 'snippets', 'bsl_language', 'vs/editor/editor.main', 'actions'], function () {
define(['bslGlobals', 'bslMetadata', 'snippets', 'bsl_language', 'vs/editor/editor.main', 'actions', 'bslQuery'], function () {
selectionText = '';
engLang = false;

@ -360,6 +360,7 @@ describe("Проверка автокомлита и подсказок реда
let strJSON = `{
"customObjects":{
"_СтруктураВыгрузки":{
"ref": "classes.Структура",
"properties":{
"Номенклатура":{
"name":"Номенклатура",
@ -369,6 +370,28 @@ describe("Проверка автокомлита и подсказок реда
"Остаток":{
"name":"Остаток"
}
},
"methods":{
"ВставитьВСтруктуру": {
"name": "ВставитьВСтруктуру",
"name_en": "InsertToStructure",
"description": "Устанавливает значение элемента структуры по ключу. Если элемент с переданным значением ключа существует, то его значение заменяется, в противном случае добавляется новый элемент.",
"signature": {
"default": {
"СтрокаПараметров": "(Ключ: Строка, Значение?: Произвольный)",
"Параметры": {
"Ключ": "Ключ устанавливаемого элемента. Ключ должен соответствовать правилам, установленным для идентификаторов: - Первым символом ключа должна быть буква или символ подчеркивания (_). - Каждый из последующих символов может быть буквой, цифрой или символом подчеркивания (_).",
"Значение": "Значение устанавливаемого элемента."
}
}
}
},
"КоличествоЗаписейВВыгрузке": {
"name": "КоличествоЗаписейВВыгрузке",
"name_en": "CountItemsToUpload",
"description": "Получает количество элементов структуры.",
"returns": "Тип: Число. "
}
}
},
"_ОстаткиТовара":{
@ -398,6 +421,22 @@ describe("Проверка автокомлита и подсказок реда
assert.equal(suggestions.some(suggest => suggest.label === "_ОстаткиТовара"), true);
});
it("проверка подсказки методов, когда у пользовательского объекта явна задана ссылка", function () {
bsl = helper('_СтруктураВыгрузки.');
let suggestions = [];
bsl.getCustomObjectsCompletition(suggestions, bslMetadata.customObjects, monaco.languages.CompletionItemKind.Enum);
expect(suggestions).to.be.an('array').that.not.is.empty;
assert.equal(suggestions.some(suggest => suggest.label === "Вставить"), true);
});
it("проверка подсказки собственных методов для пользовательского объекта", function () {
bsl = helper('_СтруктураВыгрузки.');
let suggestions = [];
bsl.getCustomObjectsCompletition(suggestions, bslMetadata.customObjects, monaco.languages.CompletionItemKind.Enum);
expect(suggestions).to.be.an('array').that.not.is.empty;
assert.equal(suggestions.some(suggest => suggest.label === "КоличествоЗаписейВВыгрузке"), true);
});
it("проверка подсказки ссылочных реквизитов", function () {
bsl = helper('_ОстаткиТовара.Номенклатура.');
let suggestions = [];
@ -502,6 +541,41 @@ describe("Проверка автокомлита и подсказок реда
switchQueryMode();
});
it("проверка подсказки параметров для функции запроса", function () {
switchQueryMode();
bsl = helper('РАЗНОСТЬДАТ(');
let help = bsl.getCommonSigHelp(bslQuery.functions);
expect(help).to.have.property('activeParameter');
switchQueryMode();
});
it("проверка подсказки для функции запроса ЗНАЧЕНИЕ", function () {
switchQueryMode();
bsl = helper('ЗНАЧЕНИЕ(Справочник.Товары.');
let suggestions = bsl.getQueryCompletition(languages.query.languageDef);
expect(suggestions).to.be.an('object');
expect(suggestions.suggestions).to.be.an('array').that.not.is.empty;
assert.equal(suggestions.suggestions.some(suggest => suggest.label === "Услуга") && suggestions.suggestions.some(suggest => suggest.label === "ПустаяСсылка"), true);
bsl = helper('ЗНАЧЕНИЕ(Перечисление.ТестовыйЭлемент.');
suggestions = bsl.getQueryCompletition(languages.query.languageDef);
expect(suggestions).to.be.an('object');
expect(suggestions.suggestions).to.be.an('array').that.not.is.empty;
assert.equal(suggestions.suggestions.some(suggest => suggest.label === "Реквизит1"), true);
switchQueryMode();
});
it("проверка подсказки объекта, полученного методом ПолучитьОбъект()", function () {
bsl = helper('СправочникСсылка = Справочник.Товары.НайтиПоКоду(1);\nСправочникОбъект = СправочникСсылка.ПолучитьОбъект();\nСправочникОбъект.');
let suggestions = [];
contextData = new Map([
[2, new Map([["получитьобъект", { "ref": "catalogs.Товары.obj", "sig": null }]])],
]);
bsl.getRefCompletition(suggestions);
expect(suggestions).to.be.an('array').that.not.is.empty;
assert.equal(suggestions.some(suggest => suggest.label === "Заблокирован"), true);
contextData = new Map();
});
}
mocha.run();