Skip to content

Commit b32992f

Browse files
Add identifierExpressionUtils (#395)
* initial commit * small additional test
1 parent 8ca8947 commit b32992f

File tree

7 files changed

+128
-4
lines changed

7 files changed

+128
-4
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@microsoft/powerquery-parser",
3-
"version": "0.18.0",
3+
"version": "0.18.1",
44
"description": "A parser for the Power Query/M formula language.",
55
"author": "Microsoft",
66
"license": "MIT",
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
import { CommonIdentifierUtilsOptions, getNormalizedIdentifier } from "./identifierUtils";
5+
import { Assert } from "../common";
6+
7+
export function assertNormalizedIdentifierExpression(text: string, options?: CommonIdentifierUtilsOptions): string {
8+
return Assert.asDefined(
9+
getNormalizedIdentifierExpression(text, options),
10+
`Expected a valid identifier expression but received '${text}'`,
11+
);
12+
}
13+
14+
// Removes the '@' and quotes from a quoted identifier if possible.
15+
// When given an invalid identifier, returns undefined.
16+
export function getNormalizedIdentifierExpression(
17+
text: string,
18+
options?: CommonIdentifierUtilsOptions,
19+
): string | undefined {
20+
if (text.startsWith("@")) {
21+
text = text.substring(1);
22+
}
23+
24+
return getNormalizedIdentifier(text, options);
25+
}

src/powerquery-parser/language/identifierUtils.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT license.
33

44
import { Assert, Pattern, StringUtils } from "../common";
5+
import { KeywordKind } from "./keyword/keyword";
56

67
export enum IdentifierKind {
78
Generalized = "Generalized",
@@ -21,6 +22,14 @@ export interface GetAllowedIdentifiersOptions extends CommonIdentifierUtilsOptio
2122
readonly allowRecursive?: boolean;
2223
}
2324

25+
// Wraps an assert around the getNormalizedIdentifier method
26+
export function assertNormalizedIdentifier(text: string, options?: CommonIdentifierUtilsOptions): string {
27+
return Assert.asDefined(
28+
getNormalizedIdentifier(text, options),
29+
`Expected a valid identifier but received '${text}'`,
30+
);
31+
}
32+
2433
// Identifiers have multiple forms that can be used interchangeably.
2534
// For example, if you have `[key = 1]`, you can use `key` or `#""key""`.
2635
// The `getAllowedIdentifiers` function returns all the forms of the identifier that are allowed in the current context.
@@ -180,6 +189,10 @@ export function getIdentifierLength(
180189
// Removes the quotes from a quoted identifier if possible.
181190
// When given an invalid identifier, returns undefined.
182191
export function getNormalizedIdentifier(text: string, options?: CommonIdentifierUtilsOptions): string | undefined {
192+
if (AllowedHashKeywords.has(text)) {
193+
return text;
194+
}
195+
183196
const allowGeneralizedIdentifier: boolean =
184197
options?.allowGeneralizedIdentifier ?? DefaultAllowGeneralizedIdentifier;
185198

@@ -367,3 +380,17 @@ function stripQuotes(text: string): string {
367380

368381
const DefaultAllowTrailingPeriod: boolean = false;
369382
const DefaultAllowGeneralizedIdentifier: boolean = false;
383+
384+
const AllowedHashKeywords: ReadonlySet<string> = new Set([
385+
KeywordKind.HashBinary,
386+
KeywordKind.HashDate,
387+
KeywordKind.HashDateTime,
388+
KeywordKind.HashDateTimeZone,
389+
KeywordKind.HashDuration,
390+
KeywordKind.HashInfinity,
391+
KeywordKind.HashNan,
392+
KeywordKind.HashSections,
393+
KeywordKind.HashShared,
394+
KeywordKind.HashTable,
395+
KeywordKind.HashTime,
396+
]);

src/powerquery-parser/language/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT license.
33

4-
import * as Comment from "./comment";
4+
export * as IdentifierExpressionUtils from "./identifierExpressionUtils";
55
export * as IdentifierUtils from "./identifierUtils";
66
export * as TextUtils from "./textUtils";
7+
import * as Comment from "./comment";
78
import * as Token from "./token";
89

910
export { Comment, Token };
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
import "mocha";
5+
import { expect } from "chai";
6+
7+
import { IdentifierExpressionUtils, IdentifierUtils } from "../../powerquery-parser/language";
8+
9+
describe("IdentifierUtils", () => {
10+
function createCommonIdentifierUtilsOptions(
11+
overrides?: Partial<IdentifierUtils.CommonIdentifierUtilsOptions>,
12+
): IdentifierUtils.CommonIdentifierUtilsOptions {
13+
return {
14+
allowTrailingPeriod: false,
15+
allowGeneralizedIdentifier: false,
16+
...overrides,
17+
};
18+
}
19+
20+
describe(`getNormalizedIdentifierExpression`, () => {
21+
function runGetNormalizedIdentifierExpressionTest(params: {
22+
readonly text: string;
23+
readonly expectedSuccess: string | undefined;
24+
readonly options?: Partial<IdentifierUtils.CommonIdentifierUtilsOptions>;
25+
}): void {
26+
const text: string = params.text;
27+
28+
const identifierUtilsOptions: IdentifierUtils.CommonIdentifierUtilsOptions =
29+
createCommonIdentifierUtilsOptions(params.options);
30+
31+
const actual: string | undefined = IdentifierExpressionUtils.getNormalizedIdentifierExpression(
32+
text,
33+
identifierUtilsOptions,
34+
);
35+
36+
if (params.expectedSuccess !== undefined) {
37+
expect(actual).to.equal(params.expectedSuccess);
38+
} else {
39+
expect(actual).to.be.undefined;
40+
}
41+
}
42+
43+
it("foo", () => {
44+
runGetNormalizedIdentifierExpressionTest({
45+
text: "foo",
46+
expectedSuccess: "foo",
47+
});
48+
});
49+
50+
it("@foo", () => {
51+
runGetNormalizedIdentifierExpressionTest({
52+
text: "@foo",
53+
expectedSuccess: "foo",
54+
});
55+
});
56+
57+
it("#table", () => {
58+
runGetNormalizedIdentifierExpressionTest({
59+
text: "#table",
60+
expectedSuccess: "#table",
61+
});
62+
});
63+
});
64+
});

src/test/libraryTest/identifierUtils.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,5 +368,12 @@ describe("IdentifierUtils", () => {
368368
expectedSuccess: "quoted generalized identifier",
369369
});
370370
});
371+
372+
it("#table", () => {
373+
runGetNormalizedIdentifierTest({
374+
text: "#table",
375+
expectedSuccess: "#table",
376+
});
377+
});
371378
});
372379
});

0 commit comments

Comments
 (0)