Merge pull request #10073 from backstage/rugvip/csname
catalog-model: enable usage of : and / in entity names
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
---
|
||||
'@backstage/catalog-model': patch
|
||||
---
|
||||
|
||||
Updated `parseEntityRef` to allow `:` and `/` in the entity name. For example, parsing `'component:default/foo:bar'` will result in the name `'foo:bar'`.
|
||||
|
||||
Note that only parsing `'foo:bar'` itself will result in the name `'bar'` and the entity kind `'foo'`, meaning this is a particularly nasty trap for user defined entity references. For this reason it is strongly discouraged to use names that contain these characters, and the catalog model does not allow it by default. However, this change now makes is possible to use these names if the default catalog validation is replaced, and in particular a high level of automation of the catalog population can limit issues that it might otherwise cause.
|
||||
@@ -34,11 +34,24 @@ describe('ref', () => {
|
||||
it('rejects bad inputs', () => {
|
||||
expect(() => parseEntityRef(null as any)).toThrow();
|
||||
expect(() => parseEntityRef(7 as any)).toThrow();
|
||||
expect(() => parseEntityRef('a:b:c')).toThrow();
|
||||
expect(() => parseEntityRef('a/b/c')).toThrow();
|
||||
expect(() => parseEntityRef('a/b:c')).toThrow();
|
||||
expect(() => parseEntityRef('a:b/c/d')).toThrow();
|
||||
expect(() => parseEntityRef('a:b/c:d')).toThrow();
|
||||
});
|
||||
|
||||
it('allows names with : and /', () => {
|
||||
expect(
|
||||
parseEntityRef('a:b:c', { defaultKind: 'k', defaultNamespace: 'ns' }),
|
||||
).toEqual({ kind: 'a', namespace: 'ns', name: 'b:c' });
|
||||
expect(
|
||||
parseEntityRef('a/b/c', { defaultKind: 'k', defaultNamespace: 'ns' }),
|
||||
).toEqual({ kind: 'k', namespace: 'a', name: 'b/c' });
|
||||
expect(
|
||||
parseEntityRef('a/b:c', { defaultKind: 'k', defaultNamespace: 'ns' }),
|
||||
).toEqual({ kind: 'k', namespace: 'a', name: 'b:c' });
|
||||
expect(
|
||||
parseEntityRef('a:b/c/d', { defaultKind: 'k', defaultNamespace: 'ns' }),
|
||||
).toEqual({ kind: 'a', namespace: 'b', name: 'c/d' });
|
||||
expect(
|
||||
parseEntityRef('a:b/c:d', { defaultKind: 'k', defaultNamespace: 'ns' }),
|
||||
).toEqual({ kind: 'a', namespace: 'b', name: 'c:d' });
|
||||
});
|
||||
|
||||
it('rejects empty parts in strings', () => {
|
||||
|
||||
@@ -23,18 +23,25 @@ function parseRefString(ref: string): {
|
||||
namespace?: string;
|
||||
name: string;
|
||||
} {
|
||||
const match = /^([^:/]+:)?([^:/]+\/)?([^:/]+)$/.exec(ref.trim());
|
||||
if (!match) {
|
||||
let colonI = ref.indexOf(':');
|
||||
const slashI = ref.indexOf('/');
|
||||
|
||||
// If the / is ahead of the :, treat the rest as the name
|
||||
if (slashI !== -1 && slashI < colonI) {
|
||||
colonI = -1;
|
||||
}
|
||||
|
||||
const kind = colonI === -1 ? undefined : ref.slice(0, colonI);
|
||||
const namespace = slashI === -1 ? undefined : ref.slice(colonI + 1, slashI);
|
||||
const name = ref.slice(Math.max(colonI + 1, slashI + 1));
|
||||
|
||||
if (kind === '' || namespace === '' || name === '') {
|
||||
throw new TypeError(
|
||||
`Entity reference "${ref}" was not on the form [<kind>:][<namespace>/]<name>`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
kind: match[1]?.slice(0, -1),
|
||||
namespace: match[2]?.slice(0, -1),
|
||||
name: match[3],
|
||||
};
|
||||
return { kind, namespace, name };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user