Skip to content

Commit 0f43dcd

Browse files
committed
Hacks for Discourse to run this codemod on their plugins
1 parent 9f4b5b9 commit 0f43dcd

File tree

5 files changed

+71
-5
lines changed

5 files changed

+71
-5
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"cosmiconfig": "^8.1.3",
5353
"deepmerge-ts": "^4.3.0",
5454
"ember-codemods-telemetry-helpers": "^3.0.0",
55+
"glob": "^8.1.0",
5556
"minimatch": "^7.4.6",
5657
"winston": "^3.8.2",
5758
"zod": "^3.21.4"
@@ -75,7 +76,6 @@
7576
"eslint-plugin-node": "^11.1.0",
7677
"eslint-plugin-unicorn": "^46.0.0",
7778
"execa": "^5.1.1",
78-
"glob": "^8.1.0",
7979
"jest": "^29.5.0",
8080
"prettier": "^2.8.8",
8181
"release-it": "^15.10.1",

transforms/helpers/options.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ export const UserOptionsSchema = z.object({
100100
type: TypeSchema.describe(
101101
'Apply transformation to only passed type.'
102102
).optional(),
103+
moduleRoot: z.string().min(1).optional().describe('FIXME'),
104+
packageBase: z.string().min(1).optional().describe('FIXME'),
103105
});
104106

105107
export type UserOptions = z.infer<typeof UserOptionsSchema>;

transforms/helpers/runtime-data.ts

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
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';
37
import { z } from 'zod';
48
import logger from './log-helper';
9+
import { type UserOptions } from './options';
510

611
const RuntimeDataSchema = z.object({
712
type: z.string().optional(),
@@ -18,8 +23,22 @@ export type RuntimeData = z.infer<typeof RuntimeDataSchema>;
1823
* Gets telemetry data for the file and parses it into a valid `RuntimeData`
1924
* object.
2025
*/
21-
export function getRuntimeData(filePath: string): RuntimeData {
26+
export function getRuntimeData(
27+
filePath: string,
28+
{ moduleRoot, packageBase }: UserOptions
29+
): RuntimeData {
2230
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+
2342
if (!rawTelemetry) {
2443
// Do not re-throw. The most likely reason this happened was because
2544
// the user's app threw an error. We still want the codemod to work if so.
@@ -50,3 +69,45 @@ class RuntimeDataError extends Error {
5069
this.name = 'RuntimeDataError';
5170
}
5271
}
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+
}

transforms/helpers/transform.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ function _maybeTransformEmberObjects(
7777
} else {
7878
const options: Options = {
7979
...userOptions,
80-
runtimeData: getRuntimeData(filePath),
80+
runtimeData: getRuntimeData(filePath, userOptions),
8181
};
8282

8383
// eslint-disable-next-line unicorn/no-array-for-each
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
declare module 'ember-codemods-telemetry-helpers' {
22
export function getTelemetryFor(filePath: string): unknown;
3+
export function getTelemetry(
4+
cacheKey?: string | undefined
5+
): Record<string, unknown>;
36
export function setTelemetry(telemetry: unknown): void;
47
}

0 commit comments

Comments
 (0)