@venizia/dev-configs 0.4.1 → 0.4.2
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/dist/cli/clean.d.ts.map +1 -1
- package/dist/cli/clean.js +10 -0
- package/dist/cli/clean.js.map +1 -1
- package/dist/cli/codemod/index.d.ts +13 -0
- package/dist/cli/codemod/index.d.ts.map +1 -0
- package/dist/cli/codemod/index.js +83 -0
- package/dist/cli/codemod/index.js.map +1 -0
- package/dist/cli/codemod/model-settings.d.ts +33 -0
- package/dist/cli/codemod/model-settings.d.ts.map +1 -0
- package/dist/cli/codemod/model-settings.js +270 -0
- package/dist/cli/codemod/model-settings.js.map +1 -0
- package/dist/cli/index.js +5 -1
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/clean.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clean.d.ts","sourceRoot":"","sources":["../../src/cli/clean.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"clean.d.ts","sourceRoot":"","sources":["../../src/cli/clean.ts"],"names":[],"mappings":"AAYA,sFAAsF;AACtF,qBAAa,YAAY;IACvB,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;CAa3C"}
|
package/dist/cli/clean.js
CHANGED
|
@@ -5,12 +5,22 @@ const node_fs_1 = require("node:fs");
|
|
|
5
5
|
const node_path_1 = require("node:path");
|
|
6
6
|
/** What a build and the checks generate, relative to the project root. */
|
|
7
7
|
const GENERATED_PATHS = ['dist', 'node_modules/.cache'];
|
|
8
|
+
/**
|
|
9
|
+
* `incremental` is on in the base tsconfig, so a type-check that emits nothing leaves
|
|
10
|
+
* `<tsconfig name>.tsbuildinfo` next to the tsconfig. One inside `dist` is already removed with it.
|
|
11
|
+
*/
|
|
12
|
+
const BUILD_INFO_SUFFIX = '.tsbuildinfo';
|
|
8
13
|
/** `devz clean`: removes what the build and the checks generate, and nothing else. */
|
|
9
14
|
class CleanCommand {
|
|
10
15
|
static run(opts) {
|
|
11
16
|
for (const path of GENERATED_PATHS) {
|
|
12
17
|
(0, node_fs_1.rmSync)((0, node_path_1.join)(opts.root, path), { recursive: true, force: true });
|
|
13
18
|
}
|
|
19
|
+
for (const entry of (0, node_fs_1.readdirSync)(opts.root, { withFileTypes: true })) {
|
|
20
|
+
if (entry.isFile() && entry.name.endsWith(BUILD_INFO_SUFFIX)) {
|
|
21
|
+
(0, node_fs_1.rmSync)((0, node_path_1.join)(opts.root, entry.name), { force: true });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
14
24
|
return 0;
|
|
15
25
|
}
|
|
16
26
|
}
|
package/dist/cli/clean.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clean.js","sourceRoot":"","sources":["../../src/cli/clean.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"clean.js","sourceRoot":"","sources":["../../src/cli/clean.ts"],"names":[],"mappings":";;;AAAA,qCAA8C;AAC9C,yCAAiC;AAEjC,0EAA0E;AAC1E,MAAM,eAAe,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;AAExD;;;GAGG;AACH,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAEzC,sFAAsF;AACtF,MAAa,YAAY;IACvB,MAAM,CAAC,GAAG,CAAC,IAAsB;QAC/B,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;YACnC,IAAA,gBAAM,EAAC,IAAA,gBAAI,EAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,IAAA,qBAAW,EAAC,IAAI,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACpE,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC;gBAC7D,IAAA,gBAAM,EAAC,IAAA,gBAAI,EAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACvD,CAAC;QACH,CAAC;QAED,OAAO,CAAC,CAAC;IACX,CAAC;CACF;AAdD,oCAcC","sourcesContent":["import { readdirSync, rmSync } from 'node:fs';\nimport { join } from 'node:path';\n\n/** What a build and the checks generate, relative to the project root. */\nconst GENERATED_PATHS = ['dist', 'node_modules/.cache'];\n\n/**\n * `incremental` is on in the base tsconfig, so a type-check that emits nothing leaves\n * `<tsconfig name>.tsbuildinfo` next to the tsconfig. One inside `dist` is already removed with it.\n */\nconst BUILD_INFO_SUFFIX = '.tsbuildinfo';\n\n/** `devz clean`: removes what the build and the checks generate, and nothing else. */\nexport class CleanCommand {\n static run(opts: { root: string }): number {\n for (const path of GENERATED_PATHS) {\n rmSync(join(opts.root, path), { recursive: true, force: true });\n }\n\n for (const entry of readdirSync(opts.root, { withFileTypes: true })) {\n if (entry.isFile() && entry.name.endsWith(BUILD_INFO_SUFFIX)) {\n rmSync(join(opts.root, entry.name), { force: true });\n }\n }\n\n return 0;\n }\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `devz codemod model-settings [paths...] [--check]`: moves `@model` settings from the flat keys
|
|
3
|
+
* (`defaultFilter`, `defaultLimit`, `maxLimit`, `scopeFilter`) to `query` and `access`. Without
|
|
4
|
+
* `--check` it writes the files; with it, it only lists what would change and exits 1 when
|
|
5
|
+
* anything would.
|
|
6
|
+
*/
|
|
7
|
+
export declare class CodemodCommand {
|
|
8
|
+
static run(opts: {
|
|
9
|
+
root: string;
|
|
10
|
+
args: string[];
|
|
11
|
+
}): Promise<number>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/codemod/index.ts"],"names":[],"mappings":"AAkCA;;;;;GAKG;AACH,qBAAa,cAAc;WACZ,GAAG,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC;CA4D1E"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CodemodCommand = void 0;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const model_settings_1 = require("./model-settings");
|
|
7
|
+
const SKIPPED_DIRECTORIES = new Set(['node_modules', 'dist', 'build', '.git']);
|
|
8
|
+
const SOURCE_PATTERN = /\.(?:ts|tsx|mts|cts)$/;
|
|
9
|
+
const USAGE = 'Usage: devz codemod model-settings [paths...] [--check]';
|
|
10
|
+
/** Every source file under `target`: the file itself, or the `.ts` files below a directory. */
|
|
11
|
+
const collectFiles = (target) => {
|
|
12
|
+
const stats = (0, node_fs_1.statSync)(target);
|
|
13
|
+
if (stats.isFile()) {
|
|
14
|
+
return [target];
|
|
15
|
+
}
|
|
16
|
+
const files = [];
|
|
17
|
+
for (const entry of (0, node_fs_1.readdirSync)(target, { withFileTypes: true })) {
|
|
18
|
+
if (entry.isDirectory()) {
|
|
19
|
+
if (!SKIPPED_DIRECTORIES.has(entry.name)) {
|
|
20
|
+
files.push(...collectFiles((0, node_path_1.join)(target, entry.name)));
|
|
21
|
+
}
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (SOURCE_PATTERN.test(entry.name) && !entry.name.endsWith('.d.ts')) {
|
|
25
|
+
files.push((0, node_path_1.join)(target, entry.name));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return files;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* `devz codemod model-settings [paths...] [--check]`: moves `@model` settings from the flat keys
|
|
32
|
+
* (`defaultFilter`, `defaultLimit`, `maxLimit`, `scopeFilter`) to `query` and `access`. Without
|
|
33
|
+
* `--check` it writes the files; with it, it only lists what would change and exits 1 when
|
|
34
|
+
* anything would.
|
|
35
|
+
*/
|
|
36
|
+
class CodemodCommand {
|
|
37
|
+
static async run(opts) {
|
|
38
|
+
const [name, ...rest] = opts.args;
|
|
39
|
+
if (name !== 'model-settings') {
|
|
40
|
+
console.error(`devz codemod: unknown codemod "${name ?? ''}"\n${USAGE}`);
|
|
41
|
+
return 1;
|
|
42
|
+
}
|
|
43
|
+
const isCheck = rest.includes('--check');
|
|
44
|
+
const paths = rest.filter((argument) => !argument.startsWith('--'));
|
|
45
|
+
const targets = (paths.length > 0 ? paths : ['.']).map((path) => (0, node_path_1.resolve)(opts.root, path));
|
|
46
|
+
let typescript;
|
|
47
|
+
try {
|
|
48
|
+
typescript = (await import('typescript')).default;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
console.error('devz codemod: the "typescript" package is required to read your sources');
|
|
52
|
+
return 1;
|
|
53
|
+
}
|
|
54
|
+
let changedCount = 0;
|
|
55
|
+
let reportCount = 0;
|
|
56
|
+
for (const target of targets) {
|
|
57
|
+
for (const file of collectFiles(target)) {
|
|
58
|
+
const source = (0, node_fs_1.readFileSync)(file, 'utf8');
|
|
59
|
+
if (!source.includes('@model')) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const result = (0, model_settings_1.migrateModelSettings)({ typescript, fileName: file, source });
|
|
63
|
+
const shown = (0, node_path_1.relative)(opts.root, file) || file;
|
|
64
|
+
for (const report of result.reports) {
|
|
65
|
+
reportCount += 1;
|
|
66
|
+
console.warn(`${shown}:${report.line}:${report.column} ${report.reason}`);
|
|
67
|
+
}
|
|
68
|
+
if (!result.changed) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
changedCount += 1;
|
|
72
|
+
console.log(`${isCheck ? 'would change' : 'changed'} ${shown} (${result.rewritten} model(s))`);
|
|
73
|
+
if (!isCheck) {
|
|
74
|
+
(0, node_fs_1.writeFileSync)(file, result.output);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
console.log(`devz codemod model-settings: ${changedCount} file(s) ${isCheck ? 'would change' : 'changed'}, ${reportCount} left untouched`);
|
|
79
|
+
return isCheck && changedCount > 0 ? 1 : 0;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
exports.CodemodCommand = CodemodCommand;
|
|
83
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/codemod/index.ts"],"names":[],"mappings":";;;AAAA,qCAA6E;AAC7E,yCAAoD;AACpD,qDAAwD;AAExD,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AAC/E,MAAM,cAAc,GAAG,uBAAuB,CAAC;AAE/C,MAAM,KAAK,GAAG,yDAAyD,CAAC;AAExE,+FAA+F;AAC/F,MAAM,YAAY,GAAG,CAAC,MAAc,EAAY,EAAE;IAChD,MAAM,KAAK,GAAG,IAAA,kBAAQ,EAAC,MAAM,CAAC,CAAC;IAE/B,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;QACnB,OAAO,CAAC,MAAM,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,IAAA,qBAAW,EAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACjE,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzC,KAAK,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,IAAA,gBAAI,EAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACxD,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YACrE,KAAK,CAAC,IAAI,CAAC,IAAA,gBAAI,EAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAa,cAAc;IACzB,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,IAAsC;QACrD,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;QAElC,IAAI,IAAI,KAAK,gBAAgB,EAAE,CAAC;YAC9B,OAAO,CAAC,KAAK,CAAC,kCAAkC,IAAI,IAAI,EAAE,MAAM,KAAK,EAAE,CAAC,CAAC;YACzE,OAAO,CAAC,CAAC;QACX,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QACpE,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAA,mBAAO,EAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;QAE3F,IAAI,UAAuC,CAAC;QAC5C,IAAI,CAAC;YACH,UAAU,GAAG,CAAC,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC;QACpD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,KAAK,CAAC,yEAAyE,CAAC,CAAC;YACzF,OAAO,CAAC,CAAC;QACX,CAAC;QAED,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,WAAW,GAAG,CAAC,CAAC;QAEpB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC;gBACxC,MAAM,MAAM,GAAG,IAAA,sBAAY,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBAE1C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC/B,SAAS;gBACX,CAAC;gBAED,MAAM,MAAM,GAAG,IAAA,qCAAoB,EAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;gBAC5E,MAAM,KAAK,GAAG,IAAA,oBAAQ,EAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC;gBAEhD,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;oBACpC,WAAW,IAAI,CAAC,CAAC;oBACjB,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,IAAI,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;gBAC7E,CAAC;gBAED,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;oBACpB,SAAS;gBACX,CAAC;gBAED,YAAY,IAAI,CAAC,CAAC;gBAClB,OAAO,CAAC,GAAG,CACT,GAAG,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,KAAK,KAAK,MAAM,MAAM,CAAC,SAAS,YAAY,CACpF,CAAC;gBAEF,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,IAAA,uBAAa,EAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;gBACrC,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,CAAC,GAAG,CACT,gCAAgC,YAAY,YAAY,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,KAAK,WAAW,iBAAiB,CAC9H,CAAC;QAEF,OAAO,OAAO,IAAI,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;CACF;AA7DD,wCA6DC","sourcesContent":["import { readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';\nimport { join, relative, resolve } from 'node:path';\nimport { migrateModelSettings } from './model-settings';\n\nconst SKIPPED_DIRECTORIES = new Set(['node_modules', 'dist', 'build', '.git']);\nconst SOURCE_PATTERN = /\\.(?:ts|tsx|mts|cts)$/;\n\nconst USAGE = 'Usage: devz codemod model-settings [paths...] [--check]';\n\n/** Every source file under `target`: the file itself, or the `.ts` files below a directory. */\nconst collectFiles = (target: string): string[] => {\n const stats = statSync(target);\n\n if (stats.isFile()) {\n return [target];\n }\n\n const files: string[] = [];\n for (const entry of readdirSync(target, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n if (!SKIPPED_DIRECTORIES.has(entry.name)) {\n files.push(...collectFiles(join(target, entry.name)));\n }\n continue;\n }\n\n if (SOURCE_PATTERN.test(entry.name) && !entry.name.endsWith('.d.ts')) {\n files.push(join(target, entry.name));\n }\n }\n\n return files;\n};\n\n/**\n * `devz codemod model-settings [paths...] [--check]`: moves `@model` settings from the flat keys\n * (`defaultFilter`, `defaultLimit`, `maxLimit`, `scopeFilter`) to `query` and `access`. Without\n * `--check` it writes the files; with it, it only lists what would change and exits 1 when\n * anything would.\n */\nexport class CodemodCommand {\n static async run(opts: { root: string; args: string[] }): Promise<number> {\n const [name, ...rest] = opts.args;\n\n if (name !== 'model-settings') {\n console.error(`devz codemod: unknown codemod \"${name ?? ''}\"\\n${USAGE}`);\n return 1;\n }\n\n const isCheck = rest.includes('--check');\n const paths = rest.filter((argument) => !argument.startsWith('--'));\n const targets = (paths.length > 0 ? paths : ['.']).map((path) => resolve(opts.root, path));\n\n let typescript: typeof import('typescript');\n try {\n typescript = (await import('typescript')).default;\n } catch {\n console.error('devz codemod: the \"typescript\" package is required to read your sources');\n return 1;\n }\n\n let changedCount = 0;\n let reportCount = 0;\n\n for (const target of targets) {\n for (const file of collectFiles(target)) {\n const source = readFileSync(file, 'utf8');\n\n if (!source.includes('@model')) {\n continue;\n }\n\n const result = migrateModelSettings({ typescript, fileName: file, source });\n const shown = relative(opts.root, file) || file;\n\n for (const report of result.reports) {\n reportCount += 1;\n console.warn(`${shown}:${report.line}:${report.column} ${report.reason}`);\n }\n\n if (!result.changed) {\n continue;\n }\n\n changedCount += 1;\n console.log(\n `${isCheck ? 'would change' : 'changed'} ${shown} (${result.rewritten} model(s))`,\n );\n\n if (!isCheck) {\n writeFileSync(file, result.output);\n }\n }\n }\n\n console.log(\n `devz codemod model-settings: ${changedCount} file(s) ${isCheck ? 'would change' : 'changed'}, ${reportCount} left untouched`,\n );\n\n return isCheck && changedCount > 0 ? 1 : 0;\n }\n}\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type ts from 'typescript';
|
|
2
|
+
type TTypeScript = typeof ts;
|
|
3
|
+
/** One thing the codemod could not decide and left alone. */
|
|
4
|
+
export interface IModelSettingsReport {
|
|
5
|
+
line: number;
|
|
6
|
+
column: number;
|
|
7
|
+
reason: string;
|
|
8
|
+
}
|
|
9
|
+
export interface IModelSettingsResult {
|
|
10
|
+
/** The source after the migration; equal to the input when nothing changed. */
|
|
11
|
+
output: string;
|
|
12
|
+
changed: boolean;
|
|
13
|
+
/** How many `@model` settings objects were rewritten. */
|
|
14
|
+
rewritten: number;
|
|
15
|
+
reports: IModelSettingsReport[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Rewrites the `settings` object literal of `@model({ ... })` from the flat keys to the grouped ones:
|
|
19
|
+
* `defaultFilter` to `query.filter`, `defaultLimit` and `maxLimit` to `query.limit.default` and
|
|
20
|
+
* `query.limit.max`, `scopeFilter` to `access` (`writeGuard` to `write.mode`, `sharedRows` to
|
|
21
|
+
* `write.sharedRows`).
|
|
22
|
+
*
|
|
23
|
+
* It edits by source range, so comments and formatting outside the rewritten properties stay. It
|
|
24
|
+
* never guesses: a `settings` value that is not an object literal, a spread, a computed key, or a
|
|
25
|
+
* `scopeFilter` that is not an object literal is reported and the model is left untouched.
|
|
26
|
+
*/
|
|
27
|
+
export declare const migrateModelSettings: (opts: {
|
|
28
|
+
typescript: TTypeScript;
|
|
29
|
+
fileName: string;
|
|
30
|
+
source: string;
|
|
31
|
+
}) => IModelSettingsResult;
|
|
32
|
+
export {};
|
|
33
|
+
//# sourceMappingURL=model-settings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-settings.d.ts","sourceRoot":"","sources":["../../../src/cli/codemod/model-settings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC,KAAK,WAAW,GAAG,OAAO,EAAE,CAAC;AAE7B,6DAA6D;AAC7D,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,yDAAyD;IACzD,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,oBAAoB,EAAE,CAAC;CACjC;AAWD;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,GAAI,MAAM;IACzC,UAAU,EAAE,WAAW,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB,KAAG,oBA+UH,CAAC"}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.migrateModelSettings = void 0;
|
|
4
|
+
const QUERY_KEYS = { defaultFilter: 'filter', defaultLimit: 'default', maxLimit: 'max' };
|
|
5
|
+
const OLD_KEYS = new Set([...Object.keys(QUERY_KEYS), 'scopeFilter']);
|
|
6
|
+
/**
|
|
7
|
+
* Rewrites the `settings` object literal of `@model({ ... })` from the flat keys to the grouped ones:
|
|
8
|
+
* `defaultFilter` to `query.filter`, `defaultLimit` and `maxLimit` to `query.limit.default` and
|
|
9
|
+
* `query.limit.max`, `scopeFilter` to `access` (`writeGuard` to `write.mode`, `sharedRows` to
|
|
10
|
+
* `write.sharedRows`).
|
|
11
|
+
*
|
|
12
|
+
* It edits by source range, so comments and formatting outside the rewritten properties stay. It
|
|
13
|
+
* never guesses: a `settings` value that is not an object literal, a spread, a computed key, or a
|
|
14
|
+
* `scopeFilter` that is not an object literal is reported and the model is left untouched.
|
|
15
|
+
*/
|
|
16
|
+
const migrateModelSettings = (opts) => {
|
|
17
|
+
const { typescript, fileName, source } = opts;
|
|
18
|
+
const sourceFile = typescript.createSourceFile(fileName, source, typescript.ScriptTarget.Latest, true);
|
|
19
|
+
const edits = [];
|
|
20
|
+
const reports = [];
|
|
21
|
+
let rewritten = 0;
|
|
22
|
+
const report = (node, reason) => {
|
|
23
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
24
|
+
reports.push({ line: line + 1, column: character + 1, reason });
|
|
25
|
+
};
|
|
26
|
+
const nameOf = (property) => {
|
|
27
|
+
if (!typescript.isPropertyAssignment(property) &&
|
|
28
|
+
!typescript.isShorthandPropertyAssignment(property)) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
const { name } = property;
|
|
32
|
+
if (typescript.isIdentifier(name) || typescript.isStringLiteral(name)) {
|
|
33
|
+
return name.text;
|
|
34
|
+
}
|
|
35
|
+
return undefined;
|
|
36
|
+
};
|
|
37
|
+
const text = (node) => source.slice(node.getStart(sourceFile), node.end);
|
|
38
|
+
/**
|
|
39
|
+
* The leading trivia of `first` (its own comments and indentation) followed by the comments that
|
|
40
|
+
* were above the properties being merged into it, so no comment is dropped.
|
|
41
|
+
*/
|
|
42
|
+
const composeLeading = (first, merged) => {
|
|
43
|
+
const trivia = source.slice(first.getFullStart(), first.getStart(sourceFile));
|
|
44
|
+
const indent = /[ \t]*$/.exec(trivia)?.[0] ?? '';
|
|
45
|
+
const extra = merged
|
|
46
|
+
.flatMap((node) => typescript.getLeadingCommentRanges(source, node.getFullStart()) ?? [])
|
|
47
|
+
.map((range) => `${source.slice(range.pos, range.end)}\n${indent}`)
|
|
48
|
+
.join('');
|
|
49
|
+
return trivia + extra;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Removes a property with the comma after it; the last property has none, so the comma before it
|
|
53
|
+
* goes instead, leaving no dangling `, }`.
|
|
54
|
+
*/
|
|
55
|
+
const removal = (node) => {
|
|
56
|
+
const after = /^\s*,/.exec(source.slice(node.end));
|
|
57
|
+
if (after) {
|
|
58
|
+
return { start: node.getFullStart(), end: node.end + after[0].length, text: '' };
|
|
59
|
+
}
|
|
60
|
+
const before = /,\s*$/.exec(source.slice(0, node.getFullStart()));
|
|
61
|
+
const start = before ? node.getFullStart() - before[0].length : node.getFullStart();
|
|
62
|
+
return { start, end: node.end, text: '' };
|
|
63
|
+
};
|
|
64
|
+
/** Appends members to an object literal: after its last member, or inside empty braces. */
|
|
65
|
+
const append = (object, members) => {
|
|
66
|
+
const last = object.properties[object.properties.length - 1];
|
|
67
|
+
if (last) {
|
|
68
|
+
return { start: last.end, end: last.end, text: `, ${members.join(', ')}` };
|
|
69
|
+
}
|
|
70
|
+
const at = object.getStart(sourceFile) + 1;
|
|
71
|
+
return { start: at, end: at, text: ` ${members.join(', ')} ` };
|
|
72
|
+
};
|
|
73
|
+
const migrateSettings = (settings) => {
|
|
74
|
+
const properties = [...settings.properties];
|
|
75
|
+
const old = new Map();
|
|
76
|
+
let existingQuery;
|
|
77
|
+
for (const property of properties) {
|
|
78
|
+
if (typescript.isSpreadAssignment(property)) {
|
|
79
|
+
// A spread can carry old keys we cannot see.
|
|
80
|
+
report(property, 'settings contains a spread, so its keys are unknown; left untouched');
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (typescript.isMethodDeclaration(property)) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const name = nameOf(property);
|
|
87
|
+
if (name === undefined) {
|
|
88
|
+
report(property, 'settings contains a computed key; left untouched');
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (OLD_KEYS.has(name)) {
|
|
92
|
+
if (!typescript.isPropertyAssignment(property)) {
|
|
93
|
+
report(property, `settings.${name} is a shorthand property; left untouched`);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
old.set(name, property);
|
|
97
|
+
}
|
|
98
|
+
if (name === 'query' && typescript.isPropertyAssignment(property)) {
|
|
99
|
+
existingQuery = property;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (old.size === 0) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const queryOld = [...old.keys()].filter((key) => key in QUERY_KEYS);
|
|
106
|
+
const localEdits = [];
|
|
107
|
+
// ---- scopeFilter -> access (rename the key, rewrite writeGuard / sharedRows inside)
|
|
108
|
+
const scopeFilter = old.get('scopeFilter');
|
|
109
|
+
if (scopeFilter) {
|
|
110
|
+
if (!typescript.isObjectLiteralExpression(scopeFilter.initializer)) {
|
|
111
|
+
report(scopeFilter, 'settings.scopeFilter is not an object literal; left untouched');
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const inner = scopeFilter.initializer;
|
|
115
|
+
const guard = inner.properties.find((property) => nameOf(property) === 'writeGuard' && typescript.isPropertyAssignment(property));
|
|
116
|
+
const shared = inner.properties.find((property) => nameOf(property) === 'sharedRows' && typescript.isPropertyAssignment(property));
|
|
117
|
+
const hasSpread = inner.properties.some((property) => typescript.isSpreadAssignment(property));
|
|
118
|
+
if (hasSpread) {
|
|
119
|
+
report(scopeFilter, 'settings.scopeFilter contains a spread; left untouched');
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (inner.properties.some((property) => nameOf(property) === 'write')) {
|
|
123
|
+
report(scopeFilter, 'settings.scopeFilter already has a write key; left untouched');
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
localEdits.push({
|
|
127
|
+
start: scopeFilter.name.getStart(sourceFile),
|
|
128
|
+
end: scopeFilter.name.end,
|
|
129
|
+
text: 'access',
|
|
130
|
+
});
|
|
131
|
+
if (guard || shared) {
|
|
132
|
+
const members = [
|
|
133
|
+
guard ? `mode: ${text(guard.initializer)}` : undefined,
|
|
134
|
+
shared ? `sharedRows: ${text(shared.initializer)}` : undefined,
|
|
135
|
+
].filter((member) => member !== undefined);
|
|
136
|
+
const ordered = [guard, shared]
|
|
137
|
+
.filter((property) => property !== undefined)
|
|
138
|
+
.sort((a, b) => a.getStart(sourceFile) - b.getStart(sourceFile));
|
|
139
|
+
const [first, ...merged] = ordered;
|
|
140
|
+
localEdits.push({
|
|
141
|
+
start: first.getFullStart(),
|
|
142
|
+
end: first.end,
|
|
143
|
+
text: `${composeLeading(first, merged)}write: { ${members.join(', ')} }`,
|
|
144
|
+
});
|
|
145
|
+
for (const second of merged) {
|
|
146
|
+
localEdits.push(removal(second));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// ---- defaultFilter / defaultLimit / maxLimit -> query
|
|
151
|
+
if (queryOld.length > 0) {
|
|
152
|
+
const filter = old.get('defaultFilter');
|
|
153
|
+
const defaultLimit = old.get('defaultLimit');
|
|
154
|
+
const maxLimit = old.get('maxLimit');
|
|
155
|
+
if (existingQuery) {
|
|
156
|
+
if (!typescript.isObjectLiteralExpression(existingQuery.initializer)) {
|
|
157
|
+
report(existingQuery, 'settings.query is not an object literal; left untouched');
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
const queryObject = existingQuery.initializer;
|
|
161
|
+
const queryKeys = new Set(queryObject.properties.map((property) => nameOf(property)));
|
|
162
|
+
const existingLimit = queryObject.properties.find((property) => nameOf(property) === 'limit');
|
|
163
|
+
if (filter && queryKeys.has('filter')) {
|
|
164
|
+
report(filter, 'settings.defaultFilter and settings.query.filter are both set; left untouched');
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if ((defaultLimit || maxLimit) && existingLimit) {
|
|
168
|
+
if (!typescript.isObjectLiteralExpression(existingLimit.initializer)) {
|
|
169
|
+
report(existingLimit, 'settings.query.limit is not an object literal; left untouched');
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const limitKeys = new Set(existingLimit.initializer.properties.map((property) => nameOf(property)));
|
|
173
|
+
if ((defaultLimit && limitKeys.has('default')) || (maxLimit && limitKeys.has('max'))) {
|
|
174
|
+
report(existingLimit, 'an old limit key and its new key are both set; left untouched');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
const additions = [];
|
|
179
|
+
if (filter) {
|
|
180
|
+
additions.push(`filter: ${text(filter.initializer)}`);
|
|
181
|
+
}
|
|
182
|
+
const limitMembers = [
|
|
183
|
+
defaultLimit ? `default: ${text(defaultLimit.initializer)}` : undefined,
|
|
184
|
+
maxLimit ? `max: ${text(maxLimit.initializer)}` : undefined,
|
|
185
|
+
].filter((member) => member !== undefined);
|
|
186
|
+
if (limitMembers.length > 0 && existingLimit) {
|
|
187
|
+
localEdits.push(append(existingLimit.initializer, limitMembers));
|
|
188
|
+
}
|
|
189
|
+
else if (limitMembers.length > 0) {
|
|
190
|
+
additions.push(`limit: { ${limitMembers.join(', ')} }`);
|
|
191
|
+
}
|
|
192
|
+
if (additions.length > 0) {
|
|
193
|
+
localEdits.push(append(queryObject, additions));
|
|
194
|
+
}
|
|
195
|
+
for (const key of queryOld) {
|
|
196
|
+
const property = old.get(key);
|
|
197
|
+
localEdits.push(removal(property));
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
const members = [];
|
|
202
|
+
if (filter) {
|
|
203
|
+
members.push(`filter: ${text(filter.initializer)}`);
|
|
204
|
+
}
|
|
205
|
+
const limitMembers = [
|
|
206
|
+
defaultLimit ? `default: ${text(defaultLimit.initializer)}` : undefined,
|
|
207
|
+
maxLimit ? `max: ${text(maxLimit.initializer)}` : undefined,
|
|
208
|
+
].filter((member) => member !== undefined);
|
|
209
|
+
if (limitMembers.length > 0) {
|
|
210
|
+
members.push(`limit: { ${limitMembers.join(', ')} }`);
|
|
211
|
+
}
|
|
212
|
+
const ordered = queryOld
|
|
213
|
+
.map((key) => old.get(key))
|
|
214
|
+
.sort((a, b) => a.getStart(sourceFile) - b.getStart(sourceFile));
|
|
215
|
+
const [first, ...others] = ordered;
|
|
216
|
+
localEdits.push({
|
|
217
|
+
start: first.getFullStart(),
|
|
218
|
+
end: first.end,
|
|
219
|
+
text: `${composeLeading(first, others)}query: { ${members.join(', ')} }`,
|
|
220
|
+
});
|
|
221
|
+
for (const other of others) {
|
|
222
|
+
localEdits.push(removal(other));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
edits.push(...localEdits);
|
|
227
|
+
rewritten += 1;
|
|
228
|
+
};
|
|
229
|
+
const visit = (node) => {
|
|
230
|
+
if (typescript.isDecorator(node) &&
|
|
231
|
+
typescript.isCallExpression(node.expression) &&
|
|
232
|
+
typescript.isIdentifier(node.expression.expression) &&
|
|
233
|
+
node.expression.expression.text === 'model') {
|
|
234
|
+
const argument = node.expression.arguments[0];
|
|
235
|
+
if (argument && typescript.isObjectLiteralExpression(argument)) {
|
|
236
|
+
const settingsProperty = argument.properties.find((property) => nameOf(property) === 'settings');
|
|
237
|
+
if (settingsProperty) {
|
|
238
|
+
if (typescript.isPropertyAssignment(settingsProperty) &&
|
|
239
|
+
typescript.isObjectLiteralExpression(settingsProperty.initializer)) {
|
|
240
|
+
migrateSettings(settingsProperty.initializer);
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
report(settingsProperty, 'settings is not an object literal (a variable, a call or a shorthand); left untouched');
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
typescript.forEachChild(node, visit);
|
|
249
|
+
};
|
|
250
|
+
visit(sourceFile);
|
|
251
|
+
// Neighbouring removals can touch the same comma: merge those, then apply from the end so
|
|
252
|
+
// earlier offsets stay valid.
|
|
253
|
+
const ascending = [...edits].sort((a, b) => a.start - b.start || a.end - b.end);
|
|
254
|
+
const merged = [];
|
|
255
|
+
for (const edit of ascending) {
|
|
256
|
+
const previous = merged[merged.length - 1];
|
|
257
|
+
if (previous && edit.start < previous.end && previous.text === '' && edit.text === '') {
|
|
258
|
+
previous.end = Math.max(previous.end, edit.end);
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
merged.push({ ...edit });
|
|
262
|
+
}
|
|
263
|
+
let output = source;
|
|
264
|
+
for (const edit of merged.reverse()) {
|
|
265
|
+
output = output.slice(0, edit.start) + edit.text + output.slice(edit.end);
|
|
266
|
+
}
|
|
267
|
+
return { output, changed: output !== source, rewritten, reports };
|
|
268
|
+
};
|
|
269
|
+
exports.migrateModelSettings = migrateModelSettings;
|
|
270
|
+
//# sourceMappingURL=model-settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-settings.js","sourceRoot":"","sources":["../../../src/cli/codemod/model-settings.ts"],"names":[],"mappings":"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","sourcesContent":["import type ts from 'typescript';\n\ntype TTypeScript = typeof ts;\n\n/** One thing the codemod could not decide and left alone. */\nexport interface IModelSettingsReport {\n line: number;\n column: number;\n reason: string;\n}\n\nexport interface IModelSettingsResult {\n /** The source after the migration; equal to the input when nothing changed. */\n output: string;\n changed: boolean;\n /** How many `@model` settings objects were rewritten. */\n rewritten: number;\n reports: IModelSettingsReport[];\n}\n\ninterface IEdit {\n start: number;\n end: number;\n text: string;\n}\n\nconst QUERY_KEYS = { defaultFilter: 'filter', defaultLimit: 'default', maxLimit: 'max' } as const;\nconst OLD_KEYS = new Set<string>([...Object.keys(QUERY_KEYS), 'scopeFilter']);\n\n/**\n * Rewrites the `settings` object literal of `@model({ ... })` from the flat keys to the grouped ones:\n * `defaultFilter` to `query.filter`, `defaultLimit` and `maxLimit` to `query.limit.default` and\n * `query.limit.max`, `scopeFilter` to `access` (`writeGuard` to `write.mode`, `sharedRows` to\n * `write.sharedRows`).\n *\n * It edits by source range, so comments and formatting outside the rewritten properties stay. It\n * never guesses: a `settings` value that is not an object literal, a spread, a computed key, or a\n * `scopeFilter` that is not an object literal is reported and the model is left untouched.\n */\nexport const migrateModelSettings = (opts: {\n typescript: TTypeScript;\n fileName: string;\n source: string;\n}): IModelSettingsResult => {\n const { typescript, fileName, source } = opts;\n const sourceFile = typescript.createSourceFile(\n fileName,\n source,\n typescript.ScriptTarget.Latest,\n true,\n );\n const edits: IEdit[] = [];\n const reports: IModelSettingsReport[] = [];\n let rewritten = 0;\n\n const report = (node: ts.Node, reason: string) => {\n const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));\n reports.push({ line: line + 1, column: character + 1, reason });\n };\n\n const nameOf = (property: ts.ObjectLiteralElementLike): string | undefined => {\n if (\n !typescript.isPropertyAssignment(property) &&\n !typescript.isShorthandPropertyAssignment(property)\n ) {\n return undefined;\n }\n\n const { name } = property;\n if (typescript.isIdentifier(name) || typescript.isStringLiteral(name)) {\n return name.text;\n }\n\n return undefined;\n };\n\n const text = (node: ts.Node) => source.slice(node.getStart(sourceFile), node.end);\n\n /**\n * The leading trivia of `first` (its own comments and indentation) followed by the comments that\n * were above the properties being merged into it, so no comment is dropped.\n */\n const composeLeading = (first: ts.Node, merged: ts.Node[]): string => {\n const trivia = source.slice(first.getFullStart(), first.getStart(sourceFile));\n const indent = /[ \\t]*$/.exec(trivia)?.[0] ?? '';\n const extra = merged\n .flatMap((node) => typescript.getLeadingCommentRanges(source, node.getFullStart()) ?? [])\n .map((range) => `${source.slice(range.pos, range.end)}\\n${indent}`)\n .join('');\n\n return trivia + extra;\n };\n\n /**\n * Removes a property with the comma after it; the last property has none, so the comma before it\n * goes instead, leaving no dangling `, }`.\n */\n const removal = (node: ts.Node): IEdit => {\n const after = /^\\s*,/.exec(source.slice(node.end));\n if (after) {\n return { start: node.getFullStart(), end: node.end + after[0].length, text: '' };\n }\n\n const before = /,\\s*$/.exec(source.slice(0, node.getFullStart()));\n const start = before ? node.getFullStart() - before[0].length : node.getFullStart();\n\n return { start, end: node.end, text: '' };\n };\n\n /** Appends members to an object literal: after its last member, or inside empty braces. */\n const append = (object: ts.ObjectLiteralExpression, members: string[]): IEdit => {\n const last = object.properties[object.properties.length - 1];\n if (last) {\n return { start: last.end, end: last.end, text: `, ${members.join(', ')}` };\n }\n\n const at = object.getStart(sourceFile) + 1;\n return { start: at, end: at, text: ` ${members.join(', ')} ` };\n };\n\n const migrateSettings = (settings: ts.ObjectLiteralExpression) => {\n const properties = [...settings.properties];\n const old = new Map<string, ts.PropertyAssignment>();\n let existingQuery: ts.PropertyAssignment | undefined;\n\n for (const property of properties) {\n if (typescript.isSpreadAssignment(property)) {\n // A spread can carry old keys we cannot see.\n report(property, 'settings contains a spread, so its keys are unknown; left untouched');\n return;\n }\n\n if (typescript.isMethodDeclaration(property)) {\n continue;\n }\n\n const name = nameOf(property);\n if (name === undefined) {\n report(property, 'settings contains a computed key; left untouched');\n return;\n }\n\n if (OLD_KEYS.has(name)) {\n if (!typescript.isPropertyAssignment(property)) {\n report(property, `settings.${name} is a shorthand property; left untouched`);\n return;\n }\n old.set(name, property);\n }\n\n if (name === 'query' && typescript.isPropertyAssignment(property)) {\n existingQuery = property;\n }\n }\n\n if (old.size === 0) {\n return;\n }\n\n const queryOld = [...old.keys()].filter((key) => key in QUERY_KEYS);\n const localEdits: IEdit[] = [];\n\n // ---- scopeFilter -> access (rename the key, rewrite writeGuard / sharedRows inside)\n const scopeFilter = old.get('scopeFilter');\n if (scopeFilter) {\n if (!typescript.isObjectLiteralExpression(scopeFilter.initializer)) {\n report(scopeFilter, 'settings.scopeFilter is not an object literal; left untouched');\n return;\n }\n\n const inner = scopeFilter.initializer;\n const guard = inner.properties.find(\n (property) =>\n nameOf(property) === 'writeGuard' && typescript.isPropertyAssignment(property),\n ) as ts.PropertyAssignment | undefined;\n const shared = inner.properties.find(\n (property) =>\n nameOf(property) === 'sharedRows' && typescript.isPropertyAssignment(property),\n ) as ts.PropertyAssignment | undefined;\n const hasSpread = inner.properties.some((property) =>\n typescript.isSpreadAssignment(property),\n );\n\n if (hasSpread) {\n report(scopeFilter, 'settings.scopeFilter contains a spread; left untouched');\n return;\n }\n\n if (inner.properties.some((property) => nameOf(property) === 'write')) {\n report(scopeFilter, 'settings.scopeFilter already has a write key; left untouched');\n return;\n }\n\n localEdits.push({\n start: scopeFilter.name.getStart(sourceFile),\n end: scopeFilter.name.end,\n text: 'access',\n });\n\n if (guard || shared) {\n const members = [\n guard ? `mode: ${text(guard.initializer)}` : undefined,\n shared ? `sharedRows: ${text(shared.initializer)}` : undefined,\n ].filter((member): member is string => member !== undefined);\n const ordered = [guard, shared]\n .filter((property): property is ts.PropertyAssignment => property !== undefined)\n .sort((a, b) => a.getStart(sourceFile) - b.getStart(sourceFile));\n const [first, ...merged] = ordered;\n\n localEdits.push({\n start: first.getFullStart(),\n end: first.end,\n text: `${composeLeading(first, merged)}write: { ${members.join(', ')} }`,\n });\n\n for (const second of merged) {\n localEdits.push(removal(second));\n }\n }\n }\n\n // ---- defaultFilter / defaultLimit / maxLimit -> query\n if (queryOld.length > 0) {\n const filter = old.get('defaultFilter');\n const defaultLimit = old.get('defaultLimit');\n const maxLimit = old.get('maxLimit');\n\n if (existingQuery) {\n if (!typescript.isObjectLiteralExpression(existingQuery.initializer)) {\n report(existingQuery, 'settings.query is not an object literal; left untouched');\n return;\n }\n\n const queryObject = existingQuery.initializer;\n const queryKeys = new Set(queryObject.properties.map((property) => nameOf(property)));\n const existingLimit = queryObject.properties.find(\n (property) => nameOf(property) === 'limit',\n ) as ts.PropertyAssignment | undefined;\n\n if (filter && queryKeys.has('filter')) {\n report(\n filter,\n 'settings.defaultFilter and settings.query.filter are both set; left untouched',\n );\n return;\n }\n\n if ((defaultLimit || maxLimit) && existingLimit) {\n if (!typescript.isObjectLiteralExpression(existingLimit.initializer)) {\n report(existingLimit, 'settings.query.limit is not an object literal; left untouched');\n return;\n }\n\n const limitKeys = new Set(\n existingLimit.initializer.properties.map((property) => nameOf(property)),\n );\n if ((defaultLimit && limitKeys.has('default')) || (maxLimit && limitKeys.has('max'))) {\n report(existingLimit, 'an old limit key and its new key are both set; left untouched');\n return;\n }\n }\n\n const additions: string[] = [];\n if (filter) {\n additions.push(`filter: ${text(filter.initializer)}`);\n }\n\n const limitMembers = [\n defaultLimit ? `default: ${text(defaultLimit.initializer)}` : undefined,\n maxLimit ? `max: ${text(maxLimit.initializer)}` : undefined,\n ].filter((member): member is string => member !== undefined);\n\n if (limitMembers.length > 0 && existingLimit) {\n localEdits.push(\n append(existingLimit.initializer as ts.ObjectLiteralExpression, limitMembers),\n );\n } else if (limitMembers.length > 0) {\n additions.push(`limit: { ${limitMembers.join(', ')} }`);\n }\n\n if (additions.length > 0) {\n localEdits.push(append(queryObject, additions));\n }\n\n for (const key of queryOld) {\n const property = old.get(key) as ts.PropertyAssignment;\n localEdits.push(removal(property));\n }\n } else {\n const members: string[] = [];\n if (filter) {\n members.push(`filter: ${text(filter.initializer)}`);\n }\n\n const limitMembers = [\n defaultLimit ? `default: ${text(defaultLimit.initializer)}` : undefined,\n maxLimit ? `max: ${text(maxLimit.initializer)}` : undefined,\n ].filter((member): member is string => member !== undefined);\n if (limitMembers.length > 0) {\n members.push(`limit: { ${limitMembers.join(', ')} }`);\n }\n\n const ordered = queryOld\n .map((key) => old.get(key) as ts.PropertyAssignment)\n .sort((a, b) => a.getStart(sourceFile) - b.getStart(sourceFile));\n const [first, ...others] = ordered;\n\n localEdits.push({\n start: first.getFullStart(),\n end: first.end,\n text: `${composeLeading(first, others)}query: { ${members.join(', ')} }`,\n });\n\n for (const other of others) {\n localEdits.push(removal(other));\n }\n }\n }\n\n edits.push(...localEdits);\n rewritten += 1;\n };\n\n const visit = (node: ts.Node) => {\n if (\n typescript.isDecorator(node) &&\n typescript.isCallExpression(node.expression) &&\n typescript.isIdentifier(node.expression.expression) &&\n node.expression.expression.text === 'model'\n ) {\n const argument = node.expression.arguments[0];\n\n if (argument && typescript.isObjectLiteralExpression(argument)) {\n const settingsProperty = argument.properties.find(\n (property) => nameOf(property) === 'settings',\n );\n\n if (settingsProperty) {\n if (\n typescript.isPropertyAssignment(settingsProperty) &&\n typescript.isObjectLiteralExpression(settingsProperty.initializer)\n ) {\n migrateSettings(settingsProperty.initializer);\n } else {\n report(\n settingsProperty,\n 'settings is not an object literal (a variable, a call or a shorthand); left untouched',\n );\n }\n }\n }\n }\n\n typescript.forEachChild(node, visit);\n };\n\n visit(sourceFile);\n\n // Neighbouring removals can touch the same comma: merge those, then apply from the end so\n // earlier offsets stay valid.\n const ascending = [...edits].sort((a, b) => a.start - b.start || a.end - b.end);\n const merged: IEdit[] = [];\n for (const edit of ascending) {\n const previous = merged[merged.length - 1];\n if (previous && edit.start < previous.end && previous.text === '' && edit.text === '') {\n previous.end = Math.max(previous.end, edit.end);\n continue;\n }\n\n merged.push({ ...edit });\n }\n\n let output = source;\n for (const edit of merged.reverse()) {\n output = output.slice(0, edit.start) + edit.text + output.slice(edit.end);\n }\n\n return { output, changed: output !== source, rewritten, reports };\n};\n"]}
|
package/dist/cli/index.js
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
const clean_1 = require("./clean");
|
|
5
|
+
const codemod_1 = require("./codemod");
|
|
5
6
|
const lint_1 = require("./lint");
|
|
6
|
-
const USAGE = 'Usage: devz lint [--fix] [files] | devz clean';
|
|
7
|
+
const USAGE = 'Usage: devz lint [--fix] [files] | devz clean | devz codemod model-settings [paths...] [--check]';
|
|
7
8
|
const main = async (opts) => {
|
|
8
9
|
const [command, ...args] = opts.argv;
|
|
9
10
|
if (command === 'lint') {
|
|
@@ -12,6 +13,9 @@ const main = async (opts) => {
|
|
|
12
13
|
if (command === 'clean') {
|
|
13
14
|
return clean_1.CleanCommand.run({ root: process.cwd() });
|
|
14
15
|
}
|
|
16
|
+
if (command === 'codemod') {
|
|
17
|
+
return codemod_1.CodemodCommand.run({ root: process.cwd(), args });
|
|
18
|
+
}
|
|
15
19
|
console.error(`devz: unknown command "${command ?? ''}"\n${USAGE}`);
|
|
16
20
|
return 1;
|
|
17
21
|
};
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;AACA,mCAAuC;AACvC,iCAAqC;AAErC,MAAM,KAAK,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;AACA,mCAAuC;AACvC,uCAA2C;AAC3C,iCAAqC;AAErC,MAAM,KAAK,GACT,kGAAkG,CAAC;AAErG,MAAM,IAAI,GAAG,KAAK,EAAE,IAAwB,EAAmB,EAAE;IAC/D,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC;IAErC,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QACvB,OAAO,kBAAW,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACxB,OAAO,oBAAY,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,wBAAc,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,0BAA0B,OAAO,IAAI,EAAE,MAAM,KAAK,EAAE,CAAC,CAAC;IACpE,OAAO,CAAC,CAAC;AACX,CAAC,CAAC;AAEF,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CACxC,CAAC,QAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EACpC,CAAC,KAAc,EAAE,EAAE;IACjB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CACF,CAAC","sourcesContent":["#!/usr/bin/env bun\nimport { CleanCommand } from './clean';\nimport { CodemodCommand } from './codemod';\nimport { LintCommand } from './lint';\n\nconst USAGE =\n 'Usage: devz lint [--fix] [files] | devz clean | devz codemod model-settings [paths...] [--check]';\n\nconst main = async (opts: { argv: string[] }): Promise<number> => {\n const [command, ...args] = opts.argv;\n\n if (command === 'lint') {\n return LintCommand.run({ root: process.cwd(), args });\n }\n\n if (command === 'clean') {\n return CleanCommand.run({ root: process.cwd() });\n }\n\n if (command === 'codemod') {\n return CodemodCommand.run({ root: process.cwd(), args });\n }\n\n console.error(`devz: unknown command \"${command ?? ''}\"\\n${USAGE}`);\n return 1;\n};\n\nmain({ argv: process.argv.slice(2) }).then(\n (exitCode) => process.exit(exitCode),\n (error: unknown) => {\n console.error(error);\n process.exit(1);\n },\n);\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@venizia/dev-configs",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "Shareable development configurations for TypeScript projects: oxlint presets with per-rule builders, the ESLint naming-convention rule, the legacy ESLint flat config, and TypeScript compiler options with critical decorator support (experimentalDecorators, emitDecoratorMetadata, useDefineForClassFields). Single source of truth for consistent code style, type checking, and build settings across monorepo packages.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"build-tools",
|