@rexezuge/tooling 0.0.0-stage → 1.0.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/LICENSE +21 -0
- package/README.md +297 -2
- package/dist/eslint.d.ts +120 -0
- package/dist/eslint.d.ts.map +1 -0
- package/dist/eslint.js +551 -0
- package/dist/eslint.js.map +1 -0
- package/dist/functions/pages-proxy.d.ts +113 -0
- package/dist/functions/pages-proxy.d.ts.map +1 -0
- package/dist/functions/pages-proxy.js +131 -0
- package/dist/functions/pages-proxy.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/scripts/backup/d1-target.d.ts +35 -0
- package/dist/scripts/backup/d1-target.d.ts.map +1 -0
- package/dist/scripts/backup/d1-target.js +31 -0
- package/dist/scripts/backup/d1-target.js.map +1 -0
- package/dist/scripts/backup/destination-config.d.ts +61 -0
- package/dist/scripts/backup/destination-config.d.ts.map +1 -0
- package/dist/scripts/backup/destination-config.js +57 -0
- package/dist/scripts/backup/destination-config.js.map +1 -0
- package/dist/scripts/backup/encrypt-backup.d.ts +35 -0
- package/dist/scripts/backup/encrypt-backup.d.ts.map +1 -0
- package/dist/scripts/backup/encrypt-backup.js +98 -0
- package/dist/scripts/backup/encrypt-backup.js.map +1 -0
- package/dist/scripts/backup/naming.d.ts +44 -0
- package/dist/scripts/backup/naming.d.ts.map +1 -0
- package/dist/scripts/backup/naming.js +58 -0
- package/dist/scripts/backup/naming.js.map +1 -0
- package/dist/scripts/check-god-files.d.ts +164 -0
- package/dist/scripts/check-god-files.d.ts.map +1 -0
- package/dist/scripts/check-god-files.js +271 -0
- package/dist/scripts/check-god-files.js.map +1 -0
- package/dist/scripts/ensure-spa-shell-stub.d.ts +3 -0
- package/dist/scripts/ensure-spa-shell-stub.d.ts.map +1 -0
- package/dist/scripts/ensure-spa-shell-stub.js +30 -0
- package/dist/scripts/ensure-spa-shell-stub.js.map +1 -0
- package/dist/scripts/init-secrets.d.ts +63 -0
- package/dist/scripts/init-secrets.d.ts.map +1 -0
- package/dist/scripts/init-secrets.js +240 -0
- package/dist/scripts/init-secrets.js.map +1 -0
- package/dist/scripts/lib/cli-args.d.ts +78 -0
- package/dist/scripts/lib/cli-args.d.ts.map +1 -0
- package/dist/scripts/lib/cli-args.js +116 -0
- package/dist/scripts/lib/cli-args.js.map +1 -0
- package/dist/scripts/lib/github-actions.d.ts +26 -0
- package/dist/scripts/lib/github-actions.d.ts.map +1 -0
- package/dist/scripts/lib/github-actions.js +38 -0
- package/dist/scripts/lib/github-actions.js.map +1 -0
- package/dist/scripts/lib/wrangler-table.d.ts +46 -0
- package/dist/scripts/lib/wrangler-table.d.ts.map +1 -0
- package/dist/scripts/lib/wrangler-table.js +99 -0
- package/dist/scripts/lib/wrangler-table.js.map +1 -0
- package/dist/scripts/migrations-lock.d.ts +3 -0
- package/dist/scripts/migrations-lock.d.ts.map +1 -0
- package/dist/scripts/migrations-lock.js +46 -0
- package/dist/scripts/migrations-lock.js.map +1 -0
- package/dist/scripts/prepare-wrangler-config.d.ts +3 -0
- package/dist/scripts/prepare-wrangler-config.d.ts.map +1 -0
- package/dist/scripts/prepare-wrangler-config.js +50 -0
- package/dist/scripts/prepare-wrangler-config.js.map +1 -0
- package/dist/scripts/spa-shell.d.ts +41 -0
- package/dist/scripts/spa-shell.d.ts.map +1 -0
- package/dist/scripts/spa-shell.js +155 -0
- package/dist/scripts/spa-shell.js.map +1 -0
- package/dist/scripts/validate-locales.d.ts +26 -0
- package/dist/scripts/validate-locales.d.ts.map +1 -0
- package/dist/scripts/validate-locales.js +350 -0
- package/dist/scripts/validate-locales.js.map +1 -0
- package/dist/scripts/verify-migrations.d.ts +62 -0
- package/dist/scripts/verify-migrations.d.ts.map +1 -0
- package/dist/scripts/verify-migrations.js +302 -0
- package/dist/scripts/verify-migrations.js.map +1 -0
- package/dist/scripts/verify-spa-shell.d.ts +3 -0
- package/dist/scripts/verify-spa-shell.d.ts.map +1 -0
- package/dist/scripts/verify-spa-shell.js +53 -0
- package/dist/scripts/verify-spa-shell.js.map +1 -0
- package/dist/scripts/wrangler-config/cli.d.ts +22 -0
- package/dist/scripts/wrangler-config/cli.d.ts.map +1 -0
- package/dist/scripts/wrangler-config/cli.js +51 -0
- package/dist/scripts/wrangler-config/cli.js.map +1 -0
- package/dist/scripts/wrangler-config/patches.d.ts +51 -0
- package/dist/scripts/wrangler-config/patches.d.ts.map +1 -0
- package/dist/scripts/wrangler-config/patches.js +140 -0
- package/dist/scripts/wrangler-config/patches.js.map +1 -0
- package/dist/scripts/wrangler-config/resources.d.ts +70 -0
- package/dist/scripts/wrangler-config/resources.d.ts.map +1 -0
- package/dist/scripts/wrangler-config/resources.js +290 -0
- package/dist/scripts/wrangler-config/resources.js.map +1 -0
- package/dist/scripts/wrangler-config/types.d.ts +103 -0
- package/dist/scripts/wrangler-config/types.d.ts.map +1 -0
- package/dist/scripts/wrangler-config/types.js +49 -0
- package/dist/scripts/wrangler-config/types.js.map +1 -0
- package/dist/test/integration-migrations.d.ts +167 -0
- package/dist/test/integration-migrations.d.ts.map +1 -0
- package/dist/test/integration-migrations.js +171 -0
- package/dist/test/integration-migrations.js.map +1 -0
- package/dist/test/mocks/cloudflare-workers.d.ts +106 -0
- package/dist/test/mocks/cloudflare-workers.d.ts.map +1 -0
- package/dist/test/mocks/cloudflare-workers.js +90 -0
- package/dist/test/mocks/cloudflare-workers.js.map +1 -0
- package/dist/vite.d.ts +117 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +125 -0
- package/dist/vite.js.map +1 -0
- package/dist/vitest-web.d.ts +73 -0
- package/dist/vitest-web.d.ts.map +1 -0
- package/dist/vitest-web.js +72 -0
- package/dist/vitest-web.js.map +1 -0
- package/dist/vitest.d.ts +92 -0
- package/dist/vitest.d.ts.map +1 -0
- package/dist/vitest.js +128 -0
- package/dist/vitest.js.map +1 -0
- package/package.json +58 -3
- package/src/eslint.test.ts +175 -0
- package/src/eslint.ts +640 -0
- package/src/functions/pages-proxy.test.ts +72 -0
- package/src/functions/pages-proxy.ts +187 -0
- package/src/github/actions/retry-step/action.yml +39 -0
- package/src/github/actions/setup-env/action.yml +20 -0
- package/src/github/dependabot.yml +30 -0
- package/src/github/workflows/backup-main.yml +46 -0
- package/src/github/workflows/continuous-deployment.yml +188 -0
- package/src/github/workflows/continuous-integration.yml +259 -0
- package/src/github/workflows/scheduled-version-update.yml +38 -0
- package/src/github/workflows/upstream-sync.yml +56 -0
- package/src/index.ts +42 -0
- package/src/scripts/backup/backup-rules.test.ts +105 -0
- package/src/scripts/backup/d1-target.ts +54 -0
- package/src/scripts/backup/destination-config.ts +92 -0
- package/src/scripts/backup/encrypt-backup.ts +107 -0
- package/src/scripts/backup/naming.ts +62 -0
- package/src/scripts/check-god-files.test.ts +131 -0
- package/src/scripts/check-god-files.ts +327 -0
- package/src/scripts/ensure-spa-shell-stub.ts +34 -0
- package/src/scripts/init-secrets.ts +265 -0
- package/src/scripts/lib/cli-args.ts +154 -0
- package/src/scripts/lib/github-actions.ts +41 -0
- package/src/scripts/lib/wrangler-table.ts +105 -0
- package/src/scripts/migrations-lock.ts +52 -0
- package/src/scripts/prepare-wrangler-config.ts +51 -0
- package/src/scripts/spa-shell.test.ts +91 -0
- package/src/scripts/spa-shell.ts +179 -0
- package/src/scripts/validate-locales.test.ts +89 -0
- package/src/scripts/validate-locales.ts +380 -0
- package/src/scripts/verify-migrations.test.ts +71 -0
- package/src/scripts/verify-migrations.ts +364 -0
- package/src/scripts/verify-spa-shell.ts +56 -0
- package/src/scripts/wrangler-config/cli.ts +51 -0
- package/src/scripts/wrangler-config/patches.ts +157 -0
- package/src/scripts/wrangler-config/resources.ts +330 -0
- package/src/scripts/wrangler-config/types.ts +113 -0
- package/src/test/integration-migrations.test.ts +169 -0
- package/src/test/integration-migrations.ts +267 -0
- package/src/test/mocks/cloudflare-workers.ts +115 -0
- package/src/vite.test.ts +83 -0
- package/src/vite.ts +202 -0
- package/src/vitest-web.ts +109 -0
- package/src/vitest.ts +185 -0
package/package.json
CHANGED
|
@@ -1,6 +1,61 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rexezuge/tooling",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/Rexezuge-CloudflareWorkers/SDK.git",
|
|
9
|
+
"directory": "packages/tooling"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"default": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./*": {
|
|
20
|
+
"types": "./dist/*.d.ts",
|
|
21
|
+
"default": "./dist/*.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist",
|
|
26
|
+
"src"
|
|
27
|
+
],
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@rexezuge/d1": "1.0.0"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"eslint": "^10.0.0",
|
|
33
|
+
"jsonc-parser": "^3.3.1",
|
|
34
|
+
"prettier": "^3.9.0",
|
|
35
|
+
"typescript": "^6.0.0",
|
|
36
|
+
"typescript-eslint": "^8.0.0",
|
|
37
|
+
"vitest": "^4.0.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "26.6.4",
|
|
41
|
+
"eslint": "10.11.0",
|
|
42
|
+
"eslint-config-prettier": "10.1.8",
|
|
43
|
+
"eslint-plugin-prettier": "5.5.6",
|
|
44
|
+
"eslint-plugin-regexp": "3.3.1",
|
|
45
|
+
"eslint-plugin-sonarjs": "4.2.2",
|
|
46
|
+
"eslint-plugin-unicorn": "76.0.0",
|
|
47
|
+
"globals": "17.13.0",
|
|
48
|
+
"jsonc-parser": "3.3.1",
|
|
49
|
+
"prettier": "3.9.9",
|
|
50
|
+
"tsx": "4.23.15",
|
|
51
|
+
"typescript": "6.0.3",
|
|
52
|
+
"typescript-eslint": "8.71.1",
|
|
53
|
+
"vitest": "4.1.11"
|
|
54
|
+
},
|
|
55
|
+
"description": "Config factories, repo scripts, test helpers, and CI templates for the Rexezuge-CloudflareWorkers family.",
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsc -p tsconfig.json",
|
|
58
|
+
"typecheck": "tsc -p tsconfig.test.json --noEmit",
|
|
59
|
+
"test": "vitest run"
|
|
60
|
+
}
|
|
6
61
|
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { defineRepoLintConfig } from './eslint';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Structural checks on the produced flat config.
|
|
6
|
+
*
|
|
7
|
+
* These do not run ESLint — a rule that has to be observed linting is a rule this
|
|
8
|
+
* suite cannot afford, and the repos' own suites lint their trees. What is asserted
|
|
9
|
+
* here is the part that is a *decision* rather than a lint result: which paths are
|
|
10
|
+
* ignored, which rules are errors rather than warnings, and that the boundary table
|
|
11
|
+
* and the dynamic-`import()` guard agree with each other. A regression in any of
|
|
12
|
+
* those is a config that silently stops gating something.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** The only glob syntax the config uses: `**`, `*`, and `{a,b}` alternation. */
|
|
16
|
+
function globToRegExp(pattern: string): RegExp {
|
|
17
|
+
const escape = (char: string): string => char.replaceAll(/[$()+.?[\\\]^{|}]/g, String.raw`\$&`);
|
|
18
|
+
let out = '';
|
|
19
|
+
for (let index = 0; index < pattern.length; index += 1) {
|
|
20
|
+
const char = pattern[index] as string;
|
|
21
|
+
if (char === '*' && pattern[index + 1] === '*') {
|
|
22
|
+
out += '.*';
|
|
23
|
+
index += 1;
|
|
24
|
+
if (pattern[index + 1] === '/') index += 1;
|
|
25
|
+
} else if (char === '*') {
|
|
26
|
+
out += '[^/]*';
|
|
27
|
+
} else if (char === '{') {
|
|
28
|
+
const end = pattern.indexOf('}', index);
|
|
29
|
+
const alternatives = pattern
|
|
30
|
+
.slice(index + 1, end)
|
|
31
|
+
.split(',')
|
|
32
|
+
.map((alternative) => escape(alternative));
|
|
33
|
+
out += `(?:${alternatives.join('|')})`;
|
|
34
|
+
index = end;
|
|
35
|
+
} else {
|
|
36
|
+
out += escape(char);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return new RegExp(`^${out}$`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Every config object in the array, flattened through any nested arrays. */
|
|
43
|
+
function entries(config: unknown): Array<Record<string, unknown>> {
|
|
44
|
+
const out: Array<Record<string, unknown>> = [];
|
|
45
|
+
for (const entry of config as unknown[]) {
|
|
46
|
+
if (Array.isArray(entry)) {
|
|
47
|
+
out.push(...entries(entry));
|
|
48
|
+
} else if (typeof entry === 'object' && entry !== null) {
|
|
49
|
+
out.push(entry as Record<string, unknown>);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* True when the entry applies to `path`.
|
|
57
|
+
*
|
|
58
|
+
* An entry with no `files` key is global — the prettier block and the plugin presets
|
|
59
|
+
* are written that way, so a matcher that required `files` would report them as
|
|
60
|
+
* applying to nothing and the config's most important decision would look absent.
|
|
61
|
+
*/
|
|
62
|
+
function covers(entry: Record<string, unknown>, path: string): boolean {
|
|
63
|
+
const files = entry['files'];
|
|
64
|
+
if (!Array.isArray(files)) return true;
|
|
65
|
+
return files.some((pattern) => typeof pattern === 'string' && globToRegExp(pattern).test(path));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Every rule that applies to `path`, later entries winning. */
|
|
69
|
+
function rulesOf(config: unknown, path: string): Record<string, unknown> {
|
|
70
|
+
const rules: Record<string, unknown> = {};
|
|
71
|
+
for (const entry of entries(config)) {
|
|
72
|
+
if (covers(entry, path)) Object.assign(rules, entry['rules']);
|
|
73
|
+
}
|
|
74
|
+
return rules;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** JSON of every rule block in the config. Rules are plain data; plugins are not. */
|
|
78
|
+
function rulesJson(config: unknown): string {
|
|
79
|
+
return entries(config)
|
|
80
|
+
.map((entry) => JSON.stringify(entry['rules'] ?? {}))
|
|
81
|
+
.join('\n');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const config = defineRepoLintConfig({ scope: '@fixture' });
|
|
85
|
+
|
|
86
|
+
describe('defineRepoLintConfig', () => {
|
|
87
|
+
it('ignores the generated and build trees but not the test suite', () => {
|
|
88
|
+
const ignores = (config[0] as { ignores?: string[] }).ignores ?? [];
|
|
89
|
+
expect(ignores).toContain('apps/api/src/generated/**');
|
|
90
|
+
expect(ignores).toContain('apps/web/dist/**');
|
|
91
|
+
// `test/**` is deliberately absent: Edge-Sonic's decision, and the one the
|
|
92
|
+
// other source repos had the opposite of.
|
|
93
|
+
expect(ignores.some((pattern) => pattern.startsWith('test/'))).toBe(false);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('makes formatting drift an error, not a warning', () => {
|
|
97
|
+
// `pnpm run lint` is `eslint --fix --quiet`, and `--quiet` discards warnings: a
|
|
98
|
+
// `prettier/prettier` warning is a gate that has never run.
|
|
99
|
+
expect(rulesOf(config, 'src/anything.ts')['prettier/prettier']).toBe('error');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('gives web files browser globals in addition to node globals', () => {
|
|
103
|
+
// The sources linted apps/web under globals.node only, so window and document
|
|
104
|
+
// read as undefined globals — and the vitest web config runs those suites under
|
|
105
|
+
// jsdom, so the lint environment disagreed with the execution environment.
|
|
106
|
+
const webEntries = entries(config).filter((entry) => covers(entry, 'apps/web/src/main.tsx'));
|
|
107
|
+
const browser = webEntries
|
|
108
|
+
.map((entry) => Object.keys((entry as { languageOptions?: { globals?: Record<string, unknown> } }).languageOptions?.globals ?? {}))
|
|
109
|
+
.flat();
|
|
110
|
+
expect(browser).toContain('window');
|
|
111
|
+
expect(browser).toContain('document');
|
|
112
|
+
// And the node globals survive: a shared file touching both still lints.
|
|
113
|
+
expect(browser).toContain('process');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('keeps the three plugin families on', () => {
|
|
117
|
+
// sonarjs / unicorn / regexp are each a preset spread into the array; a preset
|
|
118
|
+
// that failed to import would leave the array without their rule blocks.
|
|
119
|
+
const all = rulesJson(config);
|
|
120
|
+
expect(all).toContain('unicorn/');
|
|
121
|
+
expect(all).toContain('sonarjs/');
|
|
122
|
+
expect(all).toContain('regexp/');
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('parameterizes the boundary rules by scope', () => {
|
|
126
|
+
const rules = rulesJson(config);
|
|
127
|
+
expect(rules).toContain('@fixture/backend-data');
|
|
128
|
+
expect(rules).not.toContain('@durable-dav/backend-data');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('bans a backend package from the SPA, with a message that says why', () => {
|
|
132
|
+
const rules = rulesJson(config);
|
|
133
|
+
expect(rules).toContain('ships zero backend dependencies');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('mirrors every boundary in a dynamic-import guard', () => {
|
|
137
|
+
const syntax = rulesOf(config, 'packages/backend-runtime/src/x.ts')['no-restricted-syntax'];
|
|
138
|
+
expect(Array.isArray(syntax)).toBe(true);
|
|
139
|
+
// `no-restricted-imports` reads ImportDeclaration only, so the same boundary has
|
|
140
|
+
// to be stated for ImportExpression too — that hole was load-bearing in
|
|
141
|
+
// Edge-Sonic, where the credential path reached a banned module through it.
|
|
142
|
+
expect(JSON.stringify(syntax)).toContain("ImportExpression[source.type='Literal']");
|
|
143
|
+
expect(JSON.stringify(syntax)).toContain('@fixture/backend-data');
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('relaxes the Vitest idioms in tests but not the correctness rules', () => {
|
|
147
|
+
const rules = rulesOf(config, 'test/schema.test.ts');
|
|
148
|
+
expect(rules['@typescript-eslint/unbound-method']).toBe('off');
|
|
149
|
+
expect(rules['unicorn/prefer-https']).toBe('off');
|
|
150
|
+
expect(rules['sonarjs/no-clear-text-protocols']).toBe('off');
|
|
151
|
+
// Unused variables stay on in tests, at exactly the severity the product
|
|
152
|
+
// source gets: a dead fake is a defect, not an artefact of test shape.
|
|
153
|
+
expect(rules['@typescript-eslint/no-unused-vars']).toStrictEqual(
|
|
154
|
+
rulesOf(config, 'src/anything.ts')['@typescript-eslint/no-unused-vars'],
|
|
155
|
+
);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('accepts extra layers without losing the canonical ones', () => {
|
|
159
|
+
const extended = defineRepoLintConfig({
|
|
160
|
+
scope: '@fixture',
|
|
161
|
+
extraLayers: [
|
|
162
|
+
{
|
|
163
|
+
dir: 'apps/api/src/endpoints',
|
|
164
|
+
ban: ['@fixture/backend-data/dao'],
|
|
165
|
+
allowTypeImports: true,
|
|
166
|
+
message: 'route classes must not import DAOs directly',
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
});
|
|
170
|
+
const rules = rulesJson(extended);
|
|
171
|
+
expect(rules).toContain('route classes must not import DAOs directly');
|
|
172
|
+
expect(rules).toContain('zero-dependency base layer');
|
|
173
|
+
expect(rules).toContain('ships zero backend dependencies');
|
|
174
|
+
});
|
|
175
|
+
});
|