@uicontract/namer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +49 -0
- package/dist/ai-namer.d.ts +30 -0
- package/dist/ai-namer.d.ts.map +1 -0
- package/dist/ai-namer.js +29 -0
- package/dist/ai-namer.js.map +1 -0
- package/dist/deduplicator.d.ts +20 -0
- package/dist/deduplicator.d.ts.map +1 -0
- package/dist/deduplicator.js +60 -0
- package/dist/deduplicator.js.map +1 -0
- package/dist/deterministic-namer.d.ts +19 -0
- package/dist/deterministic-namer.d.ts.map +1 -0
- package/dist/deterministic-namer.js +77 -0
- package/dist/deterministic-namer.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/naming-rules.d.ts +52 -0
- package/dist/naming-rules.d.ts.map +1 -0
- package/dist/naming-rules.js +101 -0
- package/dist/naming-rules.js.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 UIC Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# @uicontract/namer
|
|
2
|
+
|
|
3
|
+
Naming engine that assigns hierarchical agent IDs to UI elements.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @uicontract/namer
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { assignNames } from '@uicontract/namer';
|
|
15
|
+
import type { RawElement } from '@uicontract/core';
|
|
16
|
+
|
|
17
|
+
const rawElements: RawElement[] = [
|
|
18
|
+
/* output from a parser */
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
const named = await assignNames(rawElements, {
|
|
22
|
+
projectRoot: '/path/to/my-app',
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Each element now has a stable, hierarchical agentId:
|
|
26
|
+
// "settings.billing.pause-subscription.button"
|
|
27
|
+
console.log(named[0].agentId);
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## API
|
|
31
|
+
|
|
32
|
+
- **`assignNames(elements, options)`**: Takes `RawElement[]` produced by a parser and returns `NamedElement[]`, each with a stable `agentId` in `route.component.element-name.type` dot-separated format.
|
|
33
|
+
|
|
34
|
+
ID format: `<route>.<component>.<label>.<type>`
|
|
35
|
+
|
|
36
|
+
Examples:
|
|
37
|
+
- `settings.billing.pause-subscription.button`
|
|
38
|
+
- `login.login-form.email.input`
|
|
39
|
+
- `nav.header.sign-out.link`
|
|
40
|
+
|
|
41
|
+
The namer is deterministic: the same element always receives the same ID across runs. It does not read source files or write anything to disk.
|
|
42
|
+
|
|
43
|
+
## Part of UIC
|
|
44
|
+
|
|
45
|
+
This package is part of [UIC (UI Contracts)](https://github.com/sherifkozman/uicontract) — making web app UIs machine-readable.
|
|
46
|
+
|
|
47
|
+
## License
|
|
48
|
+
|
|
49
|
+
[MIT](../../LICENSE)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI-assisted naming engine (stub).
|
|
3
|
+
*
|
|
4
|
+
* TODO: Connect to an AI provider (e.g., OpenAI, Anthropic) to generate
|
|
5
|
+
* context-aware, human-friendly agent IDs. The AI namer should receive
|
|
6
|
+
* the full element context (surrounding code, component hierarchy, route
|
|
7
|
+
* structure) and produce a naming suggestion that is validated against
|
|
8
|
+
* the agent ID pattern before use. When the AI namer returns null or
|
|
9
|
+
* fails, the deterministic namer is used as a fallback.
|
|
10
|
+
*/
|
|
11
|
+
import type { RawElement } from '@uicontract/core';
|
|
12
|
+
/** Options for the AI naming provider. */
|
|
13
|
+
export interface AiNamerOptions {
|
|
14
|
+
/** Timeout in milliseconds for the AI provider call. */
|
|
15
|
+
timeout?: number;
|
|
16
|
+
/** AI provider identifier (e.g., "openai", "anthropic"). */
|
|
17
|
+
provider?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Attempt to assign an AI-generated agent ID to a RawElement.
|
|
21
|
+
*
|
|
22
|
+
* Currently a stub that always returns null, causing the caller
|
|
23
|
+
* to fall back to deterministic naming.
|
|
24
|
+
*
|
|
25
|
+
* @param _element - The raw element to name.
|
|
26
|
+
* @param _options - AI provider options.
|
|
27
|
+
* @returns null (stub — AI naming not yet implemented).
|
|
28
|
+
*/
|
|
29
|
+
export declare function assignAiName(_element: RawElement, _options?: AiNamerOptions): Promise<string | null>;
|
|
30
|
+
//# sourceMappingURL=ai-namer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-namer.d.ts","sourceRoot":"","sources":["../src/ai-namer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,0CAA0C;AAC1C,MAAM,WAAW,cAAc;IAC7B,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,UAAU,EACpB,QAAQ,CAAC,EAAE,cAAc,GACxB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOxB"}
|
package/dist/ai-namer.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI-assisted naming engine (stub).
|
|
3
|
+
*
|
|
4
|
+
* TODO: Connect to an AI provider (e.g., OpenAI, Anthropic) to generate
|
|
5
|
+
* context-aware, human-friendly agent IDs. The AI namer should receive
|
|
6
|
+
* the full element context (surrounding code, component hierarchy, route
|
|
7
|
+
* structure) and produce a naming suggestion that is validated against
|
|
8
|
+
* the agent ID pattern before use. When the AI namer returns null or
|
|
9
|
+
* fails, the deterministic namer is used as a fallback.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Attempt to assign an AI-generated agent ID to a RawElement.
|
|
13
|
+
*
|
|
14
|
+
* Currently a stub that always returns null, causing the caller
|
|
15
|
+
* to fall back to deterministic naming.
|
|
16
|
+
*
|
|
17
|
+
* @param _element - The raw element to name.
|
|
18
|
+
* @param _options - AI provider options.
|
|
19
|
+
* @returns null (stub — AI naming not yet implemented).
|
|
20
|
+
*/
|
|
21
|
+
export async function assignAiName(_element, _options) {
|
|
22
|
+
// TODO: Implement AI naming. This function should:
|
|
23
|
+
// 1. Serialize the element context into a prompt
|
|
24
|
+
// 2. Call the configured AI provider
|
|
25
|
+
// 3. Validate the response matches ^[a-z][a-z0-9.-]*$
|
|
26
|
+
// 4. Return the validated name, or null on failure/timeout
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=ai-namer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-namer.js","sourceRoot":"","sources":["../src/ai-namer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAYH;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,QAAoB,EACpB,QAAyB;IAEzB,mDAAmD;IACnD,iDAAiD;IACjD,qCAAqC;IACrC,sDAAsD;IACtD,2DAA2D;IAC3D,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ID collision resolution for named elements.
|
|
3
|
+
*
|
|
4
|
+
* Detects duplicate agentIds and appends numeric suffixes (.0, .1, .2)
|
|
5
|
+
* to ALL duplicates. Duplicates are ordered by line number for stability.
|
|
6
|
+
*/
|
|
7
|
+
import type { NamedElement } from '@uicontract/core';
|
|
8
|
+
/**
|
|
9
|
+
* Deduplicate named elements by appending numeric suffixes to collisions.
|
|
10
|
+
*
|
|
11
|
+
* When two or more elements share the same agentId, ALL of them receive
|
|
12
|
+
* a numeric suffix (.0, .1, .2, ...) ordered by line number (ascending).
|
|
13
|
+
*
|
|
14
|
+
* Elements with unique IDs are returned unchanged.
|
|
15
|
+
*
|
|
16
|
+
* @param elements - Array of named elements, potentially with duplicate IDs.
|
|
17
|
+
* @returns New array with unique agentIds. Original array is not mutated.
|
|
18
|
+
*/
|
|
19
|
+
export declare function deduplicateNames(elements: NamedElement[]): NamedElement[];
|
|
20
|
+
//# sourceMappingURL=deduplicator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deduplicator.d.ts","sourceRoot":"","sources":["../src/deduplicator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE,CAyCzE"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ID collision resolution for named elements.
|
|
3
|
+
*
|
|
4
|
+
* Detects duplicate agentIds and appends numeric suffixes (.0, .1, .2)
|
|
5
|
+
* to ALL duplicates. Duplicates are ordered by line number for stability.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Deduplicate named elements by appending numeric suffixes to collisions.
|
|
9
|
+
*
|
|
10
|
+
* When two or more elements share the same agentId, ALL of them receive
|
|
11
|
+
* a numeric suffix (.0, .1, .2, ...) ordered by line number (ascending).
|
|
12
|
+
*
|
|
13
|
+
* Elements with unique IDs are returned unchanged.
|
|
14
|
+
*
|
|
15
|
+
* @param elements - Array of named elements, potentially with duplicate IDs.
|
|
16
|
+
* @returns New array with unique agentIds. Original array is not mutated.
|
|
17
|
+
*/
|
|
18
|
+
export function deduplicateNames(elements) {
|
|
19
|
+
// Group element indices by agentId
|
|
20
|
+
const idGroups = new Map();
|
|
21
|
+
for (let i = 0; i < elements.length; i++) {
|
|
22
|
+
const el = elements[i];
|
|
23
|
+
if (el === undefined)
|
|
24
|
+
continue;
|
|
25
|
+
const existing = idGroups.get(el.agentId);
|
|
26
|
+
if (existing !== undefined) {
|
|
27
|
+
existing.push(i);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
idGroups.set(el.agentId, [i]);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Create a new array with resolved IDs
|
|
34
|
+
const result = elements.map((el) => ({ ...el }));
|
|
35
|
+
for (const indices of idGroups.values()) {
|
|
36
|
+
// Skip groups with no duplicates
|
|
37
|
+
if (indices.length <= 1)
|
|
38
|
+
continue;
|
|
39
|
+
// Sort duplicate indices by line number for stable ordering
|
|
40
|
+
const sortedIndices = [...indices].sort((a, b) => {
|
|
41
|
+
const elA = elements[a];
|
|
42
|
+
const elB = elements[b];
|
|
43
|
+
if (elA === undefined || elB === undefined)
|
|
44
|
+
return 0;
|
|
45
|
+
return elA.line - elB.line;
|
|
46
|
+
});
|
|
47
|
+
// Assign numeric suffixes
|
|
48
|
+
for (let suffixIdx = 0; suffixIdx < sortedIndices.length; suffixIdx++) {
|
|
49
|
+
const elementIndex = sortedIndices[suffixIdx];
|
|
50
|
+
if (elementIndex === undefined)
|
|
51
|
+
continue;
|
|
52
|
+
const el = result[elementIndex];
|
|
53
|
+
if (el === undefined)
|
|
54
|
+
continue;
|
|
55
|
+
el.agentId = `${el.agentId}.${suffixIdx}`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=deduplicator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deduplicator.js","sourceRoot":"","sources":["../src/deduplicator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAwB;IACvD,mCAAmC;IACnC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAoB,CAAC;IAE7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,EAAE,KAAK,SAAS;YAAE,SAAS;QAC/B,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;QAC1C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnB,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,uCAAuC;IACvC,MAAM,MAAM,GAAmB,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;IAEjE,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;QACxC,iCAAiC;QACjC,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC;YAAE,SAAS;QAElC,4DAA4D;QAC5D,MAAM,aAAa,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YAC/C,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;YACxB,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;YACxB,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,SAAS;gBAAE,OAAO,CAAC,CAAC;YACrD,OAAO,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,0BAA0B;QAC1B,KAAK,IAAI,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC;YACtE,MAAM,YAAY,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;YAC9C,IAAI,YAAY,KAAK,SAAS;gBAAE,SAAS;YACzC,MAAM,EAAE,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC;YAChC,IAAI,EAAE,KAAK,SAAS;gBAAE,SAAS;YAC/B,EAAE,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,OAAO,IAAI,SAAS,EAAE,CAAC;QAC5C,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule-based deterministic naming engine.
|
|
3
|
+
*
|
|
4
|
+
* Assigns agentIds to RawElements using a priority-based strategy that
|
|
5
|
+
* combines route, label, handler, component name, and element type.
|
|
6
|
+
*/
|
|
7
|
+
import type { RawElement } from '@uicontract/core';
|
|
8
|
+
/**
|
|
9
|
+
* Assign a deterministic agent ID to a RawElement.
|
|
10
|
+
*
|
|
11
|
+
* Priority order:
|
|
12
|
+
* 1. Route + label + type
|
|
13
|
+
* 2. Route + handler + type
|
|
14
|
+
* 3. Component + label + type
|
|
15
|
+
* 4. Component + handler + type
|
|
16
|
+
* 5. Fallback: component (or "unknown") + type + line
|
|
17
|
+
*/
|
|
18
|
+
export declare function assignDeterministicName(element: RawElement): string;
|
|
19
|
+
//# sourceMappingURL=deterministic-namer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deterministic-namer.d.ts","sourceRoot":"","sources":["../src/deterministic-namer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAsCnD;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CA0CnE"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule-based deterministic naming engine.
|
|
3
|
+
*
|
|
4
|
+
* Assigns agentIds to RawElements using a priority-based strategy that
|
|
5
|
+
* combines route, label, handler, component name, and element type.
|
|
6
|
+
*/
|
|
7
|
+
import { routeToSegments, labelToSegment, handlerToSegment, componentToSegment, } from './naming-rules.js';
|
|
8
|
+
/** Agent ID validation pattern */
|
|
9
|
+
const AGENT_ID_PATTERN = /^[a-z][a-z0-9.-]*$/;
|
|
10
|
+
/**
|
|
11
|
+
* Join non-empty segments with dots and append the element type.
|
|
12
|
+
*/
|
|
13
|
+
function buildId(segments, type) {
|
|
14
|
+
const parts = [...segments, type].filter((s) => s.length > 0);
|
|
15
|
+
return parts.join('.');
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Ensure an agentId matches the required pattern.
|
|
19
|
+
*
|
|
20
|
+
* If the id doesn't start with a letter, prefix with "el".
|
|
21
|
+
* If the id is empty, return "unknown".
|
|
22
|
+
*/
|
|
23
|
+
function ensureValid(id) {
|
|
24
|
+
if (id.length === 0)
|
|
25
|
+
return 'unknown';
|
|
26
|
+
if (AGENT_ID_PATTERN.test(id))
|
|
27
|
+
return id;
|
|
28
|
+
// Strip any remaining invalid characters
|
|
29
|
+
let cleaned = id.replace(/[^a-z0-9.-]/g, '');
|
|
30
|
+
// Ensure starts with a letter
|
|
31
|
+
cleaned = cleaned.replace(/^[^a-z]+/, '');
|
|
32
|
+
if (cleaned.length === 0)
|
|
33
|
+
return 'unknown';
|
|
34
|
+
return cleaned;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Assign a deterministic agent ID to a RawElement.
|
|
38
|
+
*
|
|
39
|
+
* Priority order:
|
|
40
|
+
* 1. Route + label + type
|
|
41
|
+
* 2. Route + handler + type
|
|
42
|
+
* 3. Component + label + type
|
|
43
|
+
* 4. Component + handler + type
|
|
44
|
+
* 5. Fallback: component (or "unknown") + type + line
|
|
45
|
+
*/
|
|
46
|
+
export function assignDeterministicName(element) {
|
|
47
|
+
const routeSegments = element.route !== null ? routeToSegments(element.route) : [];
|
|
48
|
+
const hasRoute = routeSegments.length > 0;
|
|
49
|
+
const labelSeg = element.label !== null ? labelToSegment(element.label) : '';
|
|
50
|
+
const hasLabel = labelSeg.length > 0;
|
|
51
|
+
const handlerSeg = element.handler !== null ? handlerToSegment(element.handler) : '';
|
|
52
|
+
const hasHandler = handlerSeg.length > 0;
|
|
53
|
+
const componentSeg = element.componentName !== null
|
|
54
|
+
? componentToSegment(element.componentName)
|
|
55
|
+
: '';
|
|
56
|
+
const hasComponent = componentSeg.length > 0;
|
|
57
|
+
// Priority 1: route + label + type
|
|
58
|
+
if (hasRoute && hasLabel) {
|
|
59
|
+
return ensureValid(buildId([...routeSegments, labelSeg], element.type));
|
|
60
|
+
}
|
|
61
|
+
// Priority 2: route + handler + type
|
|
62
|
+
if (hasRoute && hasHandler) {
|
|
63
|
+
return ensureValid(buildId([...routeSegments, handlerSeg], element.type));
|
|
64
|
+
}
|
|
65
|
+
// Priority 3: component + label + type
|
|
66
|
+
if (hasComponent && hasLabel) {
|
|
67
|
+
return ensureValid(buildId([componentSeg, labelSeg], element.type));
|
|
68
|
+
}
|
|
69
|
+
// Priority 4: component + handler + type
|
|
70
|
+
if (hasComponent && hasHandler) {
|
|
71
|
+
return ensureValid(buildId([componentSeg, handlerSeg], element.type));
|
|
72
|
+
}
|
|
73
|
+
// Priority 5: fallback — component (or "unknown") + type + line
|
|
74
|
+
const base = hasComponent ? componentSeg : 'unknown';
|
|
75
|
+
return ensureValid(`${base}.${element.type}.${element.line}`);
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=deterministic-namer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deterministic-namer.js","sourceRoot":"","sources":["../src/deterministic-namer.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @uicontract/namer — naming engine for UIC elements.
|
|
3
|
+
*
|
|
4
|
+
* Takes RawElements discovered by a parser and assigns stable,
|
|
5
|
+
* hierarchical agentIds using deterministic rules (with an optional
|
|
6
|
+
* AI-assisted mode for future use).
|
|
7
|
+
*/
|
|
8
|
+
import type { RawElement, NamedElement } from '@uicontract/core';
|
|
9
|
+
/** Options for the naming engine. */
|
|
10
|
+
export interface NamerOptions {
|
|
11
|
+
/** Enable AI-assisted naming (falls back to deterministic if AI returns null). */
|
|
12
|
+
ai?: boolean;
|
|
13
|
+
/** Timeout in milliseconds for AI naming calls. */
|
|
14
|
+
aiTimeout?: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Name a list of raw elements, producing NamedElements with unique agentIds.
|
|
18
|
+
*
|
|
19
|
+
* 1. Each element is named via the deterministic namer (AI stub returns null).
|
|
20
|
+
* 2. Duplicate IDs are resolved with numeric suffixes.
|
|
21
|
+
*
|
|
22
|
+
* @param elements - Raw elements from a parser's discovery phase.
|
|
23
|
+
* @param options - Naming options (AI mode is stubbed for now).
|
|
24
|
+
* @returns Array of NamedElements with unique agentIds.
|
|
25
|
+
*/
|
|
26
|
+
export declare function nameElements(elements: ReadonlyArray<RawElement>, options?: NamerOptions): NamedElement[];
|
|
27
|
+
export { sanitizeSegment, camelToKebab, routeToSegments, labelToSegment, handlerToSegment, componentToSegment, } from './naming-rules.js';
|
|
28
|
+
export { assignDeterministicName } from './deterministic-namer.js';
|
|
29
|
+
export { deduplicateNames } from './deduplicator.js';
|
|
30
|
+
export { assignAiName } from './ai-namer.js';
|
|
31
|
+
export type { AiNamerOptions } from './ai-namer.js';
|
|
32
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAKjE,qCAAqC;AACrC,MAAM,WAAW,YAAY;IAC3B,kFAAkF;IAClF,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,aAAa,CAAC,UAAU,CAAC,EACnC,OAAO,CAAC,EAAE,YAAY,GACrB,YAAY,EAAE,CA0BhB;AAGD,OAAO,EACL,eAAe,EACf,YAAY,EACZ,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @uicontract/namer — naming engine for UIC elements.
|
|
3
|
+
*
|
|
4
|
+
* Takes RawElements discovered by a parser and assigns stable,
|
|
5
|
+
* hierarchical agentIds using deterministic rules (with an optional
|
|
6
|
+
* AI-assisted mode for future use).
|
|
7
|
+
*/
|
|
8
|
+
import { assignDeterministicName } from './deterministic-namer.js';
|
|
9
|
+
import { deduplicateNames } from './deduplicator.js';
|
|
10
|
+
import { assignAiName } from './ai-namer.js';
|
|
11
|
+
/**
|
|
12
|
+
* Name a list of raw elements, producing NamedElements with unique agentIds.
|
|
13
|
+
*
|
|
14
|
+
* 1. Each element is named via the deterministic namer (AI stub returns null).
|
|
15
|
+
* 2. Duplicate IDs are resolved with numeric suffixes.
|
|
16
|
+
*
|
|
17
|
+
* @param elements - Raw elements from a parser's discovery phase.
|
|
18
|
+
* @param options - Naming options (AI mode is stubbed for now).
|
|
19
|
+
* @returns Array of NamedElements with unique agentIds.
|
|
20
|
+
*/
|
|
21
|
+
export function nameElements(elements, options) {
|
|
22
|
+
const useAi = options?.ai ?? false;
|
|
23
|
+
const aiTimeout = options?.aiTimeout;
|
|
24
|
+
// Phase 1: assign names
|
|
25
|
+
const named = elements.map((element) => {
|
|
26
|
+
let agentId = null;
|
|
27
|
+
// Attempt AI naming if enabled (currently a stub that returns null)
|
|
28
|
+
if (useAi) {
|
|
29
|
+
// AI naming is async but we handle it synchronously here since
|
|
30
|
+
// the stub always returns null. When real AI is connected, this
|
|
31
|
+
// function signature should become async.
|
|
32
|
+
void assignAiName(element, { timeout: aiTimeout });
|
|
33
|
+
}
|
|
34
|
+
// Deterministic fallback (always used until AI is implemented)
|
|
35
|
+
if (agentId === null) {
|
|
36
|
+
agentId = assignDeterministicName(element);
|
|
37
|
+
}
|
|
38
|
+
return { ...element, agentId };
|
|
39
|
+
});
|
|
40
|
+
// Phase 2: deduplicate
|
|
41
|
+
return deduplicateNames(named);
|
|
42
|
+
}
|
|
43
|
+
// Re-export individual modules for direct access and testing
|
|
44
|
+
export { sanitizeSegment, camelToKebab, routeToSegments, labelToSegment, handlerToSegment, componentToSegment, } from './naming-rules.js';
|
|
45
|
+
export { assignDeterministicName } from './deterministic-namer.js';
|
|
46
|
+
export { deduplicateNames } from './deduplicator.js';
|
|
47
|
+
export { assignAiName } from './ai-namer.js';
|
|
48
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAU7C;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAC1B,QAAmC,EACnC,OAAsB;IAEtB,MAAM,KAAK,GAAG,OAAO,EAAE,EAAE,IAAI,KAAK,CAAC;IACnC,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,CAAC;IAErC,wBAAwB;IACxB,MAAM,KAAK,GAAmB,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QACrD,IAAI,OAAO,GAAkB,IAAI,CAAC;QAElC,oEAAoE;QACpE,IAAI,KAAK,EAAE,CAAC;YACV,+DAA+D;YAC/D,gEAAgE;YAChE,0CAA0C;YAC1C,KAAK,YAAY,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;QACrD,CAAC;QAED,+DAA+D;QAC/D,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,OAAO,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;QAC7C,CAAC;QAED,OAAO,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,uBAAuB;IACvB,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED,6DAA6D;AAC7D,OAAO,EACL,eAAe,EACf,YAAY,EACZ,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Character sanitization and naming rules for agent ID segments.
|
|
3
|
+
*
|
|
4
|
+
* Agent IDs must match: ^[a-z][a-z0-9.-]*$
|
|
5
|
+
* Each segment is a dot-separated part of the ID.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Convert camelCase or PascalCase text to kebab-case.
|
|
9
|
+
*
|
|
10
|
+
* Handles consecutive uppercase letters (acronyms) by treating them as a
|
|
11
|
+
* single group followed by the next lowercase run.
|
|
12
|
+
* e.g. "MyHTTPClient" -> "my-http-client"
|
|
13
|
+
*/
|
|
14
|
+
export declare function camelToKebab(text: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Sanitize a text string into a valid agent ID segment.
|
|
17
|
+
*
|
|
18
|
+
* - Lowercases
|
|
19
|
+
* - Replaces spaces, underscores, and camelCase boundaries with hyphens
|
|
20
|
+
* - Removes special characters (keeps letters, digits, hyphens)
|
|
21
|
+
* - Collapses consecutive hyphens
|
|
22
|
+
* - Trims leading and trailing hyphens
|
|
23
|
+
* - Strips leading digits so the segment starts with a letter
|
|
24
|
+
*/
|
|
25
|
+
export declare function sanitizeSegment(text: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Split a route path into sanitized segments.
|
|
28
|
+
*
|
|
29
|
+
* e.g. "/settings/billing" -> ["settings", "billing"]
|
|
30
|
+
*/
|
|
31
|
+
export declare function routeToSegments(route: string): string[];
|
|
32
|
+
/**
|
|
33
|
+
* Convert a label string into a sanitized segment.
|
|
34
|
+
*
|
|
35
|
+
* e.g. "Pause subscription" -> "pause-subscription"
|
|
36
|
+
*/
|
|
37
|
+
export declare function labelToSegment(label: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* Convert an event handler name into a sanitized segment.
|
|
40
|
+
*
|
|
41
|
+
* Strips common prefixes ("handle", "on") before converting.
|
|
42
|
+
* e.g. "handlePauseSubscription" -> "pause-subscription"
|
|
43
|
+
* e.g. "onClick" -> "click"
|
|
44
|
+
*/
|
|
45
|
+
export declare function handlerToSegment(handler: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* Convert a component name (PascalCase/camelCase) into a sanitized segment.
|
|
48
|
+
*
|
|
49
|
+
* e.g. "BillingSettings" -> "billing-settings"
|
|
50
|
+
*/
|
|
51
|
+
export declare function componentToSegment(componentName: string): string;
|
|
52
|
+
//# sourceMappingURL=naming-rules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naming-rules.d.ts","sourceRoot":"","sources":["../src/naming-rules.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASjD;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAyBpD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAKvD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAgBxD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAEhE"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Character sanitization and naming rules for agent ID segments.
|
|
3
|
+
*
|
|
4
|
+
* Agent IDs must match: ^[a-z][a-z0-9.-]*$
|
|
5
|
+
* Each segment is a dot-separated part of the ID.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Convert camelCase or PascalCase text to kebab-case.
|
|
9
|
+
*
|
|
10
|
+
* Handles consecutive uppercase letters (acronyms) by treating them as a
|
|
11
|
+
* single group followed by the next lowercase run.
|
|
12
|
+
* e.g. "MyHTTPClient" -> "my-http-client"
|
|
13
|
+
*/
|
|
14
|
+
export function camelToKebab(text) {
|
|
15
|
+
if (text.length === 0)
|
|
16
|
+
return '';
|
|
17
|
+
// Insert hyphen between lowercase/digit and uppercase
|
|
18
|
+
let result = text.replace(/([a-z0-9])([A-Z])/g, '$1-$2');
|
|
19
|
+
// Insert hyphen between consecutive uppercase and uppercase+lowercase
|
|
20
|
+
result = result.replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2');
|
|
21
|
+
return result.toLowerCase();
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Sanitize a text string into a valid agent ID segment.
|
|
25
|
+
*
|
|
26
|
+
* - Lowercases
|
|
27
|
+
* - Replaces spaces, underscores, and camelCase boundaries with hyphens
|
|
28
|
+
* - Removes special characters (keeps letters, digits, hyphens)
|
|
29
|
+
* - Collapses consecutive hyphens
|
|
30
|
+
* - Trims leading and trailing hyphens
|
|
31
|
+
* - Strips leading digits so the segment starts with a letter
|
|
32
|
+
*/
|
|
33
|
+
export function sanitizeSegment(text) {
|
|
34
|
+
if (text.length === 0)
|
|
35
|
+
return '';
|
|
36
|
+
// First convert camelCase to kebab-case
|
|
37
|
+
let result = camelToKebab(text);
|
|
38
|
+
// Replace spaces and underscores with hyphens
|
|
39
|
+
result = result.replace(/[\s_]+/g, '-');
|
|
40
|
+
// Replace anything that isn't a lowercase letter, digit, or hyphen with a hyphen
|
|
41
|
+
result = result.replace(/[^a-z0-9-]+/g, '-');
|
|
42
|
+
// Collapse consecutive hyphens
|
|
43
|
+
result = result.replace(/-{2,}/g, '-');
|
|
44
|
+
// Trim leading and trailing hyphens
|
|
45
|
+
result = result.replace(/^-+|-+$/g, '');
|
|
46
|
+
// Strip leading digits so result starts with a letter
|
|
47
|
+
result = result.replace(/^[0-9]+/, '');
|
|
48
|
+
// Trim hyphens again after digit stripping
|
|
49
|
+
result = result.replace(/^-+/, '');
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Split a route path into sanitized segments.
|
|
54
|
+
*
|
|
55
|
+
* e.g. "/settings/billing" -> ["settings", "billing"]
|
|
56
|
+
*/
|
|
57
|
+
export function routeToSegments(route) {
|
|
58
|
+
return route
|
|
59
|
+
.split('/')
|
|
60
|
+
.map((s) => sanitizeSegment(s))
|
|
61
|
+
.filter((s) => s.length > 0);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Convert a label string into a sanitized segment.
|
|
65
|
+
*
|
|
66
|
+
* e.g. "Pause subscription" -> "pause-subscription"
|
|
67
|
+
*/
|
|
68
|
+
export function labelToSegment(label) {
|
|
69
|
+
return sanitizeSegment(label);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Convert an event handler name into a sanitized segment.
|
|
73
|
+
*
|
|
74
|
+
* Strips common prefixes ("handle", "on") before converting.
|
|
75
|
+
* e.g. "handlePauseSubscription" -> "pause-subscription"
|
|
76
|
+
* e.g. "onClick" -> "click"
|
|
77
|
+
*/
|
|
78
|
+
export function handlerToSegment(handler) {
|
|
79
|
+
let stripped = handler;
|
|
80
|
+
// Strip "handle" prefix (case-sensitive, expect camelCase)
|
|
81
|
+
if (stripped.startsWith('handle') && stripped.length > 6) {
|
|
82
|
+
stripped = stripped.slice(6);
|
|
83
|
+
// Lowercase the first character of the remaining text
|
|
84
|
+
stripped = stripped.charAt(0).toLowerCase() + stripped.slice(1);
|
|
85
|
+
}
|
|
86
|
+
// Strip "on" prefix (case-sensitive)
|
|
87
|
+
else if (stripped.startsWith('on') && stripped.length > 2 && /[A-Z]/.test(stripped.charAt(2))) {
|
|
88
|
+
stripped = stripped.slice(2);
|
|
89
|
+
stripped = stripped.charAt(0).toLowerCase() + stripped.slice(1);
|
|
90
|
+
}
|
|
91
|
+
return sanitizeSegment(stripped);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Convert a component name (PascalCase/camelCase) into a sanitized segment.
|
|
95
|
+
*
|
|
96
|
+
* e.g. "BillingSettings" -> "billing-settings"
|
|
97
|
+
*/
|
|
98
|
+
export function componentToSegment(componentName) {
|
|
99
|
+
return sanitizeSegment(componentName);
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=naming-rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naming-rules.js","sourceRoot":"","sources":["../src/naming-rules.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@uicontract/namer",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Naming engine that assigns hierarchical agent IDs to UI elements",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "UIC Contributors",
|
|
8
|
+
"homepage": "https://github.com/sherifkozman/uicontract/tree/main/packages/namer",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/sherifkozman/uicontract.git",
|
|
12
|
+
"directory": "packages/namer"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/sherifkozman/uicontract/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"uic",
|
|
19
|
+
"ui-contracts",
|
|
20
|
+
"namer",
|
|
21
|
+
"agent-id",
|
|
22
|
+
"naming-engine"
|
|
23
|
+
],
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=20"
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"main": "./dist/index.js",
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"import": "./dist/index.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"LICENSE",
|
|
41
|
+
"README.md"
|
|
42
|
+
],
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@uicontract/core": "0.1.0"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsc -b",
|
|
48
|
+
"test": "vitest run",
|
|
49
|
+
"typecheck": "tsc --noEmit",
|
|
50
|
+
"lint": "eslint src"
|
|
51
|
+
}
|
|
52
|
+
}
|