Skip to content
Open
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
25 changes: 24 additions & 1 deletion core/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,33 @@ type actionsWithDependencies =
export const nativeRequire =
typeof __webpack_require__ === "function" ? __non_webpack_require__ : require;

// Turn a selector pattern containing '*' wildcards into an anchored RegExp.
// Every character except '*' is matched literally (regex metacharacters are
// escaped); each '*' matches any run of characters, so "mrd*" -> /^mrd.*$/ and
// "*features*" -> /^.*features.*$/.
function globToRegExp(pattern: string): RegExp {
const escaped = pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\\\*/g, ".*");
return new RegExp(`^${escaped}$`);
}

export function matchPatterns(patterns: string[], values: string[]) {
const fullyQualifiedActions: string[] = [];
patterns.forEach(pattern => {
if (pattern.includes(".")) {
if (pattern.includes("*")) {
// Wildcard selector. A pattern that contains "." matches against the
// fully-qualified action name; otherwise it matches against the unqualified
// name (last segment), mirroring the exact-match branches below. Wildcards
// are expected to select many actions, so no ambiguity error applies here.
const regExp = globToRegExp(pattern);
const scope = pattern.includes(".")
? values
: values.map(value => value.split(".").slice(-1)[0]);
values.forEach((value, i) => {
if (regExp.test(scope[i])) {
fullyQualifiedActions.push(value);
}
});
} else if (pattern.includes(".")) {
if (values.includes(pattern)) {
fullyQualifiedActions.push(pattern);
}
Expand Down
64 changes: 64 additions & 0 deletions core/utils_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
getEffectiveTableFolderSubpath,
getFileFormatValueForIcebergTable,
getStorageUriForIcebergTable,
matchPatterns,
validateConnectionFormat,
validateNoMixedCompilationMode,
validateStorageUriFormat,
Expand Down Expand Up @@ -299,4 +300,67 @@ suite('Dataform Utility Validations', () => {
);
});
});

suite('matchPatterns', () => {
const values = [
'schema.mrd_features_inference',
'schema.mrd_features_training',
'other.customer_orders',
'analytics.mrd_summary',
];

test('exact unqualified name selects the single matching action', () => {
expect(matchPatterns(['mrd_features_inference'], values)).to.deep.equal([
'schema.mrd_features_inference',
]);
});

test('exact fully-qualified name selects that action', () => {
expect(matchPatterns(['other.customer_orders'], values)).to.deep.equal([
'other.customer_orders',
]);
});

test('ambiguous unqualified exact name still throws', () => {
// Two schemas, same unqualified name.
const dupes = ['a.dup', 'b.dup'];
expect(() => matchPatterns(['dup'], dupes)).to.throw();
});

test('bare "*" matches every action', () => {
expect(matchPatterns(['*'], values)).to.deep.equal(values);
});

test('prefix wildcard matches on the unqualified name', () => {
expect(matchPatterns(['mrd*'], values)).to.deep.equal([
'schema.mrd_features_inference',
'schema.mrd_features_training',
'analytics.mrd_summary',
]);
});

test('surrounding wildcards match a substring of the unqualified name', () => {
expect(matchPatterns(['*features*'], values)).to.deep.equal([
'schema.mrd_features_inference',
'schema.mrd_features_training',
]);
});

test('qualified wildcard matches against the fully-qualified name', () => {
expect(matchPatterns(['schema.*'], values)).to.deep.equal([
'schema.mrd_features_inference',
'schema.mrd_features_training',
]);
});

test('wildcard with no matches returns empty (no ambiguity error)', () => {
expect(matchPatterns(['nope*'], values)).to.deep.equal([]);
});

test('literal dot in a qualified wildcard is not a regex wildcard', () => {
// "schemaXmrd..." must NOT match "schema.*" — the "." is literal.
const tricky = ['schema.mrd_a', 'schemaXmrd_b'];
expect(matchPatterns(['schema.*'], tricky)).to.deep.equal(['schema.mrd_a']);
});
});
});