rastack 0.0.16 → 0.0.20
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/CHANGELOG.md +43876 -43013
- package/dist/.prettierrc +7 -7
- package/dist/compile/analyze.js +19 -11
- package/dist/compile/index.js +26 -17
- package/dist/compile/manifest.js +2 -3
- package/dist/compile/openapi.js +5 -8
- package/dist/compile/program.js +19 -10
- package/dist/csv-schema.js +5 -6
- package/dist/define/index.js +2 -2
- package/dist/entity-generation/delete-method.js +8 -10
- package/dist/entity-generation/form.js +80 -82
- package/dist/entity-generation/get-method.js +35 -36
- package/dist/entity-generation/imports.js +24 -20
- package/dist/entity-generation/sync-method.d.ts +1 -1
- package/dist/entity-generation/sync-method.js +45 -46
- package/dist/entity-generation/update-method.js +9 -10
- package/dist/rad-wasm-build.d.ts +1 -1
- package/dist/rad-wasm-build.js +15 -6
- package/dist/rad.js +9 -2
- package/dist/schema/camel-to-pastel.js +1 -2
- package/dist/schema/capitalise-first-letter.js +1 -2
- package/dist/schema/extract-response.js +3 -4
- package/dist/schema/fetch-schema.js +4 -16
- package/dist/schema/remove-non-model-paths.js +1 -2
- package/dist/schema/to-camel-case.js +1 -2
- package/dist/schema/to-pastel-case.js +1 -2
- package/dist/schema-convert.js +22 -33
- package/dist/schema-entities.js +177 -189
- package/dist/schema-fetch.js +46 -63
- package/dist/schema-full.js +23 -36
- package/dist/schema-index.js +16 -27
- package/dist/schema-params.js +11 -22
- package/dist/seed.js +95 -97
- package/hooks/form/form.ts +207 -207
- package/hooks/form/index.ts +8 -8
- package/hooks/form/interfaces.ts +217 -217
- package/hooks/form/structure.ts +39 -39
- package/hooks/form/validate-schema.ts +49 -49
- package/hooks/index.ts +3 -3
- package/hooks/query/api.ts +42 -42
- package/hooks/query/delete.ts +45 -45
- package/hooks/query/fetch.ts +48 -48
- package/hooks/query/index.ts +21 -21
- package/hooks/query/interfaces.ts +111 -111
- package/hooks/query/list.ts +286 -286
- package/hooks/query/update.ts +88 -88
- package/hooks/query/url.ts +31 -31
- package/hooks/real-time/index.ts +1 -1
- package/hooks/real-time/pusher.ts +43 -43
- package/jest.config.cjs +6 -6
- package/package.json +57 -57
- package/provider/index.ts +13 -13
- package/provider/provider.tsx +187 -187
- package/provider/types.ts +114 -114
- package/provider/warehouse.ts +167 -167
- package/provider/wasm.ts +124 -124
- package/runtime.ts +3 -3
- package/src/.prettierrc +7 -7
- package/src/compile/analyze.ts +224 -224
- package/src/compile/index.ts +86 -86
- package/src/compile/manifest.ts +10 -10
- package/src/compile/model.ts +69 -69
- package/src/compile/openapi.ts +266 -266
- package/src/compile/program.ts +40 -40
- package/src/csv-schema.ts +187 -187
- package/src/define/index.ts +162 -162
- package/src/entity-generation/delete-method.ts +37 -37
- package/src/entity-generation/form.ts +169 -169
- package/src/entity-generation/get-method.ts +80 -80
- package/src/entity-generation/imports.ts +110 -110
- package/src/entity-generation/sync-method.ts +222 -222
- package/src/entity-generation/update-method.ts +38 -38
- package/src/index.ts +77 -77
- package/src/rad-compile.ts +88 -88
- package/src/rad-wasm-build.ts +102 -102
- package/src/rad.ts +101 -101
- package/src/scan.ts +89 -89
- package/src/schema/camel-to-pastel.ts +3 -3
- package/src/schema/capitalise-first-letter.ts +3 -3
- package/src/schema/extract-response.ts +38 -38
- package/src/schema/fetch-schema.ts +12 -12
- package/src/schema/remove-non-model-paths.ts +13 -13
- package/src/schema/to-camel-case.ts +7 -7
- package/src/schema/to-pastel-case.ts +6 -6
- package/src/schema-convert.ts +61 -61
- package/src/schema-entities.ts +401 -401
- package/src/schema-fetch.ts +82 -82
- package/src/schema-full.ts +38 -38
- package/src/schema-index.ts +29 -29
- package/src/schema-params.ts +116 -116
- package/src/seed.ts +297 -297
- package/sync/engine.ts +392 -392
- package/sync/hooks.ts +450 -450
- package/sync/index.ts +8 -8
- package/sync/persistence.ts +237 -237
- package/sync/provider.tsx +91 -91
- package/sync/registry.ts +36 -36
- package/sync/store.ts +126 -126
- package/sync/transactions.ts +300 -300
- package/sync/types.ts +94 -94
- package/test/compile.spec.ts +192 -192
- package/test/csv-schema.spec.ts +143 -143
- package/test/schema-entities.spec.ts +688 -688
- package/tsconfig.json +24 -24
- package/types.ts +18 -18
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
import { capitaliseFirstLetter } from "../schema/capitalise-first-letter";
|
|
2
|
-
|
|
3
|
-
export function generateUpdateAPIMethod(
|
|
4
|
-
url: string,
|
|
5
|
-
method: string,
|
|
6
|
-
operationId: string,
|
|
7
|
-
requestBody: string | undefined,
|
|
8
|
-
responseBody: string | undefined,
|
|
9
|
-
listQueryCacheKey?: string,
|
|
10
|
-
itemQueryCacheKey?: string,
|
|
11
|
-
): [string, Set<string>] {
|
|
12
|
-
const operationIdUpper = capitaliseFirstLetter(operationId);
|
|
13
|
-
const paramNames = `I${operationIdUpper}Params`;
|
|
14
|
-
|
|
15
|
-
let urlStructure = url.replace(/{([^}]+)}/g, "${params.$1}");
|
|
16
|
-
urlStructure = `(params) => \`${urlStructure}\``;
|
|
17
|
-
|
|
18
|
-
const methodUpper = method.charAt(0).toUpperCase() + method.slice(1);
|
|
19
|
-
const importStatements = new Set<string>();
|
|
20
|
-
importStatements.add(paramNames ?? "");
|
|
21
|
-
importStatements.add(requestBody ?? "");
|
|
22
|
-
importStatements.add(responseBody ?? "");
|
|
23
|
-
|
|
24
|
-
const cacheKeyLines = [
|
|
25
|
-
listQueryCacheKey ? `\n listQueryCacheKey: ${listQueryCacheKey},` : "",
|
|
26
|
-
itemQueryCacheKey ? `\n itemQueryCacheKey: ${itemQueryCacheKey},` : "",
|
|
27
|
-
].join("");
|
|
28
|
-
|
|
29
|
-
return [
|
|
30
|
-
`
|
|
31
|
-
export function use${methodUpper}${operationIdUpper}() {
|
|
32
|
-
return useUpdateQuery<${paramNames}, ${requestBody}, ${responseBody}>({
|
|
33
|
-
${method}Url: ${urlStructure},${cacheKeyLines}
|
|
34
|
-
});
|
|
35
|
-
}`,
|
|
36
|
-
importStatements,
|
|
37
|
-
];
|
|
38
|
-
}
|
|
1
|
+
import { capitaliseFirstLetter } from "../schema/capitalise-first-letter";
|
|
2
|
+
|
|
3
|
+
export function generateUpdateAPIMethod(
|
|
4
|
+
url: string,
|
|
5
|
+
method: string,
|
|
6
|
+
operationId: string,
|
|
7
|
+
requestBody: string | undefined,
|
|
8
|
+
responseBody: string | undefined,
|
|
9
|
+
listQueryCacheKey?: string,
|
|
10
|
+
itemQueryCacheKey?: string,
|
|
11
|
+
): [string, Set<string>] {
|
|
12
|
+
const operationIdUpper = capitaliseFirstLetter(operationId);
|
|
13
|
+
const paramNames = `I${operationIdUpper}Params`;
|
|
14
|
+
|
|
15
|
+
let urlStructure = url.replace(/{([^}]+)}/g, "${params.$1}");
|
|
16
|
+
urlStructure = `(params) => \`${urlStructure}\``;
|
|
17
|
+
|
|
18
|
+
const methodUpper = method.charAt(0).toUpperCase() + method.slice(1);
|
|
19
|
+
const importStatements = new Set<string>();
|
|
20
|
+
importStatements.add(paramNames ?? "");
|
|
21
|
+
importStatements.add(requestBody ?? "");
|
|
22
|
+
importStatements.add(responseBody ?? "");
|
|
23
|
+
|
|
24
|
+
const cacheKeyLines = [
|
|
25
|
+
listQueryCacheKey ? `\n listQueryCacheKey: ${listQueryCacheKey},` : "",
|
|
26
|
+
itemQueryCacheKey ? `\n itemQueryCacheKey: ${itemQueryCacheKey},` : "",
|
|
27
|
+
].join("");
|
|
28
|
+
|
|
29
|
+
return [
|
|
30
|
+
`
|
|
31
|
+
export function use${methodUpper}${operationIdUpper}() {
|
|
32
|
+
return useUpdateQuery<${paramNames}, ${requestBody}, ${responseBody}>({
|
|
33
|
+
${method}Url: ${urlStructure},${cacheKeyLines}
|
|
34
|
+
});
|
|
35
|
+
}`,
|
|
36
|
+
importStatements,
|
|
37
|
+
];
|
|
38
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,77 +1,77 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import path from "path";
|
|
4
|
-
import fs from "fs";
|
|
5
|
-
import { execSync } from "child_process";
|
|
6
|
-
|
|
7
|
-
const args = process.argv.slice(2);
|
|
8
|
-
const schemaOnly = args.includes("--schema-only");
|
|
9
|
-
|
|
10
|
-
const currentDir = process.cwd(); // Get the current working directory
|
|
11
|
-
const kodeDir = path.join(currentDir, ".kode");
|
|
12
|
-
const configFile = path.join(kodeDir, "generate-rad-sdk.json");
|
|
13
|
-
let config: any = {};
|
|
14
|
-
|
|
15
|
-
// Create the .kode directory if it doesn't exist
|
|
16
|
-
if (!fs.existsSync(kodeDir)) {
|
|
17
|
-
fs.mkdirSync(kodeDir);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// If the generate-schema-sdk-config.json file doesn't exist, create it with default values
|
|
21
|
-
if (!fs.existsSync(configFile)) {
|
|
22
|
-
config = {
|
|
23
|
-
schemaUrl: "http://127.0.0.1:8000/api/schema/",
|
|
24
|
-
};
|
|
25
|
-
fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
|
|
26
|
-
} else {
|
|
27
|
-
config = JSON.parse(fs.readFileSync(configFile, "utf-8"));
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const projectPath = currentDir;
|
|
31
|
-
const schemaUrl = config.schemaUrl;
|
|
32
|
-
|
|
33
|
-
// Execute the script commands and print the output
|
|
34
|
-
const schemaFetchOutput = execSync(
|
|
35
|
-
`node ${__dirname}/schema-fetch.js ${schemaUrl} ${projectPath}/packages/schema/schema/`,
|
|
36
|
-
).toString();
|
|
37
|
-
console.log(schemaFetchOutput);
|
|
38
|
-
|
|
39
|
-
const schemaConvertOutput = execSync(
|
|
40
|
-
`node ${__dirname}/schema-convert.js ${projectPath}/packages/schema/schema/`,
|
|
41
|
-
).toString();
|
|
42
|
-
console.log(schemaConvertOutput);
|
|
43
|
-
|
|
44
|
-
process.chdir(`${projectPath}/packages/schema/schema/api-schema`);
|
|
45
|
-
const schemaFullOutput = execSync(
|
|
46
|
-
`node ${__dirname}/schema-full.js ${projectPath}/packages/schema/schema/`,
|
|
47
|
-
).toString();
|
|
48
|
-
console.log(schemaFullOutput);
|
|
49
|
-
|
|
50
|
-
process.chdir(__dirname);
|
|
51
|
-
const schemaParamsOutput = execSync(
|
|
52
|
-
`node ${__dirname}/schema-params.js ${schemaUrl} ${projectPath}/packages/schema/schema/`,
|
|
53
|
-
).toString();
|
|
54
|
-
console.log(schemaParamsOutput);
|
|
55
|
-
|
|
56
|
-
const schemaIndexOutput = execSync(
|
|
57
|
-
`node ${__dirname}/schema-index.js ${projectPath}/packages/schema/schema/`,
|
|
58
|
-
).toString();
|
|
59
|
-
console.log(schemaIndexOutput);
|
|
60
|
-
|
|
61
|
-
if (!schemaOnly) {
|
|
62
|
-
// Generate entities if --schema-only flag is not provided
|
|
63
|
-
const schemaEntitiesOutput = execSync(
|
|
64
|
-
`node ${__dirname}/schema-entities.js ${schemaUrl} ${projectPath}/packages/entities/`,
|
|
65
|
-
).toString();
|
|
66
|
-
console.log(schemaEntitiesOutput);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const prettierSchemaOutput = execSync(
|
|
70
|
-
`${projectPath}/node_modules/.bin/prettier --write --config .prettierrc ${projectPath}/packages/schema/schema/`,
|
|
71
|
-
).toString();
|
|
72
|
-
console.log(prettierSchemaOutput);
|
|
73
|
-
|
|
74
|
-
const prettierEntitiesOutput = execSync(
|
|
75
|
-
`${projectPath}/node_modules/.bin/prettier --write --config .prettierrc ${projectPath}/packages/entities/`,
|
|
76
|
-
).toString();
|
|
77
|
-
console.log(prettierEntitiesOutput);
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import path from "path";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import { execSync } from "child_process";
|
|
6
|
+
|
|
7
|
+
const args = process.argv.slice(2);
|
|
8
|
+
const schemaOnly = args.includes("--schema-only");
|
|
9
|
+
|
|
10
|
+
const currentDir = process.cwd(); // Get the current working directory
|
|
11
|
+
const kodeDir = path.join(currentDir, ".kode");
|
|
12
|
+
const configFile = path.join(kodeDir, "generate-rad-sdk.json");
|
|
13
|
+
let config: any = {};
|
|
14
|
+
|
|
15
|
+
// Create the .kode directory if it doesn't exist
|
|
16
|
+
if (!fs.existsSync(kodeDir)) {
|
|
17
|
+
fs.mkdirSync(kodeDir);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// If the generate-schema-sdk-config.json file doesn't exist, create it with default values
|
|
21
|
+
if (!fs.existsSync(configFile)) {
|
|
22
|
+
config = {
|
|
23
|
+
schemaUrl: "http://127.0.0.1:8000/api/schema/",
|
|
24
|
+
};
|
|
25
|
+
fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
|
|
26
|
+
} else {
|
|
27
|
+
config = JSON.parse(fs.readFileSync(configFile, "utf-8"));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const projectPath = currentDir;
|
|
31
|
+
const schemaUrl = config.schemaUrl;
|
|
32
|
+
|
|
33
|
+
// Execute the script commands and print the output
|
|
34
|
+
const schemaFetchOutput = execSync(
|
|
35
|
+
`node ${__dirname}/schema-fetch.js ${schemaUrl} ${projectPath}/packages/schema/schema/`,
|
|
36
|
+
).toString();
|
|
37
|
+
console.log(schemaFetchOutput);
|
|
38
|
+
|
|
39
|
+
const schemaConvertOutput = execSync(
|
|
40
|
+
`node ${__dirname}/schema-convert.js ${projectPath}/packages/schema/schema/`,
|
|
41
|
+
).toString();
|
|
42
|
+
console.log(schemaConvertOutput);
|
|
43
|
+
|
|
44
|
+
process.chdir(`${projectPath}/packages/schema/schema/api-schema`);
|
|
45
|
+
const schemaFullOutput = execSync(
|
|
46
|
+
`node ${__dirname}/schema-full.js ${projectPath}/packages/schema/schema/`,
|
|
47
|
+
).toString();
|
|
48
|
+
console.log(schemaFullOutput);
|
|
49
|
+
|
|
50
|
+
process.chdir(__dirname);
|
|
51
|
+
const schemaParamsOutput = execSync(
|
|
52
|
+
`node ${__dirname}/schema-params.js ${schemaUrl} ${projectPath}/packages/schema/schema/`,
|
|
53
|
+
).toString();
|
|
54
|
+
console.log(schemaParamsOutput);
|
|
55
|
+
|
|
56
|
+
const schemaIndexOutput = execSync(
|
|
57
|
+
`node ${__dirname}/schema-index.js ${projectPath}/packages/schema/schema/`,
|
|
58
|
+
).toString();
|
|
59
|
+
console.log(schemaIndexOutput);
|
|
60
|
+
|
|
61
|
+
if (!schemaOnly) {
|
|
62
|
+
// Generate entities if --schema-only flag is not provided
|
|
63
|
+
const schemaEntitiesOutput = execSync(
|
|
64
|
+
`node ${__dirname}/schema-entities.js ${schemaUrl} ${projectPath}/packages/entities/`,
|
|
65
|
+
).toString();
|
|
66
|
+
console.log(schemaEntitiesOutput);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const prettierSchemaOutput = execSync(
|
|
70
|
+
`${projectPath}/node_modules/.bin/prettier --write --config .prettierrc ${projectPath}/packages/schema/schema/`,
|
|
71
|
+
).toString();
|
|
72
|
+
console.log(prettierSchemaOutput);
|
|
73
|
+
|
|
74
|
+
const prettierEntitiesOutput = execSync(
|
|
75
|
+
`${projectPath}/node_modules/.bin/prettier --write --config .prettierrc ${projectPath}/packages/entities/`,
|
|
76
|
+
).toString();
|
|
77
|
+
console.log(prettierEntitiesOutput);
|
package/src/rad-compile.ts
CHANGED
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* `rad compile | check | list | urls` — the TypeScript-first replacement for the
|
|
5
|
-
* old Django `manage.py rastack` command.
|
|
6
|
-
*
|
|
7
|
-
* rad compile [resourcesDir] [outDir] defs → schema.rad.json + openapi.json
|
|
8
|
-
* rad check [resourcesDir] validate the resource graph (exit != 0 on error)
|
|
9
|
-
* rad list [resourcesDir] print every resource + its fields/relations
|
|
10
|
-
* rad urls [resourcesDir] print the generated /api/{app}/v1/{model}/ routes
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { analyzeResources, collisions, compile, urlsFor } from "./compile";
|
|
14
|
-
|
|
15
|
-
const DEFAULT_RESOURCES = "resources";
|
|
16
|
-
const DEFAULT_OUT = ".rad";
|
|
17
|
-
|
|
18
|
-
function main(argv: string[]): void {
|
|
19
|
-
const [sub, ...rest] = argv;
|
|
20
|
-
|
|
21
|
-
switch (sub) {
|
|
22
|
-
case "compile": {
|
|
23
|
-
const resourcesDir = rest[0] || DEFAULT_RESOURCES;
|
|
24
|
-
const outDir = rest[1] || DEFAULT_OUT;
|
|
25
|
-
const result = compile(resourcesDir, outDir);
|
|
26
|
-
console.log(
|
|
27
|
-
`✓ compiled ${result.manifest.resources.length} resource(s) → ${result.files.join(", ")}`,
|
|
28
|
-
);
|
|
29
|
-
break;
|
|
30
|
-
}
|
|
31
|
-
case "check": {
|
|
32
|
-
const resources = analyzeResources(rest[0] || DEFAULT_RESOURCES);
|
|
33
|
-
const errors = collisions(resources);
|
|
34
|
-
if (errors.length) {
|
|
35
|
-
for (const e of errors) console.error(` ✗ ${e}`);
|
|
36
|
-
console.error(`${errors.length} error(s) found.`);
|
|
37
|
-
process.exit(1);
|
|
38
|
-
}
|
|
39
|
-
console.log(`✓ ${resources.length} resource(s): no collisions.`);
|
|
40
|
-
break;
|
|
41
|
-
}
|
|
42
|
-
case "list": {
|
|
43
|
-
const resources = analyzeResources(rest[0] || DEFAULT_RESOURCES);
|
|
44
|
-
if (!resources.length) {
|
|
45
|
-
console.log("No resources found.");
|
|
46
|
-
break;
|
|
47
|
-
}
|
|
48
|
-
for (const r of resources) {
|
|
49
|
-
console.log(`${r.app}.${r.model}`);
|
|
50
|
-
for (const f of r.fields) {
|
|
51
|
-
const rel = f.relation ? ` → ${f.relation.app}.${f.relation.model}` : "";
|
|
52
|
-
console.log(` ${f.name}: ${f.type}${rel}`);
|
|
53
|
-
}
|
|
54
|
-
if (r.sync) {
|
|
55
|
-
const flags = [
|
|
56
|
-
r.sync.mode,
|
|
57
|
-
r.sync.load === "lazy" ? "lazy" : "",
|
|
58
|
-
r.sync.clientIds ? "client-ids" : "",
|
|
59
|
-
r.sync.confirmed ? `confirmed: ${r.sync.confirmed.join(",")}` : "",
|
|
60
|
-
]
|
|
61
|
-
.filter(Boolean)
|
|
62
|
-
.join(", ");
|
|
63
|
-
console.log(` sync: ${flags}`);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
break;
|
|
67
|
-
}
|
|
68
|
-
case "urls": {
|
|
69
|
-
const resources = analyzeResources(rest[0] || DEFAULT_RESOURCES);
|
|
70
|
-
for (const url of urlsFor(resources)) console.log(url);
|
|
71
|
-
break;
|
|
72
|
-
}
|
|
73
|
-
default:
|
|
74
|
-
console.error(
|
|
75
|
-
`Unknown compile subcommand: "${sub}"\n\n` +
|
|
76
|
-
`Usage:\n` +
|
|
77
|
-
` rad compile [resourcesDir] [outDir]\n` +
|
|
78
|
-
` rad check [resourcesDir]\n` +
|
|
79
|
-
` rad list [resourcesDir]\n` +
|
|
80
|
-
` rad urls [resourcesDir]\n`,
|
|
81
|
-
);
|
|
82
|
-
process.exit(1);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (require.main === module) {
|
|
87
|
-
main(process.argv.slice(2));
|
|
88
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `rad compile | check | list | urls` — the TypeScript-first replacement for the
|
|
5
|
+
* old Django `manage.py rastack` command.
|
|
6
|
+
*
|
|
7
|
+
* rad compile [resourcesDir] [outDir] defs → schema.rad.json + openapi.json
|
|
8
|
+
* rad check [resourcesDir] validate the resource graph (exit != 0 on error)
|
|
9
|
+
* rad list [resourcesDir] print every resource + its fields/relations
|
|
10
|
+
* rad urls [resourcesDir] print the generated /api/{app}/v1/{model}/ routes
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { analyzeResources, collisions, compile, urlsFor } from "./compile";
|
|
14
|
+
|
|
15
|
+
const DEFAULT_RESOURCES = "resources";
|
|
16
|
+
const DEFAULT_OUT = ".rad";
|
|
17
|
+
|
|
18
|
+
function main(argv: string[]): void {
|
|
19
|
+
const [sub, ...rest] = argv;
|
|
20
|
+
|
|
21
|
+
switch (sub) {
|
|
22
|
+
case "compile": {
|
|
23
|
+
const resourcesDir = rest[0] || DEFAULT_RESOURCES;
|
|
24
|
+
const outDir = rest[1] || DEFAULT_OUT;
|
|
25
|
+
const result = compile(resourcesDir, outDir);
|
|
26
|
+
console.log(
|
|
27
|
+
`✓ compiled ${result.manifest.resources.length} resource(s) → ${result.files.join(", ")}`,
|
|
28
|
+
);
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
case "check": {
|
|
32
|
+
const resources = analyzeResources(rest[0] || DEFAULT_RESOURCES);
|
|
33
|
+
const errors = collisions(resources);
|
|
34
|
+
if (errors.length) {
|
|
35
|
+
for (const e of errors) console.error(` ✗ ${e}`);
|
|
36
|
+
console.error(`${errors.length} error(s) found.`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
console.log(`✓ ${resources.length} resource(s): no collisions.`);
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
case "list": {
|
|
43
|
+
const resources = analyzeResources(rest[0] || DEFAULT_RESOURCES);
|
|
44
|
+
if (!resources.length) {
|
|
45
|
+
console.log("No resources found.");
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
for (const r of resources) {
|
|
49
|
+
console.log(`${r.app}.${r.model}`);
|
|
50
|
+
for (const f of r.fields) {
|
|
51
|
+
const rel = f.relation ? ` → ${f.relation.app}.${f.relation.model}` : "";
|
|
52
|
+
console.log(` ${f.name}: ${f.type}${rel}`);
|
|
53
|
+
}
|
|
54
|
+
if (r.sync) {
|
|
55
|
+
const flags = [
|
|
56
|
+
r.sync.mode,
|
|
57
|
+
r.sync.load === "lazy" ? "lazy" : "",
|
|
58
|
+
r.sync.clientIds ? "client-ids" : "",
|
|
59
|
+
r.sync.confirmed ? `confirmed: ${r.sync.confirmed.join(",")}` : "",
|
|
60
|
+
]
|
|
61
|
+
.filter(Boolean)
|
|
62
|
+
.join(", ");
|
|
63
|
+
console.log(` sync: ${flags}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
case "urls": {
|
|
69
|
+
const resources = analyzeResources(rest[0] || DEFAULT_RESOURCES);
|
|
70
|
+
for (const url of urlsFor(resources)) console.log(url);
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
default:
|
|
74
|
+
console.error(
|
|
75
|
+
`Unknown compile subcommand: "${sub}"\n\n` +
|
|
76
|
+
`Usage:\n` +
|
|
77
|
+
` rad compile [resourcesDir] [outDir]\n` +
|
|
78
|
+
` rad check [resourcesDir]\n` +
|
|
79
|
+
` rad list [resourcesDir]\n` +
|
|
80
|
+
` rad urls [resourcesDir]\n`,
|
|
81
|
+
);
|
|
82
|
+
process.exit(1);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (require.main === module) {
|
|
87
|
+
main(process.argv.slice(2));
|
|
88
|
+
}
|
package/src/rad-wasm-build.ts
CHANGED
|
@@ -1,102 +1,102 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* `rad wasm` — compile the Rust API to WebAssembly for in-browser local dev.
|
|
5
|
-
*
|
|
6
|
-
* Pipeline:
|
|
7
|
-
* 1. cargo build -p rad-wasm --release --target wasm32-unknown-unknown
|
|
8
|
-
* 2. wasm-bindgen --target web → stack/wasm/rad_wasm.js + rad_wasm_bg.wasm
|
|
9
|
-
* 3. wasm-opt -Oz (if available) to shrink the binary
|
|
10
|
-
*
|
|
11
|
-
* The generated bundle is what `<RAStackProvider mode="local">` loads. Prereqs:
|
|
12
|
-
* rustup target add wasm32-unknown-unknown
|
|
13
|
-
* cargo install wasm-bindgen-cli (version must match the wasm-bindgen crate)
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { spawnSync } from "child_process";
|
|
17
|
-
import fs from "fs";
|
|
18
|
-
import path from "path";
|
|
19
|
-
|
|
20
|
-
const repoRoot = path.resolve(__dirname, "..", "..");
|
|
21
|
-
const rustDir = path.join(repoRoot, "rust");
|
|
22
|
-
const outDir = path.join(repoRoot, "tools", "wasm");
|
|
23
|
-
const wasmPath = path.join(
|
|
24
|
-
rustDir,
|
|
25
|
-
"target",
|
|
26
|
-
"wasm32-unknown-unknown",
|
|
27
|
-
"release",
|
|
28
|
-
"rad_wasm.wasm",
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
function run(cmd: string, args: string[], cwd = repoRoot): void {
|
|
32
|
-
// Local build tool: `cmd`/`args` are the fixed toolchain invocations below
|
|
33
|
-
// (cargo, wasm-bindgen, wasm-opt), not untrusted input — no injection surface.
|
|
34
|
-
// nosemgrep: javascript.lang.security.detect-child-process.detect-child-process
|
|
35
|
-
const result = spawnSync(cmd, args, {
|
|
36
|
-
stdio: "inherit",
|
|
37
|
-
cwd,
|
|
38
|
-
env: process.env,
|
|
39
|
-
});
|
|
40
|
-
if (result.error) {
|
|
41
|
-
console.error(`\nCould not run \`${cmd}\`. Is it installed and on PATH?`);
|
|
42
|
-
if (cmd === "wasm-bindgen") {
|
|
43
|
-
console.error(" cargo install wasm-bindgen-cli");
|
|
44
|
-
}
|
|
45
|
-
process.exit(1);
|
|
46
|
-
}
|
|
47
|
-
if (result.status !== 0) {
|
|
48
|
-
process.exit(result.status ?? 1);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function has(cmd: string): boolean {
|
|
53
|
-
// Probes a fixed toolchain name (e.g. "wasm-opt") for availability; not
|
|
54
|
-
// untrusted input.
|
|
55
|
-
// nosemgrep: javascript.lang.security.detect-child-process.detect-child-process
|
|
56
|
-
return spawnSync(cmd, ["--version"], { stdio: "ignore" }).status === 0;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
console.log("→ cargo build -p rad-wasm --release (wasm32-unknown-unknown)");
|
|
60
|
-
run(
|
|
61
|
-
"cargo",
|
|
62
|
-
[
|
|
63
|
-
"build",
|
|
64
|
-
"-p",
|
|
65
|
-
"rad-wasm",
|
|
66
|
-
"--release",
|
|
67
|
-
"--target",
|
|
68
|
-
"wasm32-unknown-unknown",
|
|
69
|
-
],
|
|
70
|
-
rustDir,
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
console.log("→ wasm-bindgen → stack/wasm/");
|
|
74
|
-
run("wasm-bindgen", [
|
|
75
|
-
"--target",
|
|
76
|
-
"web",
|
|
77
|
-
"--out-dir",
|
|
78
|
-
outDir,
|
|
79
|
-
"--out-name",
|
|
80
|
-
"rad_wasm",
|
|
81
|
-
wasmPath,
|
|
82
|
-
]);
|
|
83
|
-
|
|
84
|
-
// Mark the emitted bundle as ESM so Node and bundlers treat it correctly
|
|
85
|
-
// without forcing the parent rastack package to be a module.
|
|
86
|
-
fs.writeFileSync(
|
|
87
|
-
path.join(outDir, "package.json"),
|
|
88
|
-
JSON.stringify({ type: "module", sideEffects: false }, null, 2) + "\n",
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
if (has("wasm-opt")) {
|
|
92
|
-
console.log("→ wasm-opt -Oz");
|
|
93
|
-
const bg = path.join(outDir, "rad_wasm_bg.wasm");
|
|
94
|
-
run("wasm-opt", ["-Oz", "-o", bg, bg]);
|
|
95
|
-
} else {
|
|
96
|
-
console.log("· wasm-opt not found — skipping size optimisation (optional)");
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const size = fs.statSync(path.join(outDir, "rad_wasm_bg.wasm")).size;
|
|
100
|
-
console.log(
|
|
101
|
-
`✓ wasm engine built: stack/wasm/ (${(size / 1024).toFixed(0)} KB)`,
|
|
102
|
-
);
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `rad wasm` — compile the Rust API to WebAssembly for in-browser local dev.
|
|
5
|
+
*
|
|
6
|
+
* Pipeline:
|
|
7
|
+
* 1. cargo build -p rad-wasm --release --target wasm32-unknown-unknown
|
|
8
|
+
* 2. wasm-bindgen --target web → stack/wasm/rad_wasm.js + rad_wasm_bg.wasm
|
|
9
|
+
* 3. wasm-opt -Oz (if available) to shrink the binary
|
|
10
|
+
*
|
|
11
|
+
* The generated bundle is what `<RAStackProvider mode="local">` loads. Prereqs:
|
|
12
|
+
* rustup target add wasm32-unknown-unknown
|
|
13
|
+
* cargo install wasm-bindgen-cli (version must match the wasm-bindgen crate)
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { spawnSync } from "child_process";
|
|
17
|
+
import fs from "fs";
|
|
18
|
+
import path from "path";
|
|
19
|
+
|
|
20
|
+
const repoRoot = path.resolve(__dirname, "..", "..");
|
|
21
|
+
const rustDir = path.join(repoRoot, "rust");
|
|
22
|
+
const outDir = path.join(repoRoot, "tools", "wasm");
|
|
23
|
+
const wasmPath = path.join(
|
|
24
|
+
rustDir,
|
|
25
|
+
"target",
|
|
26
|
+
"wasm32-unknown-unknown",
|
|
27
|
+
"release",
|
|
28
|
+
"rad_wasm.wasm",
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
function run(cmd: string, args: string[], cwd = repoRoot): void {
|
|
32
|
+
// Local build tool: `cmd`/`args` are the fixed toolchain invocations below
|
|
33
|
+
// (cargo, wasm-bindgen, wasm-opt), not untrusted input — no injection surface.
|
|
34
|
+
// nosemgrep: javascript.lang.security.detect-child-process.detect-child-process
|
|
35
|
+
const result = spawnSync(cmd, args, {
|
|
36
|
+
stdio: "inherit",
|
|
37
|
+
cwd,
|
|
38
|
+
env: process.env,
|
|
39
|
+
});
|
|
40
|
+
if (result.error) {
|
|
41
|
+
console.error(`\nCould not run \`${cmd}\`. Is it installed and on PATH?`);
|
|
42
|
+
if (cmd === "wasm-bindgen") {
|
|
43
|
+
console.error(" cargo install wasm-bindgen-cli");
|
|
44
|
+
}
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
if (result.status !== 0) {
|
|
48
|
+
process.exit(result.status ?? 1);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function has(cmd: string): boolean {
|
|
53
|
+
// Probes a fixed toolchain name (e.g. "wasm-opt") for availability; not
|
|
54
|
+
// untrusted input.
|
|
55
|
+
// nosemgrep: javascript.lang.security.detect-child-process.detect-child-process
|
|
56
|
+
return spawnSync(cmd, ["--version"], { stdio: "ignore" }).status === 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log("→ cargo build -p rad-wasm --release (wasm32-unknown-unknown)");
|
|
60
|
+
run(
|
|
61
|
+
"cargo",
|
|
62
|
+
[
|
|
63
|
+
"build",
|
|
64
|
+
"-p",
|
|
65
|
+
"rad-wasm",
|
|
66
|
+
"--release",
|
|
67
|
+
"--target",
|
|
68
|
+
"wasm32-unknown-unknown",
|
|
69
|
+
],
|
|
70
|
+
rustDir,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
console.log("→ wasm-bindgen → stack/wasm/");
|
|
74
|
+
run("wasm-bindgen", [
|
|
75
|
+
"--target",
|
|
76
|
+
"web",
|
|
77
|
+
"--out-dir",
|
|
78
|
+
outDir,
|
|
79
|
+
"--out-name",
|
|
80
|
+
"rad_wasm",
|
|
81
|
+
wasmPath,
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
// Mark the emitted bundle as ESM so Node and bundlers treat it correctly
|
|
85
|
+
// without forcing the parent rastack package to be a module.
|
|
86
|
+
fs.writeFileSync(
|
|
87
|
+
path.join(outDir, "package.json"),
|
|
88
|
+
JSON.stringify({ type: "module", sideEffects: false }, null, 2) + "\n",
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (has("wasm-opt")) {
|
|
92
|
+
console.log("→ wasm-opt -Oz");
|
|
93
|
+
const bg = path.join(outDir, "rad_wasm_bg.wasm");
|
|
94
|
+
run("wasm-opt", ["-Oz", "-o", bg, bg]);
|
|
95
|
+
} else {
|
|
96
|
+
console.log("· wasm-opt not found — skipping size optimisation (optional)");
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const size = fs.statSync(path.join(outDir, "rad_wasm_bg.wasm")).size;
|
|
100
|
+
console.log(
|
|
101
|
+
`✓ wasm engine built: stack/wasm/ (${(size / 1024).toFixed(0)} KB)`,
|
|
102
|
+
);
|