Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion l10n/bundle.l10n.de.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,6 @@
"Unused anchor \"{0}\"": "Nicht verwendeter Anker \"{0}\"",
"Unresolved alias \"{0}\"": "Nicht aufgelöstes Alias \"{0}\"",
"Convert string to folded block string": "Konvertieren Sie die Zeichenfolge in eine gefaltete Blockzeichenfolge",
"Convert string to literal block string": "Konvertieren Sie die Zeichenfolge in eine wörtliche Blockzeichenfolge"
"Convert string to literal block string": "Konvertieren Sie die Zeichenfolge in eine wörtliche Blockzeichenfolge",
"Invalid pattern: \"{0}\"": "Ungültiges Pattern: \"{0}\""
}
3 changes: 2 additions & 1 deletion l10n/bundle.l10n.fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,6 @@
"Unused anchor \"{0}\"": "Ancre inutilisée '{0}'",
"Unresolved alias \"{0}\"": "Alias non résolu '{0}'",
"Convert string to folded block string": "Convertir la chaîne en style de bloc pliée",
"Convert string to literal block string": "Convertir la chaîne en style de bloc littérale"
"Convert string to literal block string": "Convertir la chaîne en style de bloc littérale",
"Invalid pattern: \"{0}\"": "Motif non valide : \"{0}\""
}
3 changes: 2 additions & 1 deletion l10n/bundle.l10n.ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,6 @@
"Unused anchor \"{0}\"": "未使用のアンカー \"{0}\"",
"Unresolved alias \"{0}\"": "未解決のエイリアス \"{0}\"",
"Convert string to folded block string": "文字列を折り畳みブロック文字列に変換する",
"Convert string to literal block string": "文字列をリテラルブロック文字列に変換する"
"Convert string to literal block string": "文字列をリテラルブロック文字列に変換する",
"Invalid pattern: \"{0}\"": "無効なパターンです:\"{0}\""
}
3 changes: 2 additions & 1 deletion l10n/bundle.l10n.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,6 @@
"Unused anchor \"{0}\"": "Unused anchor \"{0}\"",
"Unresolved alias \"{0}\"": "Unresolved alias \"{0}\"",
"Convert string to folded block string": "Convert string to folded block string",
"Convert string to literal block string": "Convert string to literal block string"
"Convert string to literal block string": "Convert string to literal block string",
"Invalid pattern: \"{0}\"": "Invalid pattern: \"{0}\""
}
3 changes: 2 additions & 1 deletion l10n/bundle.l10n.ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,6 @@
"Unused anchor \"{0}\"": "사용되지 않은 앵커 \"{0}\"",
"Unresolved alias \"{0}\"": "해결되지 않은 별칭 \"{0}\"",
"Convert string to folded block string": "문자열을 접힌 블록 문자열로 변환합니다.",
"Convert string to literal block string": "문자열을 리터럴 블록 문자열로 변환합니다."
"Convert string to literal block string": "문자열을 리터럴 블록 문자열로 변환합니다.",
"Invalid pattern: \"{0}\"": "유효하지 않은 패턴입니다: \"{0}\""
}
3 changes: 2 additions & 1 deletion l10n/bundle.l10n.zh-cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,6 @@
"Unused anchor \"{0}\"": "未使用的锚点 \"{0}\"",
"Unresolved alias \"{0}\"": "未解析的别名 \"{0}\"",
"Convert string to folded block string": "将字符串转换为折叠块字符串",
"Convert string to literal block string": "将字符串转换为文字块字符串"
"Convert string to literal block string": "将字符串转换为文字块字符串",
"Invalid pattern: \"{0}\"": "无效的模式:\"{0}\""
}
3 changes: 2 additions & 1 deletion l10n/bundle.l10n.zh-tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,6 @@
"Unused anchor \"{0}\"": "未使用的錨點 \"{0}\"",
"Unresolved alias \"{0}\"": "未解析的別名 \"{0}\"",
"Convert string to folded block string": "將字串轉換為折疊塊字串",
"Convert string to literal block string": "將字串轉換為文字區塊字串"
"Convert string to literal block string": "將字串轉換為文字區塊字串",
"Invalid pattern: \"{0}\"": "無效的模式:\"{0}\""
}
11 changes: 10 additions & 1 deletion src/languageservice/parser/schemaValidation/baseValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -824,7 +824,15 @@ export abstract class BaseValidator {

if (isString(schema.pattern)) {
const regex = safeCreateUnicodeRegExp(schema.pattern);
if (!regex.test(value)) {
if (!regex) {
validationResult.problems.push({
location: { offset: node.offset, length: node.length },
severity: DiagnosticSeverity.Warning,
message: l10n.t('Invalid pattern: "{0}"', schema.pattern),
source: this.getSchemaSource(schema, originalSchema),
schemaUri: this.getSchemaUri(schema, originalSchema),
});
} else if (!regex.test(value)) {
validationResult.problems.push({
location: { offset: node.offset, length: node.length },
severity: DiagnosticSeverity.Warning,
Expand Down Expand Up @@ -1299,6 +1307,7 @@ export abstract class BaseValidator {

for (const propertyPattern of Object.keys(patternProps)) {
const regex = safeCreateUnicodeRegExp(propertyPattern);
if (!regex) continue;

for (const propertyName of unprocessedProperties.slice(0)) {
if (!regex.test(propertyName)) continue;
Expand Down
20 changes: 17 additions & 3 deletions src/languageservice/utils/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,26 @@ export function getIndentation(lineContent: string, position: number): number {
return position;
}

export function safeCreateUnicodeRegExp(pattern: string): RegExp {
export function safeCreateUnicodeRegExp(pattern: string): RegExp | undefined {
let flags = '';
pattern = pattern.replace(/\(\?([ims]+)\)/g, (_match, modifiers: string) => {
for (const modifier of modifiers) {
if (!flags.includes(modifier)) {
flags += modifier;
}
}
return '';
});

// fall back to regular regexp if we cannot create Unicode one
try {
return new RegExp(pattern, 'u');
return new RegExp(pattern, flags + 'u');
} catch (ignore) {
return new RegExp(pattern);
try {
return new RegExp(pattern, flags);
} catch (e) {
return undefined;
}
}
}

Expand Down
54 changes: 54 additions & 0 deletions test/hover.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,60 @@ users:
);
});

it('Hover handles inline pattern modifiers', async () => {
schemaProvider.addSchema(SCHEMA_ID, {
type: 'object',
properties: {
description: {
type: 'string',
description: 'Field with dotall pattern.',
pattern: '(?s).*',
},
multilineAndDotall: {
type: 'string',
description: 'Field with multiline and dotall pattern.',
pattern: '(?ms)^start.*end$',
},
},
});

let result = await parseSetup('description: a|n|y text');
assert.strictEqual(MarkupContent.is(result.contents), true);
assert.strictEqual(
(result.contents as MarkupContent).value,
`Field with dotall pattern.\n\nSource: [${SCHEMA_ID}](file:///${SCHEMA_ID})`
);

result = await parseSetup('multilineAndDotall: start middle c|o|ntent end');
assert.strictEqual(MarkupContent.is(result.contents), true);
assert.strictEqual(
(result.contents as MarkupContent).value,
`Field with multiline and dotall pattern.\n\nSource: [${SCHEMA_ID}](file:///${SCHEMA_ID})`
);
expect(telemetry.messages).to.be.empty;
});

it('Hover handles unsupported pattern', async () => {
schemaProvider.addSchema(SCHEMA_ID, {
type: 'object',
properties: {
unsupportedPattern: {
type: 'string',
description: 'Field with unsupported pattern.',
pattern: '(?x)text .*',
},
},
});

const result = await parseSetup('unsupportedPattern: text c|o|ntent');
assert.strictEqual(MarkupContent.is(result.contents), true);
assert.strictEqual(
(result.contents as MarkupContent).value,
`Field with unsupported pattern.\n\nSource: [${SCHEMA_ID}](file:///${SCHEMA_ID})`
);
expect(telemetry.messages).to.be.empty;
});

it('hover on value and its description has multiline, indentation and special string', async () => {
(() => {
languageSettingsSetup = new ServiceSetup()
Expand Down
97 changes: 97 additions & 0 deletions test/schemaValidation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,103 @@ describe('Validation Tests', () => {
})
.then(done, done);
});
it('Test inline pattern modifiers', (done) => {
schemaProvider.addSchema(SCHEMA_ID, {
type: 'object',
properties: {
caseInsensitiveField: {
type: 'string',
pattern: '(?i)^(yes|no)$',
},
multilineOnly: {
type: 'string',
pattern: '(?m)^start.*end$',
},
dotallOnly: {
type: 'string',
pattern: '(?s)^start.*end$',
},
multilineAndDotallCombinedFlags: {
type: 'string',
pattern: '(?ms)^start.*end$',
},
dotallAndCaseInsensitiveFieldFlags: {
type: 'string',
pattern: '(?s)(?i)test.*content',
},
allFlags: {
type: 'string',
pattern: '(?ims)^START.*END$',
},
},
});
const content = [
'caseInsensitiveField: YES',
'',
'multilineOnly: |-',
' other text',
' start middle content end',
' more text',
'',
'dotallOnly: |-',
' start',
' middle content',
' end',
'',
'multilineAndDotallCombinedFlags: |-',
' other text',
' start',
' middle content',
' end',
' more text',
'',
'dotallAndCaseInsensitiveFieldFlags: |-',
' TEST',
' middle content',
' CONTENT',
'',
'allFlags: |-',
' other text',
' start',
' middle content',
' end',
' more text',
].join('\n');
parseSetup(content)
.then(function (result) {
assert.equal(result.length, 0);
})
.then(done, done);
});
it('Test an unsupported pattern', (done) => {
schemaProvider.addSchema(SCHEMA_ID, {
type: 'object',
properties: {
unsupportedPattern: {
type: 'string',
pattern: '(?x)text .*',
},
},
});
parseSetup('unsupportedPattern: text content')
.then(function (result) {
assert.equal(result.length, 1);
assert.deepEqual(
result[0],
createDiagnosticWithData(
'Invalid pattern: "(?x)text .*"',
0,
20,
0,
32,
DiagnosticSeverity.Error,
`yaml-schema: file:///${SCHEMA_ID}`,
`file:///${SCHEMA_ID}`
)
);
})
.then(done, done);
});
});

describe('Number tests', () => {
Expand Down
Loading