1
- import { getTelemetryFor } from 'ember-codemods-telemetry-helpers' ;
2
- import path from 'path' ;
1
+ import {
2
+ getTelemetry ,
3
+ getTelemetryFor ,
4
+ } from 'ember-codemods-telemetry-helpers' ;
5
+ import { GlobSync } from 'glob' ;
6
+ import path from 'node:path' ;
3
7
import { z } from 'zod' ;
4
8
import logger from './log-helper' ;
9
+ import { type UserOptions } from './options' ;
5
10
6
11
const RuntimeDataSchema = z . object ( {
7
12
type : z . string ( ) . optional ( ) ,
@@ -18,8 +23,22 @@ export type RuntimeData = z.infer<typeof RuntimeDataSchema>;
18
23
* Gets telemetry data for the file and parses it into a valid `RuntimeData`
19
24
* object.
20
25
*/
21
- export function getRuntimeData ( filePath : string ) : RuntimeData {
26
+ export function getRuntimeData (
27
+ filePath : string ,
28
+ { moduleRoot, packageBase } : UserOptions
29
+ ) : RuntimeData {
22
30
let rawTelemetry = getTelemetryFor ( path . resolve ( filePath ) ) ;
31
+
32
+ // FIXME: use either moduleRoot or packageBase??
33
+ if ( ! rawTelemetry && moduleRoot && packageBase ) {
34
+ const modulePath = getModulePathFor ( path . resolve ( filePath ) , {
35
+ moduleRoot,
36
+ packageBase,
37
+ } ) ;
38
+ const moduleKey = generateModuleKey ( modulePath ) ;
39
+ rawTelemetry = getTelemetry ( ) [ moduleKey ] ;
40
+ }
41
+
23
42
if ( ! rawTelemetry ) {
24
43
// Do not re-throw. The most likely reason this happened was because
25
44
// the user's app threw an error. We still want the codemod to work if so.
@@ -50,3 +69,45 @@ class RuntimeDataError extends Error {
50
69
this . name = 'RuntimeDataError' ;
51
70
}
52
71
}
72
+
73
+ /**
74
+ * Transforms a literal "on disk" path to a "module path".
75
+ *
76
+ * @param filePath the path on disk (from current working directory)
77
+ * @returns The in-browser module path for the specified filePath
78
+ */
79
+ function getModulePathFor (
80
+ filePath : string ,
81
+ { moduleRoot, packageBase } : { moduleRoot : string ; packageBase : string }
82
+ ) : string {
83
+ const rootPaths = new GlobSync ( `**/${ packageBase } ` , {
84
+ ignore : [ '**/tmp/**' , '**/node_modules/**' ] ,
85
+ absolute : true ,
86
+ } ) . found ;
87
+
88
+ let bestMatch = '' ;
89
+ let relativePath ;
90
+
91
+ for ( const rootPath of rootPaths ) {
92
+ if ( filePath . startsWith ( rootPath ) && rootPath . length > bestMatch . length ) {
93
+ bestMatch = rootPath ;
94
+ relativePath = filePath . slice (
95
+ rootPath . length + 1 /* for slash */ ,
96
+ - path . extname ( filePath ) . length
97
+ ) ;
98
+ }
99
+ }
100
+
101
+ if ( relativePath ) {
102
+ return `${ moduleRoot } /${ relativePath } ` ;
103
+ }
104
+
105
+ // FIXME: Better error
106
+ throw new Error ( 'Could not determine module path' ) ;
107
+ }
108
+
109
+ function generateModuleKey ( modulePath : string ) : string {
110
+ const moduleKey = modulePath . replace ( 'templates/components/' , 'components/' ) ;
111
+ // If `templates/` still exists in the path then it wasn't a component but a controller-level template instead
112
+ return moduleKey . replace ( 'templates/' , 'controllers/' ) ;
113
+ }
0 commit comments