@trackunit/iris-app 2.5.11 → 2.5.13

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.
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rewritePageContent = rewritePageContent;
4
+ const css_classname_utils_1 = require("@trackunit/css-classname-utils");
5
+ const classname_ast_rewrite_1 = require("../utils/classname-ast-rewrite");
6
+ const PAGE_CONTENT_PATTERN = "page-content";
7
+ const CONTENT_SPACE_TOKEN = "p-content-space";
8
+ const OVERFLOW_AUTO_TOKEN = "overflow-auto";
9
+ /**
10
+ * True when `token` is already present as a whole class token, including when
11
+ * wrapped in Tailwind variant prefixes (e.g. `xl:overflow-hidden`).
12
+ */
13
+ function hasOverflowToken(classes) {
14
+ return classes.some(cls => /(^|:)overflow-/.test(cls));
15
+ }
16
+ /**
17
+ * Rewrites the legacy `page-content` Tailwind class to
18
+ * `overflow-auto p-content-space` across every rewritable file under a
19
+ * single resolved extension's `sourceRoot`.
20
+ *
21
+ * When the classname already declares its own `overflow-*` token, only
22
+ * `p-content-space` is inserted — emitting a second `overflow-auto` would be
23
+ * dead (or, when an identical `overflow-auto` is already present, a
24
+ * duplicate). Scroll ownership stays with the element's existing overflow
25
+ * declaration.
26
+ *
27
+ * Scoped to one extension per call — the caller (the orchestrator) loops
28
+ * over every Asset Home/Site Home/Admin extension.
29
+ *
30
+ * Only performs the `page-content` classname rewrite: it does not touch
31
+ * `pb-*`/`pb-responsive-space` classes or produce a report, both of which are
32
+ * separate migration steps.
33
+ */
34
+ function rewritePageContent(tree, extension) {
35
+ return (0, classname_ast_rewrite_1.transformClassnamesUnderSourceRoot)(tree, extension.sourceRoot, content => content.includes(PAGE_CONTENT_PATTERN), value => {
36
+ const replacement = hasOverflowToken((0, css_classname_utils_1.splitClasses)(value))
37
+ ? CONTENT_SPACE_TOKEN
38
+ : `${OVERFLOW_AUTO_TOKEN} ${CONTENT_SPACE_TOKEN}`;
39
+ return (0, css_classname_utils_1.replaceClassToken)(value, PAGE_CONTENT_PATTERN, replacement);
40
+ });
41
+ }
42
+ //# sourceMappingURL=rewrite-page-content.js.map
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ /**
3
+ * Why invent/resolve declined to pick an ASA content shell. Surfaced in
4
+ * migration console output and UnresolvedSurfaceReport so humans (and
5
+ * third parties) can plan manual `p-content-space` placement.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.shellSkipReason = void 0;
9
+ const MESSAGES = {
10
+ "entry-missing": "extension entry file was not found under sourceRoot",
11
+ "parse-failed": "extension entry/source could not be parsed as TypeScript/TSX",
12
+ "no-root-jsx": "could not find a root JSX return in the entry component",
13
+ "empty-wrapper": "provider/Suspense/Fragment wrappers had no JSX child to walk into",
14
+ cycle: "component graph walked into a cycle while resolving the content shell",
15
+ "dynamic-component": "content shell is behind a dynamic import / lazy component (not followed)",
16
+ "unresolvable-import": "could not resolve a static local import for the host component",
17
+ "non-host-element": "leaf JSX is not a div/main/section with an inventable className host",
18
+ "router-prop-unresolved": "RouterProvider router={...} prop was not a simple identifier",
19
+ "router-inline-arrow-components": "TanStack routes use inline arrow `component: () => <...>` instead of a named component identifier — invent cannot follow them",
20
+ "router-no-analysable-leaves": "router graph had no analysable named route leaves with a clear overflow content shell",
21
+ "no-editable-classname": "div/main/section host has no editable className/class (literal or bound Tailwind helper)",
22
+ "no-overflow-on-host": "host has a className but does not itself own scrollable overflow (overflow-auto/scroll/overlay) — invent only pads the scroll owner",
23
+ "multiple-overflow-candidates": "host has more than one inventable overflow classname binding (ambiguous)",
24
+ "header-on-shell": "host also renders PageHeader/Topbar/Header — pad the body below the header, not this shell",
25
+ "descendant-owns-scroll": "a descendant owns overflow scrolling — pad that scroll owner, not the outer wrapper",
26
+ "clipping-overflow-on-host": "host uses overflow-hidden/clip (full-bleed / clipping shell) — not inventable as a content inset",
27
+ "unclear-graph": "content-shell graph was unclear; invent refused to guess a first-div",
28
+ };
29
+ /**
30
+ * Builds a structured skip reason for invent/resolve console + report output.
31
+ *
32
+ * @param code - Stable skip-reason code from the inventable-shell contract
33
+ * @param detail - Optional path / leaf list / host name appended in parentheses
34
+ * @returns {ShellSkipReason} Structured reason with a human-readable message
35
+ */
36
+ const shellSkipReason = (code, detail) => ({
37
+ code,
38
+ message: detail === undefined || detail.length === 0 ? MESSAGES[code] : `${MESSAGES[code]} (${detail})`,
39
+ });
40
+ exports.shellSkipReason = shellSkipReason;
41
+ //# sourceMappingURL=shell-skip-reason.js.map
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isRewritableFile = void 0;
4
+ exports.parseTsestreeSource = parseTsestreeSource;
5
+ exports.findClassnameLocations = findClassnameLocations;
6
+ exports.buildClassnameEdits = buildClassnameEdits;
7
+ exports.buildEditsForLocation = buildEditsForLocation;
8
+ exports.applyEdits = applyEdits;
9
+ exports.transformClassnamesUnderSourceRoot = transformClassnamesUnderSourceRoot;
10
+ exports.visitRewritableFiles = visitRewritableFiles;
11
+ const devkit_1 = require("@nx/devkit");
12
+ const css_classname_utils_1 = require("@trackunit/css-classname-utils");
13
+ const types_1 = require("@typescript-eslint/types");
14
+ const typescript_estree_1 = require("@typescript-eslint/typescript-estree");
15
+ /**
16
+ * Shared TSESTree parsing/traversal/splice helpers for classname-rewriting Nx
17
+ * migrations (the `p-content-space-codemod` and any future codemod that needs
18
+ * to detect and rewrite Tailwind classnames across a Tree).
19
+ *
20
+ * `@trackunit/css-classname-utils`'s detection helpers
21
+ * (`findClassnameStringsInAttribute`/`InCall`/`InVariable`) expect TSESTree AST
22
+ * nodes, which today only ESLint's parser produces in this repo. Nx migrations
23
+ * run outside of ESLint, so this module wraps
24
+ * `@typescript-eslint/typescript-estree`'s `parse` (the same underlying parser
25
+ * `@typescript-eslint/parser` delegates to) to turn a raw source string into an
26
+ * equivalent TSESTree `Program`, then re-splices edits directly against the
27
+ * original source string by AST node range (mirroring the range-splice
28
+ * approach `insertAttributeIntoOpeningTag` in
29
+ * `libs/react/components/migrations/utils/jsx-utils.ts` uses for the
30
+ * TypeScript-compiler-API case).
31
+ */
32
+ /**
33
+ * Parses raw TypeScript/TSX source into a TSESTree `Program` AST.
34
+ *
35
+ * `jsx: true` is always passed (harmless for plain `.ts` files) so callers
36
+ * don't need to branch on file extension before parsing.
37
+ */
38
+ function parseTsestreeSource(content) {
39
+ return (0, typescript_estree_1.parse)(content, { jsx: true, loc: true, range: true });
40
+ }
41
+ /**
42
+ * Finds every classname string location in a parsed source: JSX
43
+ * `className`/`class` attributes, Tailwind-function calls (`cva`, `cn`,
44
+ * `clsx`, etc. — see `TAILWIND_FUNCTIONS`), and
45
+ * `*Class`/`*ClassName`/`*Classes`-suffixed variable declarators.
46
+ *
47
+ * Walks the AST with `simpleTraverse` (shipped by
48
+ * `@typescript-eslint/typescript-estree`) instead of a hand-rolled
49
+ * visitor-keys walker, since it already knows every node type's visitor keys
50
+ * for the resolved parser version.
51
+ */
52
+ function findClassnameLocations(program) {
53
+ const locations = [];
54
+ (0, typescript_estree_1.simpleTraverse)(program, {
55
+ enter: node => {
56
+ if (node.type === types_1.AST_NODE_TYPES.JSXAttribute) {
57
+ locations.push(...(0, css_classname_utils_1.findClassnameStringsInAttribute)(node));
58
+ }
59
+ else if (node.type === types_1.AST_NODE_TYPES.CallExpression) {
60
+ locations.push(...(0, css_classname_utils_1.findClassnameStringsInCall)(node));
61
+ }
62
+ else if (node.type === types_1.AST_NODE_TYPES.VariableDeclarator) {
63
+ locations.push(...(0, css_classname_utils_1.findClassnameStringsInVariable)(node));
64
+ }
65
+ },
66
+ });
67
+ return locations;
68
+ }
69
+ /**
70
+ * Builds the edit(s) needed to apply `transform` to a `ClassnameLocation`'s
71
+ * `fixNode`, splicing by the node's own `.range` against the original source
72
+ * (there is no ESLint `SourceCode`/fixer available outside of rule
73
+ * execution).
74
+ *
75
+ * - `Literal`: one edit replacing the whole quoted literal, preserving the
76
+ * original quote style via `quoteString`.
77
+ * - `TemplateLiteral`: one edit per quasi whose raw text changes, splicing
78
+ * only the text between the surrounding backtick/`${`/`}` delimiters so the
79
+ * template's interpolated expressions are left untouched.
80
+ *
81
+ * Returns an empty array when `transform` doesn't change the value, so
82
+ * callers can cheaply detect "no-op" locations.
83
+ *
84
+ * Prefer {@link buildEditsForLocation} when the caller has a full
85
+ * `ClassnameLocation` — that path can drop an emptied JSX `className`
86
+ * attribute entirely instead of leaving `className=""`.
87
+ */
88
+ function buildClassnameEdits(fixNode, transform) {
89
+ if (fixNode.type === types_1.AST_NODE_TYPES.Literal) {
90
+ if (typeof fixNode.value !== "string")
91
+ return [];
92
+ const newValue = transform(fixNode.value);
93
+ if (newValue === fixNode.value)
94
+ return [];
95
+ return [{ range: fixNode.range, text: (0, css_classname_utils_1.quoteString)(newValue, fixNode) }];
96
+ }
97
+ const edits = [];
98
+ for (const quasi of fixNode.quasis) {
99
+ const newRaw = transform(quasi.value.raw);
100
+ if (newRaw === quasi.value.raw)
101
+ continue;
102
+ const start = quasi.range[0] + 1;
103
+ const end = quasi.range[1] - (quasi.tail ? 1 : 2);
104
+ edits.push({ range: [start, end], text: newRaw });
105
+ }
106
+ return edits;
107
+ }
108
+ /**
109
+ * Like {@link buildClassnameEdits}, but when a JSX `className`/`class`
110
+ * attribute's token list becomes empty, removes the whole attribute
111
+ * (including a single run of preceding horizontal whitespace) instead of
112
+ * writing `className=""`.
113
+ *
114
+ * Non-JSX locations (cva/cn/clsx calls, `*ClassName` variables) still fall
115
+ * through to an empty-string literal — deleting those would require
116
+ * statement-level surgery we deliberately do not attempt here.
117
+ */
118
+ function buildEditsForLocation(location, transform, sourceContent) {
119
+ const { fixNode, context, reportNode } = location;
120
+ if (context.type === "jsx-attribute" &&
121
+ reportNode.type === types_1.AST_NODE_TYPES.JSXAttribute &&
122
+ fixNode.type === types_1.AST_NODE_TYPES.Literal &&
123
+ typeof fixNode.value === "string") {
124
+ const newValue = transform(fixNode.value);
125
+ if (newValue === fixNode.value)
126
+ return [];
127
+ if (newValue === "") {
128
+ return [buildJsxAttributeRemovalEdit(reportNode, sourceContent)];
129
+ }
130
+ return [{ range: fixNode.range, text: (0, css_classname_utils_1.quoteString)(newValue, fixNode) }];
131
+ }
132
+ return buildClassnameEdits(fixNode, transform);
133
+ }
134
+ /**
135
+ * Removes a JSX attribute, swallowing the horizontal whitespace immediately
136
+ * before it so `<div className="x">` becomes `<div>` rather than `<div >`.
137
+ */
138
+ function buildJsxAttributeRemovalEdit(attribute, sourceContent) {
139
+ let start = attribute.range[0];
140
+ while (start > 0 && /[ \t]/.test(sourceContent[start - 1] ?? "")) {
141
+ start -= 1;
142
+ }
143
+ return { range: [start, attribute.range[1]], text: "" };
144
+ }
145
+ /**
146
+ * Applies a batch of range-based edits to `content`, splicing in
147
+ * reverse-offset order so that an earlier edit's range is never invalidated
148
+ * by one applied after it.
149
+ */
150
+ function applyEdits(content, edits) {
151
+ const byDescendingStart = [...edits].sort((a, b) => b.range[0] - a.range[0]);
152
+ let result = content;
153
+ for (const edit of byDescendingStart) {
154
+ const [start, end] = edit.range;
155
+ result = result.slice(0, start) + edit.text + result.slice(end);
156
+ }
157
+ return result;
158
+ }
159
+ const REWRITABLE_EXTENSIONS = [".ts", ".tsx"];
160
+ /**
161
+ * Manifest files must never be mutated by a classname-rewriting migration
162
+ * (a hard Success Criterion of GLU-1570). No in-repo extension currently
163
+ * declares a `sourceRoot` that overlaps its own manifest file, but this
164
+ * filename guard is defense-in-depth so that invariant doesn't depend
165
+ * entirely on that data convention holding forever.
166
+ */
167
+ const MANIFEST_FILENAME_PATTERN = /(^|\/)(iris-app-manifest|extension-manifest)\.ts$/;
168
+ /**
169
+ * `true` for `.ts`/`.tsx` files a classname-rewriting migration is allowed
170
+ * to read/write — excludes `iris-app-manifest.ts`/`extension-manifest.ts`
171
+ * files. Shared by every transform/report module in this codemod so the
172
+ * file-extension allowlist and manifest exclusion live in exactly one place.
173
+ */
174
+ const isRewritableFile = (filePath) => REWRITABLE_EXTENSIONS.some(ext => filePath.endsWith(ext)) && !MANIFEST_FILENAME_PATTERN.test(filePath);
175
+ exports.isRewritableFile = isRewritableFile;
176
+ /**
177
+ * Walks every rewritable file under `sourceRoot`, and for files passing the
178
+ * cheap `shouldConsider` substring pre-check, parses them, finds every
179
+ * classname location, applies `transform` to each, and writes back any file
180
+ * that actually changed.
181
+ *
182
+ * Shared by `rewritePageContent` and `removeRedundantPadding` so the
183
+ * walk → pre-filter → parse → find → edit → write skeleton lives in exactly
184
+ * one place instead of being duplicated per transform.
185
+ */
186
+ function transformClassnamesUnderSourceRoot(tree, sourceRoot, shouldConsider, transform) {
187
+ const filesChanged = [];
188
+ (0, devkit_1.visitNotIgnoredFiles)(tree, sourceRoot, filePath => {
189
+ if (!(0, exports.isRewritableFile)(filePath))
190
+ return;
191
+ const content = tree.read(filePath, "utf-8");
192
+ if (content === null || !shouldConsider(content))
193
+ return;
194
+ const program = parseTsestreeSource(content);
195
+ const locations = findClassnameLocations(program);
196
+ const edits = locations.flatMap(location => buildEditsForLocation(location, transform, content));
197
+ if (edits.length === 0)
198
+ return;
199
+ tree.write(filePath, applyEdits(content, edits));
200
+ filesChanged.push(filePath);
201
+ });
202
+ return { filesChanged };
203
+ }
204
+ /**
205
+ * Read-only walk of every rewritable file under `sourceRoot`, invoking
206
+ * `visitor` with each file's path and content. Never writes. Shared by
207
+ * `findUnresolvedSurface`'s detection pass, which only needs to inspect
208
+ * content, not rewrite it.
209
+ */
210
+ function visitRewritableFiles(tree, sourceRoot, visitor) {
211
+ (0, devkit_1.visitNotIgnoredFiles)(tree, sourceRoot, filePath => {
212
+ if (!(0, exports.isRewritableFile)(filePath))
213
+ return;
214
+ const content = tree.read(filePath, "utf-8");
215
+ if (content === null)
216
+ return;
217
+ visitor(filePath, content);
218
+ });
219
+ }
220
+ //# sourceMappingURL=classname-ast-rewrite.js.map
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveExtensionTypes = resolveExtensionTypes;
4
+ const tslib_1 = require("tslib");
5
+ const devkit_1 = require("@nx/devkit");
6
+ const ts = tslib_1.__importStar(require("typescript"));
7
+ const APPS_MANIFEST_PATTERN = /^apps\/([^/]+)\/iris-app-manifest\.ts$/;
8
+ const DEFAULT_ENTRY_COMPONENT_FILE = "index.tsx";
9
+ /**
10
+ * Statically resolves every `apps/*\/iris-app-manifest.ts`'s declared
11
+ * `extensions` to a concrete `type` + `sourceRoot`, deduping extensions
12
+ * shared by multiple apps into a single entry.
13
+ *
14
+ * Uses the TypeScript compiler API against the Nx `Tree` (not `fs`/dynamic
15
+ * `import()`), so uncommitted edits held only in the Tree are seen and the
16
+ * migration stays deterministic.
17
+ */
18
+ function resolveExtensionTypes(tree) {
19
+ const tsconfigPaths = readTsconfigPaths(tree);
20
+ const resolvedByPath = new Map();
21
+ const unresolved = [];
22
+ (0, devkit_1.visitNotIgnoredFiles)(tree, "apps", filePath => {
23
+ const match = APPS_MANIFEST_PATTERN.exec(filePath);
24
+ if (match === null)
25
+ return;
26
+ const appName = match[1];
27
+ if (appName === undefined)
28
+ return;
29
+ const content = tree.read(filePath, "utf-8");
30
+ if (content === null)
31
+ return;
32
+ const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
33
+ const manifestObject = resolveDefaultExportObjectLiteral(sourceFile);
34
+ if (manifestObject === null)
35
+ return;
36
+ const extensionIdentifiers = getExtensionIdentifiers(manifestObject, filePath);
37
+ if (extensionIdentifiers.length === 0)
38
+ return;
39
+ const importSpecifiersByLocalName = getImportSpecifiersByLocalName(sourceFile);
40
+ for (const identifierName of extensionIdentifiers) {
41
+ const specifier = importSpecifiersByLocalName.get(identifierName);
42
+ if (specifier === undefined) {
43
+ devkit_1.logger.warn(`[resolve-extension-types] Could not find an import for "${identifierName}" referenced in ${filePath}'s extensions array.`);
44
+ continue;
45
+ }
46
+ const extensionManifestPath = tsconfigPaths.get(specifier);
47
+ if (extensionManifestPath === undefined) {
48
+ devkit_1.logger.warn(`[resolve-extension-types] Could not resolve module specifier "${specifier}" (from ${filePath}) via tsconfig.base.json paths.`);
49
+ unresolved.push({ app: appName, specifier });
50
+ continue;
51
+ }
52
+ const existing = resolvedByPath.get(extensionManifestPath);
53
+ if (existing !== undefined) {
54
+ if (!existing.ownerApps.includes(appName))
55
+ existing.ownerApps.push(appName);
56
+ continue;
57
+ }
58
+ const resolvedExtension = resolveExtensionManifest(tree, extensionManifestPath);
59
+ if (resolvedExtension === null) {
60
+ devkit_1.logger.warn(`[resolve-extension-types] Could not resolve extension manifest fields from "${extensionManifestPath}" (imported as "${specifier}" in ${filePath}).`);
61
+ continue;
62
+ }
63
+ resolvedByPath.set(extensionManifestPath, { ...resolvedExtension, ownerApps: [appName] });
64
+ }
65
+ });
66
+ return { resolved: [...resolvedByPath.values()], unresolved };
67
+ }
68
+ function resolveExtensionManifest(tree, extensionManifestPath) {
69
+ const content = tree.read(extensionManifestPath, "utf-8");
70
+ if (content === null)
71
+ return null;
72
+ const sourceFile = ts.createSourceFile(extensionManifestPath, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
73
+ const extensionObject = resolveDefaultExportObjectLiteral(sourceFile);
74
+ if (extensionObject === null)
75
+ return null;
76
+ const id = getStringLiteralProperty(extensionObject, "id");
77
+ const type = getStringLiteralProperty(extensionObject, "type");
78
+ const sourceRoot = getStringLiteralProperty(extensionObject, "sourceRoot");
79
+ if (id === null || type === null || sourceRoot === null)
80
+ return null;
81
+ const main = getStringLiteralProperty(extensionObject, "main") ?? DEFAULT_ENTRY_COMPONENT_FILE;
82
+ return { id, type, sourceRoot, extensionManifestPath, main };
83
+ }
84
+ /**
85
+ * Finds the object literal behind `export default <expr>;`, following a
86
+ * single level of identifier indirection (e.g. `const x = {...}; export
87
+ * default x;`) since that's the shape every real manifest in this repo uses.
88
+ */
89
+ function resolveDefaultExportObjectLiteral(sourceFile) {
90
+ for (const statement of sourceFile.statements) {
91
+ if (!ts.isExportAssignment(statement) || statement.isExportEquals)
92
+ continue;
93
+ const expr = statement.expression;
94
+ if (ts.isObjectLiteralExpression(expr))
95
+ return expr;
96
+ if (ts.isIdentifier(expr))
97
+ return findObjectLiteralVariable(sourceFile, expr.text);
98
+ }
99
+ return null;
100
+ }
101
+ function findObjectLiteralVariable(sourceFile, name) {
102
+ for (const statement of sourceFile.statements) {
103
+ if (!ts.isVariableStatement(statement))
104
+ continue;
105
+ for (const declaration of statement.declarationList.declarations) {
106
+ if (!ts.isIdentifier(declaration.name) || declaration.name.text !== name)
107
+ continue;
108
+ if (declaration.initializer !== undefined && ts.isObjectLiteralExpression(declaration.initializer)) {
109
+ return declaration.initializer;
110
+ }
111
+ }
112
+ }
113
+ return null;
114
+ }
115
+ function getExtensionIdentifiers(manifestObject, filePath) {
116
+ for (const property of manifestObject.properties) {
117
+ if (!ts.isPropertyAssignment(property))
118
+ continue;
119
+ if (!ts.isIdentifier(property.name) || property.name.text !== "extensions")
120
+ continue;
121
+ if (!ts.isArrayLiteralExpression(property.initializer))
122
+ return [];
123
+ const identifiers = [];
124
+ for (const element of property.initializer.elements) {
125
+ if (ts.isIdentifier(element)) {
126
+ identifiers.push(element.text);
127
+ }
128
+ else {
129
+ devkit_1.logger.warn(`[resolve-extension-types] Skipping a non-identifier element of the "extensions" array in ${filePath} (only \`import x from "..."\`-style identifiers can be statically resolved).`);
130
+ }
131
+ }
132
+ return identifiers;
133
+ }
134
+ return [];
135
+ }
136
+ function getImportSpecifiersByLocalName(sourceFile) {
137
+ const result = new Map();
138
+ for (const statement of sourceFile.statements) {
139
+ if (!ts.isImportDeclaration(statement))
140
+ continue;
141
+ const moduleSpecifier = statement.moduleSpecifier;
142
+ if (!ts.isStringLiteral(moduleSpecifier))
143
+ continue;
144
+ const specifier = moduleSpecifier.text;
145
+ const importClause = statement.importClause;
146
+ if (importClause === undefined)
147
+ continue;
148
+ if (importClause.name !== undefined) {
149
+ result.set(importClause.name.text, specifier);
150
+ }
151
+ const namedBindings = importClause.namedBindings;
152
+ if (namedBindings !== undefined && ts.isNamedImports(namedBindings)) {
153
+ for (const element of namedBindings.elements) {
154
+ result.set(element.name.text, specifier);
155
+ }
156
+ }
157
+ }
158
+ return result;
159
+ }
160
+ function getStringLiteralProperty(objectLiteral, propertyName) {
161
+ for (const property of objectLiteral.properties) {
162
+ if (!ts.isPropertyAssignment(property))
163
+ continue;
164
+ if (!ts.isIdentifier(property.name) || property.name.text !== propertyName)
165
+ continue;
166
+ return ts.isStringLiteral(property.initializer) ? property.initializer.text : null;
167
+ }
168
+ return null;
169
+ }
170
+ function readTsconfigPaths(tree) {
171
+ const result = new Map();
172
+ const content = tree.read("tsconfig.base.json", "utf-8");
173
+ if (content === null) {
174
+ devkit_1.logger.warn("[resolve-extension-types] tsconfig.base.json not found; no extension imports will resolve.");
175
+ return result;
176
+ }
177
+ let parsed;
178
+ try {
179
+ parsed = JSON.parse(stripJsonComments(content));
180
+ }
181
+ catch (error) {
182
+ const message = error instanceof Error ? error.message : String(error);
183
+ devkit_1.logger.warn(`[resolve-extension-types] Failed to parse tsconfig.base.json: ${message}`);
184
+ return result;
185
+ }
186
+ const paths = parsed.compilerOptions?.paths ?? {};
187
+ for (const [specifier, targets] of Object.entries(paths)) {
188
+ const target = targets[0];
189
+ if (target === undefined)
190
+ continue;
191
+ result.set(specifier, normalizeRepoRelativePath(target));
192
+ }
193
+ return result;
194
+ }
195
+ /**
196
+ * `tsconfig.base.json` is committed without comments today, but strip
197
+ * line comments and block comments defensively in case that changes, so a
198
+ * stray comment doesn't hard-fail `JSON.parse`. The line-comment regex
199
+ * requires the preceding character not be `:` so it doesn't mangle URL-like
200
+ * string values (e.g. `"https://..."`).
201
+ */
202
+ function stripJsonComments(content) {
203
+ return content.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1");
204
+ }
205
+ function normalizeRepoRelativePath(pathValue) {
206
+ return pathValue.replace(/^\.\//, "");
207
+ }
208
+ //# sourceMappingURL=resolve-extension-types.js.map
package/migrations.json CHANGED
@@ -1,3 +1,9 @@
1
1
  {
2
- "generators": {}
2
+ "generators": {
3
+ "v2-5-12-p-content-space-codemod": {
4
+ "version": "2.5.12",
5
+ "description": "Rewrite the legacy page-content Tailwind class to overflow-auto p-content-space, invent p-content-space on high-confidence Asset Home/Site Home/Admin content shells, and remove now-redundant bottom-inset classes.",
6
+ "implementation": "./migrations/p-content-space-codemod/orchestrator"
7
+ }
8
+ }
3
9
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trackunit/iris-app",
3
- "version": "2.5.11",
3
+ "version": "2.5.13",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "main": "src/index.js",
6
6
  "generators": "./generators.json",
@@ -10,7 +10,9 @@
10
10
  "node": ">=24.x"
11
11
  },
12
12
  "dependencies": {
13
- "@trackunit/css-classname-utils": "0.0.18",
13
+ "@trackunit/css-classname-utils": "0.0.20",
14
+ "@typescript-eslint/types": "8.58.1",
15
+ "@typescript-eslint/typescript-estree": "8.58.1",
14
16
  "pacote": "^21.0.4",
15
17
  "libnpmpublish": "^11.1.3",
16
18
  "open": "^10.2.0",
@@ -24,10 +26,10 @@
24
26
  "@nx/react": "23.1.0",
25
27
  "@npmcli/arborist": "^9.1.9",
26
28
  "win-ca": "^3.5.1",
27
- "@trackunit/iris-app-build-utilities": "2.4.11",
28
- "@trackunit/react-graphql-tools": "1.15.15",
29
- "@trackunit/shared-utils": "1.16.18",
30
- "@trackunit/iris-app-api": "2.4.7",
29
+ "@trackunit/iris-app-build-utilities": "2.4.13",
30
+ "@trackunit/react-graphql-tools": "1.15.17",
31
+ "@trackunit/shared-utils": "1.16.20",
32
+ "@trackunit/iris-app-api": "2.4.9",
31
33
  "tslib": "^2.6.2",
32
34
  "@clack/prompts": "^1.0.0",
33
35
  "@npm/types": "^1.0.2",