rbxts-transformer-commit-migrations 1.0.2 → 1.2.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/bin/init.js CHANGED
@@ -15,7 +15,7 @@ if (!existsSync(huskyDir)) {
15
15
  process.exit(1);
16
16
  }
17
17
 
18
- const setupResolve = `npx resolve-commit-migrations\n`;
18
+ const setupResolve = `npx resolve-commit-migrations | xargs git add\n`;
19
19
 
20
20
  if (existsSync(hookFile)) {
21
21
  const existing = readFileSync(hookFile, "utf-8");
package/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export declare function $migrate(order: number): never;
2
- export declare function $migrate(order: "__resolved"): number;
3
- export declare function $migrate(order: number | "__resolved"): number | undefined;
2
+ export declare function $migrate(order: "__resolved", path: string[]): number;
3
+ export declare function $migrate(order: number | "__resolved", path: string[]): number | undefined;
package/out/abc.js ADDED
@@ -0,0 +1,7 @@
1
+ import { $migrate } from "../index.js";
2
+ function test(b) {
3
+ return 0;
4
+ }
5
+ export const abc = {
6
+ hello: { abc: test($migrate(0)) }
7
+ };
@@ -4,29 +4,56 @@ import { readFileSync, writeFileSync, existsSync } from "fs";
4
4
  import { glob } from "glob";
5
5
  import loadMigrationEntries from "../util/loadMigrationEntries.js";
6
6
  import { CONFIG, MACRO, MACRO_CALL_REGEX, MACRO_REGEX } from "../config.js";
7
- function findEntryName(node) {
7
+ function getConfigPathFromTransformerConfig(tsconfigPath = "tsconfig.json") {
8
+ const raw = readFileSync(tsconfigPath, "utf-8");
9
+ if (!raw)
10
+ return;
11
+ const result = ts.parseConfigFileTextToJson(tsconfigPath, raw);
12
+ if (result.error || !result.config)
13
+ return undefined;
14
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
15
+ const plugins = result.config.compilerOptions?.plugins ?? [];
16
+ const entry = plugins.find((p) => p.transform === "rbxts-transformer-commit-migrations");
17
+ if (!entry)
18
+ return undefined;
19
+ return entry.configPath;
20
+ }
21
+ function findEntryPath(node) {
22
+ const parts = [];
8
23
  let current = node.parent;
9
24
  while (current) {
10
25
  if (ts.isPropertyAssignment(current) || ts.isShorthandPropertyAssignment(current)) {
11
- const name = ts.isIdentifier(current.name) ? current.name.text : null;
12
- return name;
26
+ if (ts.isIdentifier(current.name) || ts.isStringLiteral(current.name)) {
27
+ parts.push(current.name.text);
28
+ }
29
+ else {
30
+ return null;
31
+ }
32
+ current = current.parent;
13
33
  }
14
- if (ts.isCallExpression(current) || ts.isPropertyAccessExpression(current)) {
34
+ else if (ts.isCallExpression(current) ||
35
+ ts.isPropertyAccessExpression(current) ||
36
+ ts.isObjectLiteralExpression(current)) {
15
37
  current = current.parent;
16
38
  }
17
39
  else {
18
40
  break;
19
41
  }
20
42
  }
21
- return null;
43
+ return parts.length > 0 ? parts.reverse() : null;
22
44
  }
45
+ const config = getConfigPathFromTransformerConfig() ?? CONFIG;
23
46
  const files = glob.sync("src/**/*.ts");
24
47
  const migrations = [];
25
48
  const migrationData = {};
26
49
  const usedOrders = new Set();
50
+ const changed = [];
27
51
  function walk(node, ctx) {
28
52
  if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && MACRO_REGEX.test(node.expression.text)) {
29
- const entry = findEntryName(node);
53
+ const path = findEntryPath(node);
54
+ if (!path || path.length === 0)
55
+ return;
56
+ const entry = path.join("/");
30
57
  const orderArg = node.arguments[0];
31
58
  const order = orderArg ? ts.isNumericLiteral(orderArg) ? parseInt(orderArg.getText()) : null : 0;
32
59
  if (order !== null && usedOrders.has(order)) {
@@ -41,10 +68,10 @@ function walk(node, ctx) {
41
68
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
42
69
  usedOrders.add(order);
43
70
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
44
- migrationData[entry] = { timestamp: Date.now(), order: order };
71
+ migrationData[entry] = { timestamp: Date.now(), order: order, path };
45
72
  ctx.changed = true;
73
+ migrations.push(entry);
46
74
  }
47
- migrations.push(entry);
48
75
  }
49
76
  ts.forEachChild(node, (node) => {
50
77
  walk(node, ctx);
@@ -56,32 +83,39 @@ for (const file of files) {
56
83
  const ctx = { changed: false };
57
84
  walk(sourceFile, ctx);
58
85
  if (ctx.changed) {
86
+ changed.push(file);
59
87
  writeFileSync(file, src.replaceAll(MACRO_CALL_REGEX, `${MACRO}("__resolved")`));
60
88
  }
61
89
  }
62
- const [previousMigrations] = loadMigrationEntries(CONFIG);
90
+ const [previousMigrations] = loadMigrationEntries(config);
63
91
  const removedMigrations = previousMigrations.filter((v) => !migrations.includes(v));
64
92
  if (removedMigrations.length > 0) {
65
93
  console.error(`Removed migrations: ${removedMigrations}. Migrations should never be removed!`);
66
94
  process.exit(1);
67
95
  }
68
96
  const newMigrations = migrations.filter((v) => !previousMigrations.includes(v));
69
- if (newMigrations.length === 0)
97
+ if (newMigrations.length === 0) {
98
+ console.error("No new migrations to resolve.");
70
99
  process.exit(0);
100
+ }
71
101
  const newLines = newMigrations
72
- .map((e) => `\t${e}: { timestamp: ${migrationData[e].timestamp}, order: ${migrationData[e].order} },`)
102
+ .map((e) => `\t"${e}": { timestamp: ${migrationData[e].timestamp}, order: ${migrationData[e].order}, path: ${JSON.stringify(migrationData[e].path)} },`)
73
103
  .join("\n");
74
104
  const migratedEntries = migrations.map((e) => `"${e}"`).join(" | ");
75
- if (!existsSync(CONFIG)) {
76
- writeFileSync(CONFIG, `type MigratedEntries = ${migratedEntries}\n\ninterface MigrationData {\n\ttimestamp: number\n\torder: number\n}\n\n// AUTO-GENERATED MIGRATION CONFIG - DO NOT EDIT\nexport const MIGRATED_ENTRIES: Record<MigratedEntries, MigrationData> = {\n${newLines}\n};\n`);
105
+ if (!existsSync(config)) {
106
+ writeFileSync(config, `type MigratedEntries = ${migratedEntries}\n\ninterface MigrationData {\n\tpath: string[]\n\ttimestamp: number\n\torder: number\n}\n\n// AUTO-GENERATED MIGRATION CONFIG - DO NOT EDIT\nexport const MIGRATED_ENTRIES: Record<MigratedEntries, MigrationData> = {\n${newLines}\n};\n`);
77
107
  }
78
108
  else {
79
- const lines = readFileSync(CONFIG, "utf-8").split("\n");
109
+ const lines = readFileSync(config, "utf-8").split("\n");
80
110
  const typeIndex = lines.findIndex((l) => l.startsWith("type MigratedEntries"));
81
111
  if (typeIndex !== -1) {
82
112
  lines[typeIndex] = `type MigratedEntries = ${migratedEntries}`;
83
113
  }
84
114
  const updated = lines.join("\n").replace(/\};\s*$/, `${newLines}\n};`);
85
- writeFileSync(CONFIG, updated);
115
+ writeFileSync(config, updated);
116
+ }
117
+ changed.push(config);
118
+ console.error(`Successfuly resolved ${newMigrations.length} new migrations. [${newMigrations}]`);
119
+ for (const path of changed) {
120
+ console.log(path.replace(/\\/g, "/"));
86
121
  }
87
- console.log(`Successfuly resolved ${newMigrations.length} new migrations. [${newMigrations}]`);
package/out/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import ts from "typescript";
2
- import { findMacroCall, replaceMacroCall } from "./macro.js";
2
+ import { findMacroCall, replaceMacroCall } from "./util/macro.js";
3
3
  import loadMigrationEntries from "./util/loadMigrationEntries.js";
4
4
  import { CONFIG } from "./config.js";
5
5
  import { existsSync } from "node:fs";
@@ -18,18 +18,21 @@ export default function (_, config) {
18
18
  return (file) => {
19
19
  if (config?.files && !config.files.some((f) => file.fileName.includes(f)))
20
20
  return file;
21
- function visit(node) {
22
- if (!ts.isPropertyAssignment(node) || !findMacroCall(node.initializer))
23
- return ts.visitEachChild(node, visit, ctx);
21
+ function visit(node, currentPath) {
22
+ if (!ts.isPropertyAssignment(node))
23
+ return ts.visitEachChild(node, (node) => visit(node, currentPath), ctx);
24
24
  const entry = ts.isIdentifier(node.name) ? node.name.text : node.name.getText(file);
25
- const replacement = orderedEntries.indexOf(entry);
26
- if (replacement !== -1) {
27
- const newInit = replaceMacroCall(node.initializer, replacement);
25
+ const newPath = [...currentPath, entry];
26
+ if (!findMacroCall(node.initializer))
27
+ return ts.visitEachChild(node, (node) => visit(node, newPath), ctx);
28
+ const order = orderedEntries.indexOf(newPath.join("/"));
29
+ if (order !== -1) {
30
+ const newInit = replaceMacroCall(node.initializer, order, newPath);
28
31
  return ts.factory.createPropertyAssignment(node.name, newInit);
29
32
  }
30
- return ts.visitEachChild(node, visit, ctx);
33
+ return ts.visitEachChild(node, (node) => visit(node, newPath), ctx);
31
34
  }
32
- return ts.visitNode(file, visit);
35
+ return ts.visitNode(file, (node) => visit(node, []));
33
36
  };
34
37
  };
35
38
  }
package/out/macro.js CHANGED
@@ -4,10 +4,14 @@ export function findMacroCall(node) {
4
4
  if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && MACRO_REGEX.test(node.expression.text)) {
5
5
  return node;
6
6
  }
7
- let found;
8
- ts.forEachChild(node, (child) => { if (found)
9
- return; found = findMacroCall(child); });
10
- return found;
7
+ if (ts.isCallExpression(node)) {
8
+ for (const arg of node.arguments) {
9
+ if (ts.isCallExpression(arg) && ts.isIdentifier(arg.expression) && MACRO_REGEX.test(arg.expression.text)) {
10
+ return arg;
11
+ }
12
+ }
13
+ }
14
+ return undefined;
11
15
  }
12
16
  export function replaceMacroCall(node, replacement) {
13
17
  if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && MACRO_REGEX.test(node.expression.text)) {
package/out/test.js ADDED
@@ -0,0 +1,7 @@
1
+ import { $migrate } from "../index.js";
2
+ function test(a) {
3
+ return 0;
4
+ }
5
+ const abc = {
6
+ test: { bruh: test($migrate(0)) }
7
+ };
@@ -26,7 +26,7 @@ export default function (config) {
26
26
  const result = [];
27
27
  const object = {};
28
28
  for (const prop of declaration.initializer.properties) {
29
- if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name) || !ts.isObjectLiteralExpression(prop.initializer))
29
+ if (!ts.isPropertyAssignment(prop) || !ts.isStringLiteral(prop.name) || !ts.isObjectLiteralExpression(prop.initializer))
30
30
  continue;
31
31
  result.push(prop.name.text);
32
32
  object[prop.name.text] = reconstructProperties(prop.initializer.properties);
@@ -0,0 +1,35 @@
1
+ import ts from "typescript";
2
+ import { MACRO_REGEX } from "../config.js";
3
+ export function findMacroCall(node) {
4
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && MACRO_REGEX.test(node.expression.text)) {
5
+ return node;
6
+ }
7
+ if (ts.isCallExpression(node)) {
8
+ for (const arg of node.arguments) {
9
+ if (ts.isCallExpression(arg) && ts.isIdentifier(arg.expression) && MACRO_REGEX.test(arg.expression.text)) {
10
+ return arg;
11
+ }
12
+ }
13
+ }
14
+ return undefined;
15
+ }
16
+ export function replaceMacroCall(node, order, path) {
17
+ if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
18
+ const newArgs = [];
19
+ let changed = false;
20
+ for (const arg of node.arguments) {
21
+ if (ts.isCallExpression(arg) && ts.isIdentifier(arg.expression) && MACRO_REGEX.test(arg.expression.text)) {
22
+ newArgs.push(ts.factory.createNumericLiteral(order));
23
+ newArgs.push(ts.factory.createArrayLiteralExpression(path.map(p => ts.factory.createStringLiteral(p)), false));
24
+ changed = true;
25
+ }
26
+ else {
27
+ newArgs.push(arg);
28
+ }
29
+ }
30
+ if (changed) {
31
+ return ts.factory.updateCallExpression(node, node.expression, node.typeArguments, newArgs);
32
+ }
33
+ }
34
+ return ts.visitEachChild(node, (child) => replaceMacroCall(child, order, path), undefined);
35
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rbxts-transformer-commit-migrations",
3
- "version": "1.0.2",
3
+ "version": "1.2.0",
4
4
  "description": "rbxts transformer used in user data migration builder chains",
5
5
  "main": "out/index.js",
6
6
  "type": "module",