rbxts-transformer-commit-migrations 1.1.0 → 1.2.1

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/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,22 +4,45 @@ 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 = {};
@@ -27,7 +50,10 @@ const usedOrders = new Set();
27
50
  const changed = [];
28
51
  function walk(node, ctx) {
29
52
  if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && MACRO_REGEX.test(node.expression.text)) {
30
- const entry = findEntryName(node);
53
+ const path = findEntryPath(node);
54
+ if (!path || path.length === 0)
55
+ return;
56
+ const entry = path.join("/");
31
57
  const orderArg = node.arguments[0];
32
58
  const order = orderArg ? ts.isNumericLiteral(orderArg) ? parseInt(orderArg.getText()) : null : 0;
33
59
  if (order !== null && usedOrders.has(order)) {
@@ -42,10 +68,10 @@ function walk(node, ctx) {
42
68
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
43
69
  usedOrders.add(order);
44
70
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
45
- migrationData[entry] = { timestamp: Date.now(), order: order };
71
+ migrationData[entry] = { timestamp: Date.now(), order: order, path };
46
72
  ctx.changed = true;
73
+ migrations.push(entry);
47
74
  }
48
- migrations.push(entry);
49
75
  }
50
76
  ts.forEachChild(node, (node) => {
51
77
  walk(node, ctx);
@@ -61,7 +87,7 @@ for (const file of files) {
61
87
  writeFileSync(file, src.replaceAll(MACRO_CALL_REGEX, `${MACRO}("__resolved")`));
62
88
  }
63
89
  }
64
- const [previousMigrations] = loadMigrationEntries(CONFIG);
90
+ const [previousMigrations] = loadMigrationEntries(config);
65
91
  const removedMigrations = previousMigrations.filter((v) => !migrations.includes(v));
66
92
  if (removedMigrations.length > 0) {
67
93
  console.error(`Removed migrations: ${removedMigrations}. Migrations should never be removed!`);
@@ -73,22 +99,22 @@ if (newMigrations.length === 0) {
73
99
  process.exit(0);
74
100
  }
75
101
  const newLines = newMigrations
76
- .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)} },`)
77
103
  .join("\n");
78
104
  const migratedEntries = migrations.map((e) => `"${e}"`).join(" | ");
79
- if (!existsSync(CONFIG)) {
80
- 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`);
81
107
  }
82
108
  else {
83
- const lines = readFileSync(CONFIG, "utf-8").split("\n");
109
+ const lines = readFileSync(config, "utf-8").split("\n");
84
110
  const typeIndex = lines.findIndex((l) => l.startsWith("type MigratedEntries"));
85
111
  if (typeIndex !== -1) {
86
112
  lines[typeIndex] = `type MigratedEntries = ${migratedEntries}`;
87
113
  }
88
114
  const updated = lines.join("\n").replace(/\};\s*$/, `${newLines}\n};`);
89
- writeFileSync(CONFIG, updated);
115
+ writeFileSync(config, updated);
90
116
  }
91
- changed.push(CONFIG);
117
+ changed.push(config);
92
118
  console.error(`Successfuly resolved ${newMigrations.length} new migrations. [${newMigrations}]`);
93
119
  for (const path of changed) {
94
120
  console.log(path.replace(/\\/g, "/"));
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 CHANGED
@@ -1,7 +1,7 @@
1
1
  import { $migrate } from "../index.js";
2
- function test(b) {
2
+ function test(a) {
3
3
  return 0;
4
4
  }
5
- export const abc = {
6
- hello: test($migrate(0))
5
+ const abc = {
6
+ test: { bruh: test($migrate(0)) }
7
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.1.0",
3
+ "version": "1.2.1",
4
4
  "description": "rbxts transformer used in user data migration builder chains",
5
5
  "main": "out/index.js",
6
6
  "type": "module",