four-stroke 0.2.1 → 0.3.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/.github/dependabot.yml +2 -0
- package/bin/api-types.mjs +18 -10
- package/bin/lint.mjs +6 -2
- package/bin/test.mjs +1 -0
- package/bin/type-check.mjs +6 -2
- package/oxlint.config.mjs +66 -26
- package/package.json +15 -7
- package/src/cmd.mjs +0 -1
- package/src/openapi-typescript.mjs +15 -0
- package/worker-configuration.d.ts +1706 -359
package/.github/dependabot.yml
CHANGED
package/bin/api-types.mjs
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import ts from "@typescript/typescript6";
|
|
3
4
|
import fs from "node:fs";
|
|
4
|
-
import openapiTS from "openapi-typescript";
|
|
5
5
|
import { format } from "oxfmt";
|
|
6
|
-
import
|
|
6
|
+
import openapiTS from "../src/openapi-typescript.mjs";
|
|
7
7
|
|
|
8
8
|
const services = process.argv[2].split(",");
|
|
9
9
|
|
|
10
10
|
const UUID = ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("UUID"));
|
|
11
11
|
const NULL = ts.factory.createLiteralTypeNode(ts.factory.createNull());
|
|
12
12
|
|
|
13
|
+
const isEmpty = (node) =>
|
|
14
|
+
ts.isTypeAliasDeclaration(node) &&
|
|
15
|
+
ts.isTypeReferenceNode(node.type) &&
|
|
16
|
+
ts.isIdentifier(node.type.typeName) &&
|
|
17
|
+
node.type.typeName.text === "Record" &&
|
|
18
|
+
node.type.typeArguments?.length === 2 &&
|
|
19
|
+
node.type.typeArguments[1].kind === ts.SyntaxKind.NeverKeyword;
|
|
20
|
+
|
|
13
21
|
await Promise.all(
|
|
14
22
|
services.map(async (service) => {
|
|
15
23
|
const output = await openapiTS(`${service}/doc`, {
|
|
@@ -20,18 +28,18 @@ await Promise.all(
|
|
|
20
28
|
return null;
|
|
21
29
|
},
|
|
22
30
|
});
|
|
31
|
+
const path = `src/__definitions__/${service.replace("https://", "").replace("http://", "")}-definitions.ts`;
|
|
23
32
|
const printer = ts.createPrinter({});
|
|
24
|
-
const resultFile = ts.createSourceFile(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
ts.
|
|
28
|
-
|
|
29
|
-
const result = printer.printNode(ts.EmitHint.Unspecified, output[0], resultFile);
|
|
33
|
+
const resultFile = ts.createSourceFile(path, "", ts.ScriptTarget.Latest);
|
|
34
|
+
const result = output
|
|
35
|
+
.filter((node) => !isEmpty(node))
|
|
36
|
+
.map((node) => printer.printNode(ts.EmitHint.Unspecified, node, resultFile))
|
|
37
|
+
.join("\n\n");
|
|
30
38
|
fs.writeFileSync(
|
|
31
|
-
|
|
39
|
+
path,
|
|
32
40
|
(
|
|
33
41
|
await format(
|
|
34
|
-
|
|
42
|
+
path,
|
|
35
43
|
`// Autogenerated by two-stroke
|
|
36
44
|
|
|
37
45
|
${fs.readFileSync("src/__definitions__/type-definitions.ts", "utf8")}
|
package/bin/lint.mjs
CHANGED
|
@@ -3,9 +3,13 @@
|
|
|
3
3
|
import fs from "fs";
|
|
4
4
|
import { cmd } from "../src/cmd.mjs";
|
|
5
5
|
|
|
6
|
+
const isApp = fs.readdirSync(".").some((file) => file.startsWith("vite.config."));
|
|
7
|
+
|
|
6
8
|
if (fs.existsSync("wrangler.jsonc")) {
|
|
7
9
|
cmd("wrangler types --env-file /dev/null --strict-vars false --check");
|
|
8
10
|
}
|
|
9
|
-
|
|
11
|
+
if (isApp) {
|
|
12
|
+
cmd("react-router typegen");
|
|
13
|
+
}
|
|
10
14
|
cmd("oxfmt --check");
|
|
11
|
-
cmd("oxlint");
|
|
15
|
+
cmd("oxlint --report-unused-disable-directives-severity=error");
|
package/bin/test.mjs
CHANGED
package/bin/type-check.mjs
CHANGED
|
@@ -3,9 +3,13 @@
|
|
|
3
3
|
import fs from "fs";
|
|
4
4
|
import { cmd } from "../src/cmd.mjs";
|
|
5
5
|
|
|
6
|
+
const isApp = fs.readdirSync(".").some((file) => file.startsWith("vite.config."));
|
|
7
|
+
|
|
6
8
|
if (fs.existsSync("wrangler.jsonc")) {
|
|
7
9
|
cmd("wrangler types --env-file /dev/null --strict-vars false");
|
|
8
10
|
}
|
|
9
|
-
|
|
10
|
-
cmd("
|
|
11
|
+
if (isApp) {
|
|
12
|
+
cmd("react-router typegen");
|
|
13
|
+
cmd("vite build");
|
|
14
|
+
}
|
|
11
15
|
cmd("tsc --noEmit");
|
package/oxlint.config.mjs
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { defineConfig } from "oxlint";
|
|
2
2
|
|
|
3
3
|
export default defineConfig({
|
|
4
|
-
plugins: ["eslint", "typescript", "unicorn", "oxc", "import", "promise", "
|
|
4
|
+
plugins: ["eslint", "typescript", "unicorn", "oxc", "import", "promise", "react"],
|
|
5
5
|
options: {
|
|
6
6
|
typeAware: true,
|
|
7
7
|
},
|
|
8
8
|
categories: {
|
|
9
9
|
correctness: "error",
|
|
10
|
-
suspicious: "
|
|
10
|
+
suspicious: "error",
|
|
11
11
|
perf: "error",
|
|
12
|
-
style: "
|
|
12
|
+
style: "error",
|
|
13
13
|
},
|
|
14
14
|
rules: {
|
|
15
|
+
// Judge a wrapped comment by its first line, so the second can carry on the sentence.
|
|
16
|
+
"capitalized-comments": ["error", "always", { ignoreConsecutiveComments: true }],
|
|
15
17
|
"no-map-spread": "off",
|
|
16
18
|
"no-named-export": "off",
|
|
17
19
|
"no-magic-numbers": "off",
|
|
@@ -22,7 +24,6 @@ export default defineConfig({
|
|
|
22
24
|
"sort-keys": "off",
|
|
23
25
|
curly: "off",
|
|
24
26
|
"switch-case-braces": "off",
|
|
25
|
-
"vitest/require-hook": "off",
|
|
26
27
|
"no-ternary": "off",
|
|
27
28
|
"group-exports": "off",
|
|
28
29
|
"exports-last": "off",
|
|
@@ -30,7 +31,6 @@ export default defineConfig({
|
|
|
30
31
|
"no-null": "off",
|
|
31
32
|
"consistent-type-specifier-style": "off",
|
|
32
33
|
"max-statements": "off",
|
|
33
|
-
"consistent-type-imports": "error",
|
|
34
34
|
"relative-url-style": ["error", "always"],
|
|
35
35
|
"no-namespace": "off",
|
|
36
36
|
"no-duplicate-imports": ["error", { allowSeparateTypeImports: true }],
|
|
@@ -53,32 +53,75 @@ export default defineConfig({
|
|
|
53
53
|
"no-anonymous-default-export": "off",
|
|
54
54
|
"no-continue": "off",
|
|
55
55
|
"init-declarations": "off",
|
|
56
|
-
"vitest/prefer-to-be-truthy": "off",
|
|
57
|
-
"vitest/prefer-to-be-falsy": "off",
|
|
58
|
-
"vitest/prefer-expect-assertions": "off",
|
|
59
|
-
"vitest/prefer-importing-vitest-globals": "off",
|
|
60
|
-
"vitest/no-importing-vitest-globals": "error",
|
|
61
|
-
"vitest/require-top-level-describe": "off",
|
|
62
|
-
"vitest/max-expects": "off",
|
|
63
|
-
"vitest/no-hooks": "off",
|
|
64
56
|
"unicorn/number-literal-case": "off",
|
|
65
57
|
"eslint/one-var": "off",
|
|
66
|
-
|
|
67
|
-
"
|
|
68
|
-
"
|
|
58
|
+
// A ternary only reads better when both branches fit on one line.
|
|
59
|
+
"unicorn/prefer-ternary": ["error", "only-single-line"],
|
|
60
|
+
"unicorn/prefer-spread": "off", // Upstream bug
|
|
61
|
+
// Positional capture groups are used throughout; naming them all would
|
|
62
|
+
// reindex every `match[n]` consumer for no functional gain.
|
|
63
|
+
"eslint/prefer-named-capture-group": "off",
|
|
64
|
+
// Stylesheets can only be pulled in for their side effects.
|
|
65
|
+
"import/no-unassigned-import": ["error", { allow: ["**/*.css", "**/*.scss"] }],
|
|
66
|
+
"react/jsx-max-depth": ["error", { max: 4 }],
|
|
67
|
+
"react/react-in-jsx-scope": "off", // Automatic JSX runtime (tsconfig `jsx: react-jsx`)
|
|
69
68
|
"react/function-component-definition": [
|
|
70
69
|
"error",
|
|
71
|
-
{
|
|
72
|
-
namedComponents: "arrow-function",
|
|
73
|
-
unnamedComponents: "arrow-function",
|
|
74
|
-
},
|
|
70
|
+
{ namedComponents: "arrow-function", unnamedComponents: "arrow-function" },
|
|
75
71
|
],
|
|
76
72
|
},
|
|
77
73
|
overrides: [
|
|
78
74
|
{
|
|
79
|
-
|
|
75
|
+
// Mocks and page factories are test code too, and use vitest.
|
|
76
|
+
files: [
|
|
77
|
+
"*.test.ts",
|
|
78
|
+
"*.test.tsx",
|
|
79
|
+
"*.spec.ts",
|
|
80
|
+
"*.spec.tsx",
|
|
81
|
+
"e2e/**",
|
|
82
|
+
"**/__mocks__/**",
|
|
83
|
+
"**/__factories__/**",
|
|
84
|
+
],
|
|
85
|
+
plugins: ["vitest"],
|
|
80
86
|
rules: {
|
|
81
|
-
"
|
|
87
|
+
"vitest/require-hook": "off",
|
|
88
|
+
"vitest/prefer-to-be-truthy": "off",
|
|
89
|
+
"vitest/prefer-to-be-falsy": "off",
|
|
90
|
+
"vitest/prefer-expect-assertions": "off",
|
|
91
|
+
"vitest/prefer-importing-vitest-globals": "off",
|
|
92
|
+
"vitest/prefer-describe-function-title": "off",
|
|
93
|
+
"vitest/require-top-level-describe": "off",
|
|
94
|
+
"vitest/max-expects": "off",
|
|
95
|
+
"vitest/no-hooks": "off",
|
|
96
|
+
"vitest/prefer-called-once": "off",
|
|
97
|
+
// `toEqual` ignores keys written as `undefined`; `toStrictEqual` does not. Fixtures
|
|
98
|
+
// spell those out on purpose, so the fix changes what a test asserts.
|
|
99
|
+
"vitest/prefer-strict-equal": "off",
|
|
100
|
+
// `vi.mock(import("x"))` does not type-check against vi.mock's overloads.
|
|
101
|
+
"vitest/prefer-import-in-mock": "off",
|
|
102
|
+
// A mock standing in for a whole module would restate that module's signatures.
|
|
103
|
+
"vitest/require-mock-type-parameters": "off",
|
|
104
|
+
// Assertion helpers are named `expect…` or `assert…` (`expectRedirect`), or are
|
|
105
|
+
// page-object methods that wrap expect(), so it can see them; anything left over
|
|
106
|
+
// really asserts nothing.
|
|
107
|
+
"vitest/expect-expect": [
|
|
108
|
+
"error",
|
|
109
|
+
{ assertFunctionNames: ["expect*", "assert*", "page.expect*", "page.*Present"] },
|
|
110
|
+
],
|
|
111
|
+
"vitest/prefer-lowercase-title": "off",
|
|
112
|
+
// Tests stash a method to restore it after stubbing. It is never called, so
|
|
113
|
+
// `this` never matters.
|
|
114
|
+
"unbound-method": "off",
|
|
115
|
+
// A helper belongs next to the only test that uses it; hoisting it to module
|
|
116
|
+
// scope saves nothing in a test run and puts it out of sight.
|
|
117
|
+
"unicorn/consistent-function-scoping": "off",
|
|
118
|
+
"vitest/no-conditional-expect": "off",
|
|
119
|
+
"vitest/prefer-called-with": "off",
|
|
120
|
+
"prefer-arrow-callback": "off",
|
|
121
|
+
"vitest/consistent-vitest-vi": "off", // Upstream bug
|
|
122
|
+
"vitest/consistent-test-filename": "off",
|
|
123
|
+
// UI steps, polling and findBy queries are sequential by design.
|
|
124
|
+
"eslint/no-await-in-loop": "off",
|
|
82
125
|
},
|
|
83
126
|
},
|
|
84
127
|
{
|
|
@@ -87,13 +130,10 @@ export default defineConfig({
|
|
|
87
130
|
"no-unused-vars": "off",
|
|
88
131
|
"@typescript-eslint/no-redundant-type-constituents": "off",
|
|
89
132
|
"@typescript-eslint/no-duplicate-type-constituents": "off",
|
|
90
|
-
"group-exports": "off",
|
|
91
|
-
"exports-last": "off",
|
|
92
|
-
"consistent-indexed-object-style": "off",
|
|
93
133
|
},
|
|
94
134
|
},
|
|
95
135
|
{
|
|
96
|
-
files: ["bin/*.mjs", "src/cmd.mjs"],
|
|
136
|
+
files: ["bin/*.mjs", "src/cmd.mjs", "src/openapi-typescript.mjs"],
|
|
97
137
|
rules: {
|
|
98
138
|
"import/no-nodejs-modules": "off",
|
|
99
139
|
"prefer-destructuring": "off",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "four-stroke",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Simple Cloudflare Worker SSR SPA framework",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -20,15 +20,16 @@
|
|
|
20
20
|
"main": "src/fake.ts",
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@types/react": "^19.3.0",
|
|
23
|
+
"@typescript/typescript6": "^6.0.2",
|
|
23
24
|
"openapi-typescript": "^7.13.0",
|
|
24
|
-
"typescript": "^
|
|
25
|
+
"typescript": "^7.0.2"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
28
|
"@cloudflare/vitest-pool-workers": "^0.22.0",
|
|
28
|
-
"knip": "^6.
|
|
29
|
-
"oxfmt": "^0.
|
|
30
|
-
"oxlint": "^1.
|
|
31
|
-
"oxlint-tsgolint": "^7.0.
|
|
29
|
+
"knip": "^6.38.0",
|
|
30
|
+
"oxfmt": "^0.71.0",
|
|
31
|
+
"oxlint": "^1.86.0",
|
|
32
|
+
"oxlint-tsgolint": "^7.0.2003",
|
|
32
33
|
"vitest": "^4.1.11"
|
|
33
34
|
},
|
|
34
35
|
"peerDependencies": {
|
|
@@ -37,11 +38,18 @@
|
|
|
37
38
|
"oxfmt": ">=0.59.0",
|
|
38
39
|
"oxlint": ">=1.74.0",
|
|
39
40
|
"oxlint-tsgolint": ">=0.24.0",
|
|
40
|
-
"typescript": "^
|
|
41
|
+
"typescript": "^7.0.2",
|
|
41
42
|
"vitest": "^4",
|
|
42
43
|
"wrangler": ">=3"
|
|
43
44
|
},
|
|
44
45
|
"engines": {
|
|
45
46
|
"node": "^24.9.0"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"dev": "node bin/dev.mjs",
|
|
50
|
+
"format": "node bin/format.mjs",
|
|
51
|
+
"lint": "node bin/lint.mjs",
|
|
52
|
+
"test": "node bin/test.mjs",
|
|
53
|
+
"type-check": "node bin/type-check.mjs"
|
|
46
54
|
}
|
|
47
55
|
}
|
package/src/cmd.mjs
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { registerHooks } from "node:module";
|
|
2
|
+
|
|
3
|
+
// Openapi-typescript needs the TypeScript 6 JS API (ts.factory), which TypeScript 7 no longer
|
|
4
|
+
// ships. Redirect its `typescript` import to @typescript/typescript6, resolved from two-stroke's
|
|
5
|
+
// own dependencies so this works however two-stroke is installed.
|
|
6
|
+
registerHooks({
|
|
7
|
+
resolve(specifier, context, nextResolve) {
|
|
8
|
+
if (specifier === "typescript" && context.parentURL?.includes("/openapi-typescript/")) {
|
|
9
|
+
return nextResolve("@typescript/typescript6", { ...context, parentURL: import.meta.url });
|
|
10
|
+
}
|
|
11
|
+
return nextResolve(specifier, context);
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export default (await import("openapi-typescript")).default;
|