Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

langium

Package Overview
Dependencies
Maintainers
4
Versions
49
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

langium - npm Package Compare versions

Comparing version 2.1.1 to 2.1.2

2

lib/generator/index.d.ts

@@ -10,3 +10,3 @@ /******************************************************************************

export * from './template-node.js';
export { expandToString, expandToStringWithNL, normalizeEOL } from './template-string.js';
export { expandToString, expandToStringLF, expandToStringLFWithNL, expandToStringWithNL, normalizeEOL } from './template-string.js';
//# sourceMappingURL=index.d.ts.map

@@ -9,3 +9,3 @@ /******************************************************************************

export * from './template-node.js';
export { expandToString, expandToStringWithNL, normalizeEOL } from './template-string.js';
export { expandToString, expandToStringLF, expandToStringLFWithNL, expandToStringWithNL, normalizeEOL } from './template-string.js';
//# sourceMappingURL=index.js.map

@@ -7,4 +7,6 @@ /******************************************************************************

export declare function expandToStringWithNL(staticParts: TemplateStringsArray, ...substitutions: unknown[]): string;
export declare function expandToStringLFWithNL(staticParts: TemplateStringsArray, ...substitutions: unknown[]): string;
/**
* A tag function that automatically aligns embedded multiline strings.
* Multiple lines are joined with the platform-specific line separator.
*

@@ -16,2 +18,11 @@ * @param staticParts the static parts of a tagged template literal

export declare function expandToString(staticParts: TemplateStringsArray, ...substitutions: unknown[]): string;
/**
* A tag function that automatically aligns embedded multiline strings.
* Multiple lines are joined with the LINE_FEED (`\n`) line separator.
*
* @param staticParts the static parts of a tagged template literal
* @param substitutions the variable parts of a tagged template literal
* @returns an aligned string that consists of the given parts
*/
export declare function expandToStringLF(staticParts: TemplateStringsArray, ...substitutions: unknown[]): string;
export declare const SNLE: string;

@@ -18,0 +29,0 @@ export declare const NEWLINE_REGEXP: RegExp;

@@ -10,4 +10,8 @@ /******************************************************************************

}
export function expandToStringLFWithNL(staticParts, ...substitutions) {
return expandToStringLF(staticParts, ...substitutions) + '\n';
}
/**
* A tag function that automatically aligns embedded multiline strings.
* Multiple lines are joined with the platform-specific line separator.
*

@@ -19,2 +23,16 @@ * @param staticParts the static parts of a tagged template literal

export function expandToString(staticParts, ...substitutions) {
return internalExpandToString(EOL, staticParts, ...substitutions);
}
/**
* A tag function that automatically aligns embedded multiline strings.
* Multiple lines are joined with the LINE_FEED (`\n`) line separator.
*
* @param staticParts the static parts of a tagged template literal
* @param substitutions the variable parts of a tagged template literal
* @returns an aligned string that consists of the given parts
*/
export function expandToStringLF(staticParts, ...substitutions) {
return internalExpandToString('\n', staticParts, ...substitutions);
}
function internalExpandToString(lineSep, staticParts, ...substitutions) {
let lines = substitutions

@@ -49,5 +67,5 @@ // align substitutions and fuse them with static parts

// shifts lines to the left
.map(line => line.slice(indent).trimRight())
.map(line => line.slice(indent).trimEnd())
// convert lines to string
.join(EOL);
.join(lineSep);
}

@@ -54,0 +72,0 @@ export const SNLE = Object.freeze('__«SKIP^NEW^LINE^IF^EMPTY»__');

@@ -119,2 +119,3 @@ /******************************************************************************

protected buildContexts(document: LangiumDocument, position: Position): IterableIterator<CompletionContext>;
protected performNextTokenCompletion(document: LangiumDocument, text: string, _offset: number, _end: number): boolean;
protected findDataTypeRuleStart(cst: CstNode, offset: number): [number, number] | undefined;

@@ -121,0 +122,0 @@ /**

@@ -10,3 +10,3 @@ /******************************************************************************

import { assignMandatoryAstProperties, getContainerOfType } from '../../utils/ast-util.js';
import { findDeclarationNodeAtOffset, findLeafNodeAtOffset } from '../../utils/cst-util.js';
import { findDeclarationNodeAtOffset, findLeafNodeBeforeOffset } from '../../utils/cst-util.js';
import { getEntryRule } from '../../utils/grammar-util.js';

@@ -105,3 +105,3 @@ import { stream } from '../../utils/stream.js';

*buildContexts(document, position) {
var _a, _b, _c, _d, _e;
var _a, _b;
const cst = document.parseResult.value.$cstNode;

@@ -125,3 +125,3 @@ if (!cst) {

const [ruleStart, ruleEnd] = dataTypeRuleOffsets;
const parentNode = (_a = findLeafNodeAtOffset(cst, ruleStart)) === null || _a === void 0 ? void 0 : _a.astNode;
const parentNode = (_a = findLeafNodeBeforeOffset(cst, ruleStart)) === null || _a === void 0 ? void 0 : _a.astNode;
yield Object.assign(Object.assign({}, partialContext), { node: parentNode, tokenOffset: ruleStart, tokenEndOffset: ruleEnd, features: this.findFeaturesAt(textDocument, ruleStart) });

@@ -131,12 +131,21 @@ }

const { nextTokenStart, nextTokenEnd, previousTokenStart, previousTokenEnd } = this.backtrackToAnyToken(text, offset);
let astNode;
let astNodeOffset = nextTokenStart;
if (offset <= nextTokenStart && previousTokenStart !== undefined) {
// This check indicates that the cursor is still before the next token, so we should use the previous AST node (if it exists)
astNodeOffset = previousTokenStart;
}
const astNode = (_b = findLeafNodeBeforeOffset(cst, astNodeOffset)) === null || _b === void 0 ? void 0 : _b.astNode;
let performNextCompletion = true;
if (previousTokenStart !== undefined && previousTokenEnd !== undefined && previousTokenEnd === offset) {
astNode = (_b = findLeafNodeAtOffset(cst, previousTokenStart)) === null || _b === void 0 ? void 0 : _b.astNode;
// This context aims to complete the current feature
yield Object.assign(Object.assign({}, partialContext), { node: astNode, tokenOffset: previousTokenStart, tokenEndOffset: previousTokenEnd, features: this.findFeaturesAt(textDocument, previousTokenStart) });
// This context aims to complete the immediate next feature (if one exists at the current cursor position)
// It uses the previous AST node for that.
yield Object.assign(Object.assign({}, partialContext), { node: astNode, tokenOffset: previousTokenEnd, tokenEndOffset: previousTokenEnd, features: this.findFeaturesAt(textDocument, previousTokenEnd) });
// The completion after the current token should be prevented in case we find out that the current token definitely isn't completed yet
// This is usually the case when the current token ends on a letter.
performNextCompletion = this.performNextTokenCompletion(document, text.substring(previousTokenStart, previousTokenEnd), previousTokenStart, previousTokenEnd);
if (performNextCompletion) {
// This context aims to complete the immediate next feature (if one exists at the current cursor position)
// It uses the previous cst start/offset for that.
yield Object.assign(Object.assign({}, partialContext), { node: astNode, tokenOffset: previousTokenEnd, tokenEndOffset: previousTokenEnd, features: this.findFeaturesAt(textDocument, previousTokenEnd) });
}
}
astNode = (_d = (_c = findLeafNodeAtOffset(cst, nextTokenStart)) === null || _c === void 0 ? void 0 : _c.astNode) !== null && _d !== void 0 ? _d : (previousTokenStart === undefined ? undefined : (_e = findLeafNodeAtOffset(cst, previousTokenStart)) === null || _e === void 0 ? void 0 : _e.astNode);
if (!astNode) {

@@ -150,7 +159,14 @@ const parserRule = getEntryRule(this.grammar);

}
else {
// This context aims to complete the next feature, using the next ast node
else if (performNextCompletion) {
// This context aims to complete the next feature, using the next cst start/end
yield Object.assign(Object.assign({}, partialContext), { node: astNode, tokenOffset: nextTokenStart, tokenEndOffset: nextTokenEnd, features: this.findFeaturesAt(textDocument, nextTokenStart) });
}
}
performNextTokenCompletion(document, text, _offset, _end) {
// This regex returns false if the text ends with a letter.
// We don't want to complete new text immediately after a keyword, ID etc.
// We only care about the last character in the text, so we use $ here.
// The \P{L} used here is a Unicode category that matches any character that is not a letter
return /\P{L}$/u.test(text);
}
findDataTypeRuleStart(cst, offset) {

@@ -309,3 +325,3 @@ var _a, _b;

// Filter out keywords that do not contain any word character
return keyword.value.match(/[\w]/) !== null;
return /\p{L}/u.test(keyword.value);
}

@@ -312,0 +328,0 @@ fillCompletionItem(context, item) {

@@ -6,6 +6,6 @@ /******************************************************************************

******************************************************************************/
import { Lexer, EOF } from 'chevrotain';
import { isKeyword, isParserRule, isTerminalRule, isEndOfFile } from '../grammar/generated/ast.js';
import { Lexer } from 'chevrotain';
import { isKeyword, isParserRule, isTerminalRule } from '../grammar/generated/ast.js';
import { terminalRegex } from '../grammar/internal-grammar-util.js';
import { streamAllContents, streamAst } from '../utils/ast-util.js';
import { streamAllContents } from '../utils/ast-util.js';
import { getAllReachableRules } from '../utils/grammar-util.js';

@@ -28,6 +28,4 @@ import { getCaseInsensitivePattern, isWhitespaceRegExp, partialMatches } from '../utils/regex-util.js';

});
//reminder: EOF should always be the last token, because it is very unlikely that it will be matched within the input
if (reachableRules.some(r => streamAst(r.definition).some(isEndOfFile))) {
tokens.push(EOF);
}
// We don't need to add the EOF token explicitly.
// It is automatically available at the end of the token stream.
return tokens;

@@ -34,0 +32,0 @@ }

@@ -46,3 +46,24 @@ /******************************************************************************

export declare function isCommentNode(cstNode: CstNode, commentNames: string[]): boolean;
/**
* Finds the leaf CST node at the specified 0-based string offset.
* Note that the given offset will be within the range of the returned leaf node.
*
* If the offset does not point to a CST node (but just white space), this method will return `undefined`.
*
* @param node The CST node to search through.
* @param offset The specified offset.
* @returns The CST node at the specified offset.
*/
export declare function findLeafNodeAtOffset(node: CstNode, offset: number): LeafCstNode | undefined;
/**
* Finds the leaf CST node at the specified 0-based string offset.
* If no CST node exists at the specified position, it will return the leaf node before it.
*
* If there is no leaf node before the specified offset, this method will return `undefined`.
*
* @param node The CST node to search through.
* @param offset The specified offset.
* @returns The CST node closest to the specified offset.
*/
export declare function findLeafNodeBeforeOffset(node: CstNode, offset: number): LeafCstNode | undefined;
export declare function getPreviousNode(node: CstNode, hidden?: boolean): CstNode | undefined;

@@ -49,0 +70,0 @@ export declare function getNextNode(node: CstNode, hidden?: boolean): CstNode | undefined;

@@ -142,2 +142,12 @@ /******************************************************************************

}
/**
* Finds the leaf CST node at the specified 0-based string offset.
* Note that the given offset will be within the range of the returned leaf node.
*
* If the offset does not point to a CST node (but just white space), this method will return `undefined`.
*
* @param node The CST node to search through.
* @param offset The specified offset.
* @returns The CST node at the specified offset.
*/
export function findLeafNodeAtOffset(node, offset) {

@@ -148,19 +158,27 @@ if (isLeafCstNode(node)) {

else if (isCompositeCstNode(node)) {
let firstChild = 0;
let lastChild = node.content.length - 1;
while (firstChild < lastChild) {
const middleChild = Math.floor((firstChild + lastChild) / 2);
const n = node.content[middleChild];
if (n.offset > offset) {
lastChild = middleChild - 1;
}
else if (n.end <= offset) {
firstChild = middleChild + 1;
}
else {
return findLeafNodeAtOffset(n, offset);
}
const searchResult = binarySearch(node, offset, false);
if (searchResult) {
return findLeafNodeAtOffset(searchResult, offset);
}
if (firstChild === lastChild) {
return findLeafNodeAtOffset(node.content[firstChild], offset);
}
return undefined;
}
/**
* Finds the leaf CST node at the specified 0-based string offset.
* If no CST node exists at the specified position, it will return the leaf node before it.
*
* If there is no leaf node before the specified offset, this method will return `undefined`.
*
* @param node The CST node to search through.
* @param offset The specified offset.
* @returns The CST node closest to the specified offset.
*/
export function findLeafNodeBeforeOffset(node, offset) {
if (isLeafCstNode(node)) {
return node;
}
else if (isCompositeCstNode(node)) {
const searchResult = binarySearch(node, offset, true);
if (searchResult) {
return findLeafNodeBeforeOffset(searchResult, offset);
}

@@ -170,2 +188,25 @@ }

}
function binarySearch(node, offset, closest) {
let left = 0;
let right = node.content.length - 1;
let closestNode = undefined;
while (left <= right) {
const middle = Math.floor((left + right) / 2);
const middleNode = node.content[middle];
if (middleNode.offset <= offset && middleNode.end > offset) {
// Found an exact match
return middleNode;
}
if (middleNode.end <= offset) {
// Update the closest node (less than offset) and move to the right half
closestNode = closest ? middleNode : undefined;
left = middle + 1;
}
else {
// Move to the left half
right = middle - 1;
}
}
return closestNode;
}
export function getPreviousNode(node, hidden = true) {

@@ -172,0 +213,0 @@ while (node.container) {

{
"name": "langium",
"version": "2.1.1",
"version": "2.1.2",
"description": "A language engineering tool for the Language Server Protocol",

@@ -55,2 +55,3 @@ "homepage": "https://langium.org",

"lint": "eslint src test --ext .ts",
"validate-exports": "tsc -p test/tsconfig.export-main.json",
"langium:generate": "langium generate",

@@ -57,0 +58,0 @@ "langium:generate:production": "langium generate --mode=production",

@@ -11,2 +11,3 @@ /******************************************************************************

export * from './template-node.js';
export { expandToString, expandToStringWithNL, normalizeEOL } from './template-string.js';
export { expandToString, expandToStringLF, expandToStringLFWithNL, expandToStringWithNL, normalizeEOL } from './template-string.js';

@@ -13,4 +13,9 @@ /******************************************************************************

export function expandToStringLFWithNL(staticParts: TemplateStringsArray, ...substitutions: unknown[]): string {
return expandToStringLF(staticParts, ...substitutions) + '\n';
}
/**
* A tag function that automatically aligns embedded multiline strings.
* Multiple lines are joined with the platform-specific line separator.
*

@@ -22,2 +27,18 @@ * @param staticParts the static parts of a tagged template literal

export function expandToString(staticParts: TemplateStringsArray, ...substitutions: unknown[]): string {
return internalExpandToString(EOL, staticParts, ...substitutions);
}
/**
* A tag function that automatically aligns embedded multiline strings.
* Multiple lines are joined with the LINE_FEED (`\n`) line separator.
*
* @param staticParts the static parts of a tagged template literal
* @param substitutions the variable parts of a tagged template literal
* @returns an aligned string that consists of the given parts
*/
export function expandToStringLF(staticParts: TemplateStringsArray, ...substitutions: unknown[]): string {
return internalExpandToString('\n', staticParts, ...substitutions);
}
function internalExpandToString(lineSep: string, staticParts: TemplateStringsArray, ...substitutions: unknown[]): string {
let lines = substitutions

@@ -56,5 +77,5 @@ // align substitutions and fuse them with static parts

// shifts lines to the left
.map(line => line.slice(indent).trimRight())
.map(line => line.slice(indent).trimEnd())
// convert lines to string
.join(EOL);
.join(lineSep);
}

@@ -82,2 +103,2 @@

return input.replace(NEWLINE_REGEXP, EOL);
}
}

@@ -26,3 +26,3 @@ /******************************************************************************

import { assignMandatoryAstProperties, getContainerOfType } from '../../utils/ast-util.js';
import { findDeclarationNodeAtOffset, findLeafNodeAtOffset } from '../../utils/cst-util.js';
import { findDeclarationNodeAtOffset, findLeafNodeBeforeOffset } from '../../utils/cst-util.js';
import { getEntryRule } from '../../utils/grammar-util.js';

@@ -241,3 +241,3 @@ import { stream } from '../../utils/stream.js';

const [ruleStart, ruleEnd] = dataTypeRuleOffsets;
const parentNode = findLeafNodeAtOffset(cst, ruleStart)?.astNode;
const parentNode = findLeafNodeBeforeOffset(cst, ruleStart)?.astNode;
yield {

@@ -253,5 +253,10 @@ ...partialContext,

const { nextTokenStart, nextTokenEnd, previousTokenStart, previousTokenEnd } = this.backtrackToAnyToken(text, offset);
let astNode: AstNode | undefined;
let astNodeOffset = nextTokenStart;
if (offset <= nextTokenStart && previousTokenStart !== undefined) {
// This check indicates that the cursor is still before the next token, so we should use the previous AST node (if it exists)
astNodeOffset = previousTokenStart;
}
const astNode = findLeafNodeBeforeOffset(cst, astNodeOffset)?.astNode;
let performNextCompletion = true;
if (previousTokenStart !== undefined && previousTokenEnd !== undefined && previousTokenEnd === offset) {
astNode = findLeafNodeAtOffset(cst, previousTokenStart)?.astNode;
// This context aims to complete the current feature

@@ -265,14 +270,22 @@ yield {

};
// This context aims to complete the immediate next feature (if one exists at the current cursor position)
// It uses the previous AST node for that.
yield {
...partialContext,
node: astNode,
tokenOffset: previousTokenEnd,
tokenEndOffset: previousTokenEnd,
features: this.findFeaturesAt(textDocument, previousTokenEnd),
};
// The completion after the current token should be prevented in case we find out that the current token definitely isn't completed yet
// This is usually the case when the current token ends on a letter.
performNextCompletion = this.performNextTokenCompletion(
document,
text.substring(previousTokenStart, previousTokenEnd),
previousTokenStart,
previousTokenEnd
);
if (performNextCompletion) {
// This context aims to complete the immediate next feature (if one exists at the current cursor position)
// It uses the previous cst start/offset for that.
yield {
...partialContext,
node: astNode,
tokenOffset: previousTokenEnd,
tokenEndOffset: previousTokenEnd,
features: this.findFeaturesAt(textDocument, previousTokenEnd),
};
}
}
astNode = findLeafNodeAtOffset(cst, nextTokenStart)?.astNode
?? (previousTokenStart === undefined ? undefined : findLeafNodeAtOffset(cst, previousTokenStart)?.astNode);

@@ -291,4 +304,4 @@ if (!astNode) {

};
} else {
// This context aims to complete the next feature, using the next ast node
} else if (performNextCompletion) {
// This context aims to complete the next feature, using the next cst start/end
yield {

@@ -304,2 +317,10 @@ ...partialContext,

protected performNextTokenCompletion(document: LangiumDocument, text: string, _offset: number, _end: number): boolean {
// This regex returns false if the text ends with a letter.
// We don't want to complete new text immediately after a keyword, ID etc.
// We only care about the last character in the text, so we use $ here.
// The \P{L} used here is a Unicode category that matches any character that is not a letter
return /\P{L}$/u.test(text);
}
protected findDataTypeRuleStart(cst: CstNode, offset: number): [number, number] | undefined {

@@ -463,3 +484,3 @@ let containerNode: CstNode | undefined = findDeclarationNodeAtOffset(cst, offset, this.grammarConfig.nameRegexp);

// Filter out keywords that do not contain any word character
return keyword.value.match(/[\w]/) !== null;
return /\p{L}/u.test(keyword.value);
}

@@ -466,0 +487,0 @@

@@ -10,6 +10,6 @@ /******************************************************************************

import type { Stream } from '../utils/stream.js';
import { Lexer, EOF } from 'chevrotain';
import { isKeyword, isParserRule, isTerminalRule, isEndOfFile } from '../grammar/generated/ast.js';
import { Lexer } from 'chevrotain';
import { isKeyword, isParserRule, isTerminalRule } from '../grammar/generated/ast.js';
import { terminalRegex } from '../grammar/internal-grammar-util.js';
import { streamAllContents, streamAst } from '../utils/ast-util.js';
import { streamAllContents } from '../utils/ast-util.js';
import { getAllReachableRules } from '../utils/grammar-util.js';

@@ -42,7 +42,4 @@ import { getCaseInsensitivePattern, isWhitespaceRegExp, partialMatches } from '../utils/regex-util.js';

});
//reminder: EOF should always be the last token, because it is very unlikely that it will be matched within the input
if (reachableRules.some(r => streamAst(r.definition).some(isEndOfFile))) {
tokens.push(EOF);
}
// We don't need to add the EOF token explicitly.
// It is automatically available at the end of the token stream.
return tokens;

@@ -49,0 +46,0 @@ }

@@ -158,2 +158,12 @@ /******************************************************************************

/**
* Finds the leaf CST node at the specified 0-based string offset.
* Note that the given offset will be within the range of the returned leaf node.
*
* If the offset does not point to a CST node (but just white space), this method will return `undefined`.
*
* @param node The CST node to search through.
* @param offset The specified offset.
* @returns The CST node at the specified offset.
*/
export function findLeafNodeAtOffset(node: CstNode, offset: number): LeafCstNode | undefined {

@@ -163,17 +173,27 @@ if (isLeafCstNode(node)) {

} else if (isCompositeCstNode(node)) {
let firstChild = 0;
let lastChild = node.content.length - 1;
while (firstChild < lastChild) {
const middleChild = Math.floor((firstChild + lastChild) / 2);
const n = node.content[middleChild];
if (n.offset > offset) {
lastChild = middleChild - 1;
} else if (n.end <= offset) {
firstChild = middleChild + 1;
} else {
return findLeafNodeAtOffset(n, offset);
}
const searchResult = binarySearch(node, offset, false);
if (searchResult) {
return findLeafNodeAtOffset(searchResult, offset);
}
if (firstChild === lastChild) {
return findLeafNodeAtOffset(node.content[firstChild], offset);
}
return undefined;
}
/**
* Finds the leaf CST node at the specified 0-based string offset.
* If no CST node exists at the specified position, it will return the leaf node before it.
*
* If there is no leaf node before the specified offset, this method will return `undefined`.
*
* @param node The CST node to search through.
* @param offset The specified offset.
* @returns The CST node closest to the specified offset.
*/
export function findLeafNodeBeforeOffset(node: CstNode, offset: number): LeafCstNode | undefined {
if (isLeafCstNode(node)) {
return node;
} else if (isCompositeCstNode(node)) {
const searchResult = binarySearch(node, offset, true);
if (searchResult) {
return findLeafNodeBeforeOffset(searchResult, offset);
}

@@ -184,2 +204,29 @@ }

function binarySearch(node: CompositeCstNode, offset: number, closest: boolean): CstNode | undefined {
let left = 0;
let right = node.content.length - 1;
let closestNode: CstNode | undefined = undefined;
while (left <= right) {
const middle = Math.floor((left + right) / 2);
const middleNode = node.content[middle];
if (middleNode.offset <= offset && middleNode.end > offset) {
// Found an exact match
return middleNode;
}
if (middleNode.end <= offset) {
// Update the closest node (less than offset) and move to the right half
closestNode = closest ? middleNode : undefined;
left = middle + 1;
} else {
// Move to the left half
right = middle - 1;
}
}
return closestNode;
}
export function getPreviousNode(node: CstNode, hidden = true): CstNode | undefined {

@@ -186,0 +233,0 @@ while (node.container) {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc