@greenpandastudios/aug-cli 0.20.1 → 0.21.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/README.md +1 -1
- package/docs/assets/benchmarks/execution.svg +774 -637
- package/docs/assets/benchmarks/http.svg +278 -249
- package/docs/assets/benchmarks/improvements.svg +66 -66
- package/docs/assets/benchmarks/kernels-mobile.svg +1 -0
- package/docs/assets/benchmarks/kernels.svg +1 -0
- package/docs/assets/benchmarks/memory.svg +153 -153
- package/docs/benchmark-results.json +227089 -90363
- package/docs/compatibility.md +6 -6
- package/docs/contributing-benchmarks.md +36 -6
- package/docs/dev-containers.md +8 -15
- package/docs/dgx-consumers.json +122 -0
- package/docs/dgx-gyms.json +784 -0
- package/docs/dgx-kernels.json +1170 -0
- package/docs/dgx-performance.json +227849 -0
- package/docs/dgx-spark.md +64 -0
- package/docs/diagnostics.md +1 -1
- package/docs/docker.md +16 -17
- package/docs/example-projects.json +32 -0
- package/docs/examples/approved-design/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
- package/docs/examples/approved-design/domain/app.md +4 -4
- package/docs/examples/approved-design/main.md +2 -2
- package/docs/examples/calls-benchmark/index.md +36 -0
- package/docs/examples/calls-benchmark/main.md +78 -0
- package/docs/examples/calls-benchmark/operations.md +60 -0
- package/docs/examples/developer-workflow/calculator.md +5 -5
- package/docs/examples/developer-workflow/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
- package/docs/examples/developer-workflow/logging/console.md +2 -2
- package/docs/examples/developer-workflow/logging/logger.md +2 -2
- package/docs/examples/developer-workflow/main.md +2 -2
- package/docs/examples/errors-benchmark/index.md +36 -0
- package/docs/examples/errors-benchmark/main.md +92 -0
- package/docs/examples/errors-benchmark/operations.md +65 -0
- package/docs/examples/float-benchmark/index.md +35 -0
- package/docs/examples/float-benchmark/main.md +75 -0
- package/docs/examples/generic-di/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
- package/docs/examples/generic-di/main.md +2 -2
- package/docs/examples/generic-di/types.md +3 -3
- package/docs/examples/hello/app/greeter.md +3 -3
- package/docs/examples/hello/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
- package/docs/examples/hello/logging/console.md +2 -2
- package/docs/examples/hello/logging/logger.md +2 -2
- package/docs/examples/hello/main.md +2 -2
- package/docs/examples/index.md +18 -1
- package/docs/examples/interceptors/app.md +5 -5
- package/docs/examples/interceptors/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
- package/docs/examples/interceptors/interceptors.md +2 -2
- package/docs/examples/interceptors/logging.md +3 -3
- package/docs/examples/interceptors/main.md +2 -2
- package/docs/examples/list-benchmark/index.md +35 -0
- package/docs/examples/list-benchmark/main.md +78 -0
- package/docs/examples/map-churn-benchmark/index.md +35 -0
- package/docs/examples/map-churn-benchmark/main.md +106 -0
- package/docs/examples/native-blake3/dependencies/packages/@greenpandastudios/aug-blake3/0.1.3/api.md +104 -0
- package/docs/examples/native-blake3/dependencies/packages/@greenpandastudios/aug-blake3/0.1.3/contracts.md +54 -0
- package/docs/examples/native-blake3/dependencies/packages/@greenpandastudios/aug-blake3/0.1.3/native.abi-json.md +48 -0
- package/docs/examples/native-blake3/hashing.md +93 -0
- package/docs/examples/native-blake3/index.md +38 -0
- package/docs/examples/native-blake3/main.md +73 -0
- package/docs/examples/native-pytorch/dependencies/packages/@greenpandastudios/aug-pytorch/0.1.4/api.md +406 -0
- package/docs/examples/native-pytorch/dependencies/packages/@greenpandastudios/aug-pytorch/0.1.4/bindings.md +51 -0
- package/docs/examples/native-pytorch/dependencies/packages/@greenpandastudios/aug-pytorch/0.1.4/contracts.md +63 -0
- package/docs/examples/native-pytorch/dependencies/packages/@greenpandastudios/aug-pytorch/0.1.4/native.abi-json.md +161 -0
- package/docs/examples/native-pytorch/index.md +38 -0
- package/docs/examples/native-pytorch/main.md +73 -0
- package/docs/examples/native-pytorch/tensors.md +123 -0
- package/docs/examples/native-sqlite/database.md +116 -0
- package/docs/examples/native-sqlite/dependencies/packages/@greenpandastudios/aug-sqlite/0.1.3/api.md +284 -0
- package/docs/examples/native-sqlite/dependencies/packages/@greenpandastudios/aug-sqlite/0.1.3/bindings.md +51 -0
- package/docs/examples/native-sqlite/dependencies/packages/@greenpandastudios/aug-sqlite/0.1.3/contracts.md +75 -0
- package/docs/examples/native-sqlite/dependencies/packages/@greenpandastudios/aug-sqlite/0.1.3/native.abi-json.md +119 -0
- package/docs/examples/native-sqlite/index.md +38 -0
- package/docs/examples/native-sqlite/main.md +73 -0
- package/docs/examples/native-zlib/compression.md +99 -0
- package/docs/examples/native-zlib/dependencies/packages/@greenpandastudios/aug-zlib/0.1.3/api.md +153 -0
- package/docs/examples/native-zlib/dependencies/packages/@greenpandastudios/aug-zlib/0.1.3/contracts.md +54 -0
- package/docs/examples/native-zlib/dependencies/packages/@greenpandastudios/aug-zlib/0.1.3/native.abi-json.md +76 -0
- package/docs/examples/native-zlib/index.md +38 -0
- package/docs/examples/native-zlib/main.md +78 -0
- package/docs/examples/new-syntax/console.md +2 -2
- package/docs/examples/new-syntax/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
- package/docs/examples/new-syntax/greeter.md +3 -3
- package/docs/examples/new-syntax/logger.md +2 -2
- package/docs/examples/new-syntax/main.md +2 -2
- package/docs/examples/ownership-transfer/dependencies/august/{0.20.1 → 0.21.0}/io/contracts.md +3 -3
- package/docs/examples/ownership-transfer/main.md +2 -2
- package/docs/examples/ownership-transfer/resource.md +2 -2
- package/docs/examples/packages-math/aug-package-json.md +1 -1
- package/docs/examples/records-benchmark/data.md +55 -0
- package/docs/examples/records-benchmark/index.md +36 -0
- package/docs/examples/records-benchmark/main.md +85 -0
- package/docs/examples/strings-benchmark/index.md +35 -0
- package/docs/examples/strings-benchmark/main.md +76 -0
- package/docs/examples/tasks-benchmark/index.md +36 -0
- package/docs/examples/tasks-benchmark/main.md +89 -0
- package/docs/examples/tasks-benchmark/operations.md +58 -0
- package/docs/getting-started.md +3 -3
- package/docs/grammar.md +2 -2
- package/docs/gym-results.json +784 -0
- package/docs/implementation-map.md +6 -0
- package/docs/index.md +1 -1
- package/docs/kernel-results.json +1170 -0
- package/docs/language-conformance.md +6 -0
- package/docs/language-constructs.md +9 -1
- package/docs/learn/index.md +1 -1
- package/docs/maintaining-docs.md +1 -1
- package/docs/native-implementation.md +276 -0
- package/docs/native-interop-llvm-plan.md +342 -0
- package/docs/native-package-examples.md +684 -0
- package/docs/native-packages.md +179 -0
- package/docs/packages.md +2 -2
- package/docs/performance.md +50 -29
- package/docs/production-readiness.md +11 -1
- package/docs/public/downloads/approved-design.zip +0 -0
- package/docs/public/downloads/calls-benchmark.zip +0 -0
- package/docs/public/downloads/developer-workflow.zip +0 -0
- package/docs/public/downloads/errors-benchmark.zip +0 -0
- package/docs/public/downloads/float-benchmark.zip +0 -0
- package/docs/public/downloads/generic-di.zip +0 -0
- package/docs/public/downloads/hello.zip +0 -0
- package/docs/public/downloads/interceptors.zip +0 -0
- package/docs/public/downloads/json-benchmark.zip +0 -0
- package/docs/public/downloads/list-benchmark.zip +0 -0
- package/docs/public/downloads/map-churn-benchmark.zip +0 -0
- package/docs/public/downloads/native-blake3.zip +0 -0
- package/docs/public/downloads/native-pytorch.zip +0 -0
- package/docs/public/downloads/native-sqlite.zip +0 -0
- package/docs/public/downloads/native-zlib.zip +0 -0
- package/docs/public/downloads/new-syntax.zip +0 -0
- package/docs/public/downloads/oidc-login.zip +0 -0
- package/docs/public/downloads/ownership-transfer.zip +0 -0
- package/docs/public/downloads/packages-app.zip +0 -0
- package/docs/public/downloads/packages-math.zip +0 -0
- package/docs/public/downloads/records-benchmark.zip +0 -0
- package/docs/public/downloads/strings-benchmark.zip +0 -0
- package/docs/public/downloads/tasks-benchmark.zip +0 -0
- package/docs/qualification-results.md +66 -0
- package/docs/reference.md +24 -0
- package/docs/releasing.md +81 -6
- package/docs/research/libtorch-native-qualification.md +115 -0
- package/docs/research/native-interop-llvm.md +197 -0
- package/docs/research/qualification-methods.md +15 -0
- package/docs/roadmap.md +1 -0
- package/docs/safety-gyms.md +41 -0
- package/docs/tooling.md +16 -15
- package/docs/web-library-gaps.md +1 -1
- package/docs/web.md +4 -0
- package/examples/approved-design/.aug-spec/manifest.json +3 -3
- package/examples/approved-design/domain/app.aug.md +4 -4
- package/examples/approved-design/main.aug.md +2 -2
- package/examples/developer-workflow/.aug-spec/manifest.json +3 -3
- package/examples/developer-workflow/calculator.aug.md +5 -5
- package/examples/developer-workflow/logging/console.aug.md +2 -2
- package/examples/developer-workflow/logging/logger.aug.md +2 -2
- package/examples/developer-workflow/main.aug.md +2 -2
- package/examples/generic-di/.aug-spec/manifest.json +3 -3
- package/examples/generic-di/main.aug.md +2 -2
- package/examples/generic-di/types.aug.md +3 -3
- package/examples/hello/.aug-spec/manifest.json +3 -3
- package/examples/hello/app/greeter.aug.md +3 -3
- package/examples/hello/logging/console.aug.md +2 -2
- package/examples/hello/logging/logger.aug.md +2 -2
- package/examples/hello/main.aug.md +2 -2
- package/examples/interceptors/.aug-spec/manifest.json +3 -3
- package/examples/interceptors/app.aug.md +5 -5
- package/examples/interceptors/interceptors.aug.md +2 -2
- package/examples/interceptors/logging.aug.md +3 -3
- package/examples/interceptors/main.aug.md +2 -2
- package/examples/native-blake3/.aug-spec/manifest.json +16 -0
- package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.1/native.abi.json +29 -0
- package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/api.aug +14 -0
- package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/api.aug.md +34 -0
- package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/contracts.aug +4 -0
- package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/contracts.aug.md +8 -0
- package/examples/native-blake3/.aug-spec/packages/@greenpandastudios/aug-blake3/0.1.3/native.abi.json +29 -0
- package/examples/native-blake3/AGENTS.md +5 -0
- package/examples/native-blake3/aug.lock.json +253 -0
- package/examples/native-blake3/hashing.aug +11 -0
- package/examples/native-blake3/hashing.aug.md +25 -0
- package/examples/native-blake3/main.aug +8 -0
- package/examples/native-blake3/main.aug.md +13 -0
- package/examples/native-pytorch/.aug-spec/manifest.json +18 -0
- package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.1/native.abi.json +142 -0
- package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.3/native.abi.json +142 -0
- package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/api.aug +101 -0
- package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/api.aug.md +160 -0
- package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/bindings.aug +3 -0
- package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/bindings.aug.md +8 -0
- package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/contracts.aug +6 -0
- package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/contracts.aug.md +13 -0
- package/examples/native-pytorch/.aug-spec/packages/@greenpandastudios/aug-pytorch/0.1.4/native.abi.json +142 -0
- package/examples/native-pytorch/AGENTS.md +5 -0
- package/examples/native-pytorch/aug.lock.json +309 -0
- package/examples/native-pytorch/main.aug +8 -0
- package/examples/native-pytorch/main.aug.md +13 -0
- package/examples/native-pytorch/tensors.aug +23 -0
- package/examples/native-pytorch/tensors.aug.md +35 -0
- package/examples/native-sqlite/.aug-spec/manifest.json +18 -0
- package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.2/native.abi.json +100 -0
- package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/api.aug +48 -0
- package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/api.aug.md +91 -0
- package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/bindings.aug +3 -0
- package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/bindings.aug.md +8 -0
- package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/contracts.aug +8 -0
- package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/contracts.aug.md +22 -0
- package/examples/native-sqlite/.aug-spec/packages/@greenpandastudios/aug-sqlite/0.1.3/native.abi.json +100 -0
- package/examples/native-sqlite/AGENTS.md +5 -0
- package/examples/native-sqlite/aug.lock.json +236 -0
- package/examples/native-sqlite/database.aug +15 -0
- package/examples/native-sqlite/database.aug.md +27 -0
- package/examples/native-sqlite/main.aug +8 -0
- package/examples/native-sqlite/main.aug.md +13 -0
- package/examples/native-zlib/.aug-spec/manifest.json +16 -0
- package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.1/native.abi.json +57 -0
- package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/api.aug +29 -0
- package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/api.aug.md +54 -0
- package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/contracts.aug +4 -0
- package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/contracts.aug.md +8 -0
- package/examples/native-zlib/.aug-spec/packages/@greenpandastudios/aug-zlib/0.1.3/native.abi.json +57 -0
- package/examples/native-zlib/AGENTS.md +5 -0
- package/examples/native-zlib/aug.lock.json +236 -0
- package/examples/native-zlib/compression.aug +15 -0
- package/examples/native-zlib/compression.aug.md +27 -0
- package/examples/native-zlib/main.aug +10 -0
- package/examples/native-zlib/main.aug.md +13 -0
- package/examples/new-syntax/.aug-spec/manifest.json +3 -3
- package/examples/new-syntax/console.aug.md +2 -2
- package/examples/new-syntax/greeter.aug.md +3 -3
- package/examples/new-syntax/logger.aug.md +2 -2
- package/examples/new-syntax/main.aug.md +2 -2
- package/examples/oidc-login/aug.lock.json +6 -6
- package/examples/ownership-transfer/.aug-spec/manifest.json +3 -3
- package/examples/ownership-transfer/main.aug.md +2 -2
- package/examples/ownership-transfer/resource.aug.md +2 -2
- package/examples/packages/math/aug-package.json +1 -1
- package/native/compiler-packs.json +43 -0
- package/package.json +3 -2
- package/runtime/aug_http.c +48 -21
- package/runtime/aug_http_ir.c +30 -0
- package/runtime/aug_http_ir.h +18 -0
- package/runtime/aug_ir.c +209 -0
- package/runtime/aug_ir.h +89 -0
- package/runtime/aug_json.c +6 -1
- package/runtime/aug_runtime.c +82 -16
- package/runtime/aug_runtime.h +16 -2
- package/runtime/aug_tasks.c +38 -7
- package/runtime/aug_values.c +12 -6
- package/scripts/bootstrap-native.mjs +4 -1
- package/src/ast.js +1 -1
- package/src/checker.js +110 -28
- package/src/cli.js +92 -14
- package/src/codegen.js +31 -6
- package/src/compiler-packs.js +66 -0
- package/src/config.js +2 -2
- package/src/editor.js +15 -6
- package/src/formatter.js +4 -2
- package/src/git-http.js +137 -0
- package/src/git-packages.js +9 -1
- package/src/help.js +10 -2
- package/src/ir-types.js +5 -0
- package/src/ir-verify.js +277 -0
- package/src/ir.js +962 -0
- package/src/llvm-debug.js +101 -0
- package/src/llvm-native.js +152 -0
- package/src/llvm-platform.js +20 -0
- package/src/llvm.js +781 -0
- package/src/native-artifacts.js +207 -0
- package/src/native-bindings.js +189 -0
- package/src/native-contracts.js +295 -0
- package/src/native-declarations.js +68 -0
- package/src/native-facts.js +63 -0
- package/src/package-locking.js +43 -0
- package/src/package-manager.js +23 -8
- package/src/parser.js +20 -2
- package/src/project.js +2 -2
- package/src/runtime-abi.js +23 -0
- package/src/runtime-adapters.js +18 -0
- package/src/schemas.js +24 -17
- package/src/semantic.js +8 -3
- package/src/snippets.js +1 -0
- package/src/spec.js +49 -8
- /package/examples/approved-design/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
- /package/examples/approved-design/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
- /package/examples/developer-workflow/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
- /package/examples/developer-workflow/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
- /package/examples/generic-di/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
- /package/examples/generic-di/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
- /package/examples/hello/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
- /package/examples/hello/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
- /package/examples/interceptors/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
- /package/examples/interceptors/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
- /package/examples/new-syntax/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
- /package/examples/new-syntax/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
- /package/examples/ownership-transfer/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug +0 -0
- /package/examples/ownership-transfer/.aug-spec/august/{0.20.1 → 0.21.0}/io/contracts.aug.md +0 -0
package/src/project.js
CHANGED
|
@@ -91,14 +91,14 @@ export function loadProject(projectRoot, overrides = new Map(), cache) {
|
|
|
91
91
|
if (!isExport && item.kind === 'export') {
|
|
92
92
|
diagnostics.push(diagnostic(file.path, item.span.line, item.span.column, 'export declarations belong in export.aug', 'EXPORT'));
|
|
93
93
|
}
|
|
94
|
-
if (file === main && ['class', 'interface', 'function', 'interceptor', 'test', 'composition'].includes(item.kind)) {
|
|
94
|
+
if (file === main && ['class', 'interface', 'function', 'interceptor', 'test', 'composition', 'resource'].includes(item.kind)) {
|
|
95
95
|
diagnostics.push(diagnostic(file.path, item.span.line, item.span.column, 'Define classes, interfaces, functions, and interceptors outside main.aug', 'MAIN'));
|
|
96
96
|
}
|
|
97
97
|
if (file !== main && ['bind', 'include', 'expr', 'assign', 'return', 'throw', 'if', 'while', 'for', 'destructure', 'match', 'scope', 'freeze', 'serve', 'lock',
|
|
98
98
|
'try', 'unsafe', 'borrow'].includes(item.kind)) {
|
|
99
99
|
diagnostics.push(diagnostic(file.path, item.span.line, item.span.column, 'Executable statements and bindings belong in main.aug', 'MAIN'));
|
|
100
100
|
}
|
|
101
|
-
if (item.kind === 'class' || item.kind === 'interface' || item.kind === 'function' || item.kind === 'interceptor' || item.kind === 'composition') {
|
|
101
|
+
if (item.kind === 'class' || item.kind === 'interface' || item.kind === 'function' || item.kind === 'interceptor' || item.kind === 'composition' || item.kind === 'resource') {
|
|
102
102
|
if (item.name in builtinTypes || builtinFunctions.some(operation => operation.name === item.name) || item.name === 'next') {
|
|
103
103
|
diagnostics.push(diagnostic(file.path, item.span.line, item.span.column, `${item.name} is a reserved built-in name`, 'NAME'));
|
|
104
104
|
continue;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { httpPolicyNames, httpPolicyNativeName } from "./http-policies.js";
|
|
3
|
+
/** Compiler-private identifiers, checked against the compiled target headers. */
|
|
4
|
+
export const runtimeOperations = ['PRINT', 'BINARY', 'UNARY', 'FIELD', 'SET_FIELD', 'LIST', 'TUPLE', 'SET', 'MAP', 'MAP_SET', 'LIST_LENGTH', 'LIST_GET', 'LIST_AT', 'LIST_APPEND', 'TUPLE_LENGTH', 'TUPLE_GET', 'SET_LENGTH', 'SET_ADD', 'SET_CONTAINS', 'MAP_LENGTH', 'MAP_GET', 'MAP_TAKE', 'MAP_CONTAINS', 'STRING_LENGTH', 'STRING_BYTES', 'STRING_SPLIT', 'STRING_STARTS_WITH', 'STRING_IS_TOKEN', 'BYTES_LENGTH', 'BYTES_TEXT', 'BYTES_BASE64URL', 'BASE64URL_DECODE', 'C_INT', 'READ_FILE', 'WRITE_FILE', 'ARGUMENTS', 'FREEZE', 'ITER', 'MAP_ITER', 'IS_TYPE', 'SHARED', 'SHARED_LOCK', 'JSON_WRAP', 'JSON_PARSE', 'JSON_STRINGIFY', 'JSON_GET', 'JSON_REQUIRE', 'JSON_STRING', 'JSON_INTEGER', 'JSON_BOOLEAN', 'JSON_ITEMS', 'TIME_NOW', 'EXIT', 'TEST_CASE'];
|
|
5
|
+
export const httpOperations = ['HTTP_HEADERS', 'HTTP_HEADERS_WITH', 'HTTP_HEADERS_GET', 'HTTP_HEADERS_ALL', 'HTTP_RESPONSE', 'HTTP_RESPONSE_STATUS', 'HTTP_FINISH', 'HTTP_EVENT', 'HTTP_YIELD', 'HTTP_CLIENT_REQUEST', 'HTTP_ACTION'];
|
|
6
|
+
/** Every private operation declares either a fixed or a collection arity. */
|
|
7
|
+
export const runtimeArities = {
|
|
8
|
+
PRINT: 1, BINARY: 2, UNARY: 1, FIELD: 1, SET_FIELD: 2, LIST: 'variadic', TUPLE: 'variadic', SET: 'variadic', MAP: 0, MAP_SET: 3,
|
|
9
|
+
LIST_LENGTH: 1, LIST_GET: 2, LIST_AT: 2, LIST_APPEND: 2, TUPLE_LENGTH: 1, TUPLE_GET: 2, SET_LENGTH: 1, SET_ADD: 2, SET_CONTAINS: 2,
|
|
10
|
+
MAP_LENGTH: 1, MAP_GET: 2, MAP_TAKE: 2, MAP_CONTAINS: 2, STRING_LENGTH: 1, STRING_BYTES: 1, STRING_SPLIT: 2, STRING_STARTS_WITH: 2, STRING_IS_TOKEN: 3,
|
|
11
|
+
BYTES_LENGTH: 1, BYTES_TEXT: 1, BYTES_BASE64URL: 1, BASE64URL_DECODE: 1, C_INT: 1, READ_FILE: 1, WRITE_FILE: 2, ARGUMENTS: 0, FREEZE: 1, ITER: 1, MAP_ITER: 1, IS_TYPE: 1,
|
|
12
|
+
SHARED: 1, SHARED_LOCK: 1, JSON_WRAP: 1, JSON_PARSE: 1, JSON_STRINGIFY: 1, JSON_GET: 2, JSON_REQUIRE: 2, JSON_STRING: 1, JSON_INTEGER: 1, JSON_BOOLEAN: 1, JSON_ITEMS: 1,
|
|
13
|
+
TIME_NOW: 0, EXIT: 1, TEST_CASE: 0, HTTP_HEADERS: 0, HTTP_HEADERS_WITH: 3, HTTP_HEADERS_GET: 2, HTTP_HEADERS_ALL: 2, HTTP_RESPONSE: 3, HTTP_RESPONSE_STATUS: 2,
|
|
14
|
+
HTTP_FINISH: 1, HTTP_EVENT: 4, HTTP_YIELD: 1, HTTP_CLIENT_REQUEST: 5, HTTP_ACTION: 'variadic',
|
|
15
|
+
};
|
|
16
|
+
export const schemaKinds = ['INT', 'C_INT', 'FLOAT', 'BOOL', 'STRING', 'LIST', 'MAP', 'SET', 'TUPLE', 'RECORD', 'JSON'];
|
|
17
|
+
export const runtimeIdentifiers = Object.fromEntries([
|
|
18
|
+
...runtimeOperations.map((name, index) => ['AUG_IR_' + name, index + 1]),
|
|
19
|
+
...httpOperations.map((name, index) => ['AUG_IR_' + name, index + 1]),
|
|
20
|
+
...schemaKinds.map((name, index) => ['AUG_SCHEMA_' + name, index]),
|
|
21
|
+
...httpPolicyNames.map((name, index) => [httpPolicyNativeName(name), index + 1]),
|
|
22
|
+
]);
|
|
23
|
+
export const runtimeIdentifierSha256 = createHash('sha256').update(JSON.stringify(runtimeIdentifiers)).digest('hex');
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const runtimeAdapters = [
|
|
2
|
+
{ name: '_aug_crypto_random', parameters: ['int'], returns: 'Bytes', component: 'crypto' },
|
|
3
|
+
{ name: '_aug_crypto_sha256', parameters: ['Bytes'], returns: 'Bytes', component: 'crypto' },
|
|
4
|
+
{ name: '_aug_crypto_generate_rsa', parameters: [], returns: 'RsaPrivateKey', component: 'crypto' },
|
|
5
|
+
{ name: '_aug_crypto_public_rsa', parameters: ['RsaPrivateKey'], returns: 'RsaPublicKey', component: 'crypto' },
|
|
6
|
+
{ name: '_aug_crypto_sign_rsa', parameters: ['RsaPrivateKey', 'Bytes'], returns: 'Bytes', component: 'crypto' },
|
|
7
|
+
{ name: '_aug_crypto_verify_rsa', parameters: ['RsaPublicKey', 'Bytes', 'Bytes'], returns: 'bool', component: 'crypto' },
|
|
8
|
+
{ name: '_aug_crypto_decode_base64url', parameters: ['string'], returns: 'Bytes', component: 'crypto' },
|
|
9
|
+
{ name: '_aug_crypto_equal', parameters: ['Bytes', 'Bytes'], returns: 'bool', component: 'crypto' },
|
|
10
|
+
{ name: '_aug_crypto_export_rsa', parameters: ['RsaPublicKey'], returns: 'Tuple<Bytes,Bytes>', component: 'crypto' },
|
|
11
|
+
{ name: '_aug_crypto_import_rsa', parameters: ['Bytes', 'Bytes'], returns: 'RsaPublicKey', component: 'crypto' },
|
|
12
|
+
{ name: '_aug_crypto_password_hash', parameters: ['Bytes', 'Bytes', 'int'], returns: 'Bytes', component: 'crypto' },
|
|
13
|
+
{ name: '_aug_http_log', parameters: ['string', 'string', 'int', 'int'], returns: 'void', component: 'http' },
|
|
14
|
+
{ name: '_aug_http_request', parameters: ['string', 'string', 'optional Headers', 'optional Bytes'], returns: 'HttpResponse<Bytes>', component: 'http' },
|
|
15
|
+
{ name: '_aug_http_url_encode', parameters: ['string'], returns: 'string', component: 'http' },
|
|
16
|
+
{ name: '_aug_http_cookie', parameters: ['string', 'string', 'string', 'int', 'bool'], returns: 'Headers', component: 'http' }
|
|
17
|
+
];
|
|
18
|
+
export function adapterSymbol(adapter) { return 'aug_ir_private' + adapter.name; }
|
package/src/schemas.js
CHANGED
|
@@ -21,11 +21,10 @@ export function jsonDataType(project, type, seen = new Set()) {
|
|
|
21
21
|
const params = new Map(node.typeParams.map((name, i) => [name, type.args[i]]));
|
|
22
22
|
return node.fields.every(field => jsonDataType(project, schemaType(project, field.type, type.def.file, params), seen));
|
|
23
23
|
}
|
|
24
|
-
/**
|
|
25
|
-
export class
|
|
24
|
+
/** Backend-neutral, resolved schema graph shared by HTTP and JSON decoding. */
|
|
25
|
+
export class DataSchemas {
|
|
26
26
|
names = new Map();
|
|
27
|
-
|
|
28
|
-
forwards = [];
|
|
27
|
+
nodes = [];
|
|
29
28
|
project;
|
|
30
29
|
constructorName;
|
|
31
30
|
constructor(project, constructorName) {
|
|
@@ -39,24 +38,32 @@ export class NativeSchemas {
|
|
|
39
38
|
return previous;
|
|
40
39
|
const name = 'aug_schema_' + this.names.size;
|
|
41
40
|
this.names.set(key, name);
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
const schema = { name, kind: type.name.toUpperCase(), nullable: type.nullable,
|
|
42
|
+
optional: !!type.optional, fields: [], labels: [] };
|
|
43
|
+
this.nodes.push(schema);
|
|
44
44
|
if (type.def?.node.kind === 'class' && type.def.node.record) {
|
|
45
|
-
kind = '
|
|
45
|
+
schema.kind = 'RECORD';
|
|
46
46
|
const node = type.def.node, params = new Map(node.typeParams.map((param, i) => [param, type.args[i]]));
|
|
47
|
-
fields = node.fields.map(field =>
|
|
48
|
-
labels = node.fields.map(field =>
|
|
49
|
-
maker = this.constructorName(type.def);
|
|
47
|
+
schema.fields = node.fields.map(field => this.request(schemaType(this.project, field.type, type.def.file, params)));
|
|
48
|
+
schema.labels = node.fields.map(field => field.name);
|
|
49
|
+
schema.maker = this.constructorName(type.def);
|
|
50
50
|
}
|
|
51
51
|
else
|
|
52
|
-
fields = type.args.map(arg =>
|
|
53
|
-
if (fields.length)
|
|
54
|
-
this.output.push(`static const AugSchema *const ${name}_fields[] = {${fields.join(', ')}};`);
|
|
55
|
-
if (labels.length)
|
|
56
|
-
this.output.push(`static const char *const ${name}_names[] = {${labels.join(', ')}};`);
|
|
57
|
-
this.output.push(`static const AugSchema ${name} = {${kind}, ${type.nullable ? 'true' : 'false'}, ${type.optional ? 'true' : 'false'}, ${fields.length}, ${fields.length ? name + '_fields' : 'NULL'}, ${labels.length ? name + '_names' : 'NULL'}, ${maker}};`);
|
|
52
|
+
schema.fields = type.args.map(arg => this.request(arg));
|
|
58
53
|
return name;
|
|
59
54
|
}
|
|
60
55
|
identity(type) { return [type.id, type.nullable, !!type.optional, type.args.map(arg => this.identity(arg))]; }
|
|
61
|
-
|
|
56
|
+
}
|
|
57
|
+
/** C representation of the same checked concrete schema graph. */
|
|
58
|
+
export class NativeSchemas extends DataSchemas {
|
|
59
|
+
declarations() {
|
|
60
|
+
return [...this.nodes.map(schema => `static const AugSchema ${schema.name};`), ...this.nodes.flatMap(schema => {
|
|
61
|
+
const { name, fields, labels } = schema;
|
|
62
|
+
return [
|
|
63
|
+
...(fields.length ? [`static const AugSchema *const ${name}_fields[] = {${fields.map(field => '&' + field).join(', ')}};`] : []),
|
|
64
|
+
...(labels.length ? [`static const char *const ${name}_names[] = {${labels.map(label => JSON.stringify(label)).join(', ')}};`] : []),
|
|
65
|
+
`static const AugSchema ${name} = {AUG_SCHEMA_${schema.kind}, ${schema.nullable ? 'true' : 'false'}, ${schema.optional ? 'true' : 'false'}, ${fields.length}, ${fields.length ? name + '_fields' : 'NULL'}, ${labels.length ? name + '_names' : 'NULL'}, ${schema.maker ?? 'NULL'}, NULL};`
|
|
66
|
+
];
|
|
67
|
+
})].join('\n');
|
|
68
|
+
}
|
|
62
69
|
}
|
package/src/semantic.js
CHANGED
|
@@ -12,6 +12,7 @@ import { checkUnitTests, discoverTests, mergeTestAnalysis, uniqueDiagnostics } f
|
|
|
12
12
|
import { formatFile } from "./formatter.js";
|
|
13
13
|
import { interceptorBehavior } from "./interceptors.js";
|
|
14
14
|
import { callableResult, callableErrors } from "./contracts.js";
|
|
15
|
+
import { nativeFact, nativeDependencies } from "./native-facts.js";
|
|
15
16
|
const genericFacts = (header) => header.typeParams.map(name => ({ name,
|
|
16
17
|
variance: header.typeVariance?.[name] ?? 'invariant', constraints: (header.typeConstraints?.[name] ?? []).map(typeName) }));
|
|
17
18
|
export function contractFacts(checked) {
|
|
@@ -19,7 +20,9 @@ export function contractFacts(checked) {
|
|
|
19
20
|
const callable = (method, constructor) => {
|
|
20
21
|
const contract = checked.effectContracts.get(method);
|
|
21
22
|
const layers = checked.interceptorPlans.get(constructor ?? method) ?? [];
|
|
23
|
+
const native = nativeFact(checked, method);
|
|
22
24
|
return { name: method.name, location: method.span, genericParameters: genericFacts(method),
|
|
25
|
+
native: native?.kind === 'function' ? native : undefined, nativeDependencies: nativeDependencies(checked, method), nativeCoverage: 'resolved-standalone-calls',
|
|
23
26
|
inputs: method.params.map(param => ({ label: param.label ?? param.name, name: param.name,
|
|
24
27
|
type: typeName(param.type), ownership: param.ownership, injected: param.injected, source: param.source })),
|
|
25
28
|
http: method.endpoint ? { method: method.endpoint.method, path: method.endpoint.path, status: method.endpoint.status,
|
|
@@ -28,7 +31,7 @@ export function contractFacts(checked) {
|
|
|
28
31
|
dependencies: policy.dependencies.map(index => method.params[index]?.label ?? method.params[index]?.name ?? '') })),
|
|
29
32
|
result: `${method.returnOwnership === 'own' ? 'own ' : ''}${tyName(callableResult(checked, method))}`,
|
|
30
33
|
changes: [...(contract?.changes ?? method.changes ?? [])],
|
|
31
|
-
capabilities: [...(contract?.uses.values() ?? [])].map(effect => `${effect.source}.${effect.operation}`).concat(method.externC ? [`C.${method.name}`] : []),
|
|
34
|
+
capabilities: [...(contract?.uses.values() ?? [])].map(effect => `${effect.source}.${effect.operation}`).concat(method.externC && !native ? [`C.${method.name}`] : []),
|
|
32
35
|
inferredEffects: !!contract?.inferred,
|
|
33
36
|
errors: constructor ? [...new Set([...(checked.constructorContracts.get(constructor)?.errors.map(tyName) ?? constructor.validationErrors?.map(typeName) ?? []),
|
|
34
37
|
...layers.flatMap(layer => layer.errors.map(tyName))])].sort() : callableErrors(checked, method),
|
|
@@ -68,8 +71,10 @@ export function contractFacts(checked) {
|
|
|
68
71
|
visit(child);
|
|
69
72
|
};
|
|
70
73
|
visit(node);
|
|
74
|
+
const native = node.kind === 'resource' ? nativeFact(checked, node) : undefined;
|
|
71
75
|
return { id: def.id, name: def.name, kind: node.kind === 'class' && node.record ? 'record' :
|
|
72
76
|
node.kind === 'interface' && node.capability ? 'capability' : node.kind,
|
|
77
|
+
native: native?.kind === 'resource' ? native : undefined,
|
|
73
78
|
location: node.span, public: !node.name.startsWith('_'), typeParameters: node.typeParams, genericParameters: genericFacts(node),
|
|
74
79
|
documentation: javadocBefore(file.source, 'annotations' in node ? node.annotations?.[0]?.span.start ?? node.span.start : node.span.start)?.markdown,
|
|
75
80
|
interfaces: node.kind === 'class' ? node.implements.map(typeName) : node.kind === 'interface' ? node.extends.map(typeName) : [],
|
|
@@ -79,7 +84,7 @@ export function contractFacts(checked) {
|
|
|
79
84
|
typeConstraints: node.typeConstraints, typeVariance: node.typeVariance, params: node.fields,
|
|
80
85
|
returns: syntheticType(node.name, node.span), returnOwnership: 'managed',
|
|
81
86
|
throws: node.validationErrors ?? [], changes: [], uses: [], body: node.constructorBody, externC: false, span: node.span }, node)] : []),
|
|
82
|
-
...methods.filter(method => !method.name.startsWith('_')).map(method => callable(method))], calls,
|
|
87
|
+
...methods.filter(method => node.kind === 'function' || !method.name.startsWith('_')).map(method => callable(method))], calls,
|
|
83
88
|
tests: file.items.flatMap(item => item.kind === 'test' && item.type.name === def.name ? item.groups.flatMap(group => group.cases.map(test => ({ group: group.name, name: test.name, location: test.span }))) : []) };
|
|
84
89
|
});
|
|
85
90
|
}
|
|
@@ -147,7 +152,7 @@ export function describe(checked, fileName, options = {}) {
|
|
|
147
152
|
const module = { file: source.path, dependencies: [...new Set(source.items.flatMap(item => item.kind === 'import' ?
|
|
148
153
|
(checked.project.imports.get(item) ?? []).map(def => def.file) : []))].sort(),
|
|
149
154
|
public: publicFacts.map(fact => ({ name: fact.name, shape: createHash('sha256').update(JSON.stringify({ kind: fact.kind,
|
|
150
|
-
generics: fact.genericParameters, fields: fact.fields.filter(field => !field.storage.startsWith('_')),
|
|
155
|
+
native: fact.native, generics: fact.genericParameters, fields: fact.fields.filter(field => !field.storage.startsWith('_')),
|
|
151
156
|
interfaces: fact.interfaces, callables: fact.callables.map(({ location, interceptors, inputs, ...contract }) => ({ ...contract,
|
|
152
157
|
inputs: inputs.map(({ name, ...input }) => input),
|
|
153
158
|
interceptors: interceptors.map(({ location, ...layer }) => layer) })) })).digest('hex') })),
|
package/src/snippets.js
CHANGED
|
@@ -24,6 +24,7 @@ export const snippetCatalog = [
|
|
|
24
24
|
{ prefix: 'waitall', description: 'Join two computations', body: 'wait for ${1:loadingUsers} and ${2:loadingOrders} as ${3:users} and ${4:orders}' },
|
|
25
25
|
{ prefix: 'lock', description: 'Access shared mutable state inside a bounded lock', body: 'lock ${1:shared} as ${2:value}:\n $0' },
|
|
26
26
|
{ prefix: 'unsafe', description: 'Contain a native C call', body: 'unsafe:\n $0' },
|
|
27
|
+
{ prefix: 'resource', description: 'An opaque native package resource with checked cleanup', body: 'extern C resource ${1:Handle}' },
|
|
27
28
|
{ prefix: 'serve', description: 'Start a native HTTP listener', body: 'serve ${1:endpoint} on port ${2:8787}' },
|
|
28
29
|
...['GET', 'POST', 'PATCH', 'DELETE'].map(method => ({ prefix: 'endpoint' + method.toLowerCase(), description: `A typed ${method} endpoint`, body: `endpoint ${method} "\${1:/items}" as \${2:handler}(\${3:}):\n $0` })),
|
|
29
30
|
{ prefix: 'stream', description: 'An endpoint yielding server-sent events', body: 'endpoint GET "${1:/events}" as ${2:events}() streams ServerEvent<string>:\n yield ServerEvent(data=${3:"hello"})' },
|
package/src/spec.js
CHANGED
|
@@ -11,6 +11,7 @@ import { compilerVersion } from "./package-manager.js";
|
|
|
11
11
|
import { tyName } from "./types.js";
|
|
12
12
|
import { action, attempt, branch, choice, coordinate, flow, loop, paragraph, renderSpecTree, scope, section, sequence, step } from "./spec-tree.js";
|
|
13
13
|
import { specHint } from "./spec-hints.js";
|
|
14
|
+
import { nativeFact, nativeDescription } from "./native-facts.js";
|
|
14
15
|
const generated = '<!-- Generated by aug spec. Edit the August source, then regenerate. -->';
|
|
15
16
|
const copied = '// Generated by aug spec. This is a copy of the installed dependency source.\n';
|
|
16
17
|
const code = (value) => { const text = value.replaceAll('\n', '\\n'); const fence = '`'.repeat(1 + Math.max(0, ...(text.match(/`+/g) ?? []).map(part => part.length))); return fence + (text.startsWith('`') ? ' ' : '') + text + (text.endsWith('`') ? ' ' : '') + fence; };
|
|
@@ -44,12 +45,19 @@ export function generateSpecs(checked, options = {}) {
|
|
|
44
45
|
}
|
|
45
46
|
const queue = [...owned].sort((a, b) => compare(a.path, b.path));
|
|
46
47
|
const seen = new Set(), outputs = hints.map(hint => ({ path: hint.file.path, text: hint.text, source: hint.file.path, kind: 'source-hint' }));
|
|
48
|
+
const contracts = new Map();
|
|
49
|
+
for (const [provider, path] of checked.native.providerDescriptors) {
|
|
50
|
+
const at = provider.lastIndexOf('@'), name = provider.slice(0, at), version = provider.slice(at + 1);
|
|
51
|
+
const destination = join(project.root, '.aug-spec', 'packages', name, version, 'native.abi.json');
|
|
52
|
+
contracts.set(provider, destination);
|
|
53
|
+
outputs.push({ path: destination, text: readFileSync(path, 'utf8'), source: path, kind: 'native-descriptor' });
|
|
54
|
+
}
|
|
47
55
|
for (let index = 0; index < queue.length; index++) {
|
|
48
56
|
const file = queue[index];
|
|
49
57
|
if (seen.has(file.path))
|
|
50
58
|
continue;
|
|
51
59
|
seen.add(file.path);
|
|
52
|
-
const writer = new SpecWriter(checked, file, docs, sources, own, offsets, path => {
|
|
60
|
+
const writer = new SpecWriter(checked, file, docs, sources, own, offsets, contracts, path => {
|
|
53
61
|
const dependency = project.files.get(path);
|
|
54
62
|
if (dependency && !seen.has(path))
|
|
55
63
|
queue.push(dependency);
|
|
@@ -67,20 +75,26 @@ class SpecWriter {
|
|
|
67
75
|
sources;
|
|
68
76
|
own;
|
|
69
77
|
offsets;
|
|
78
|
+
contracts;
|
|
70
79
|
enqueue;
|
|
71
80
|
used = new Map();
|
|
72
81
|
builtins = new Map();
|
|
73
82
|
properties = new Map();
|
|
74
83
|
locals = new Map();
|
|
75
|
-
constructor(checked, file, docs, sources, own, offsets, enqueue) {
|
|
84
|
+
constructor(checked, file, docs, sources, own, offsets, contracts, enqueue) {
|
|
76
85
|
this.checked = checked;
|
|
77
86
|
this.file = file;
|
|
78
87
|
this.docs = docs;
|
|
79
88
|
this.sources = sources;
|
|
80
89
|
this.own = own;
|
|
81
90
|
this.offsets = offsets;
|
|
91
|
+
this.contracts = contracts;
|
|
82
92
|
this.enqueue = enqueue;
|
|
83
93
|
}
|
|
94
|
+
nativeDescription(native) {
|
|
95
|
+
const contract = this.contracts.get(native.provider);
|
|
96
|
+
return nativeDescription(native, `[${code(native.descriptor)}](${url(relative(dirname(this.docs.get(this.file.path)), contract))})`);
|
|
97
|
+
}
|
|
84
98
|
definition(name) { return this.checked.project.scopes.get(this.file.path)?.get(name); }
|
|
85
99
|
use(def, method, field) {
|
|
86
100
|
if (!def || def.file === this.file.path)
|
|
@@ -804,8 +818,10 @@ class SpecWriter {
|
|
|
804
818
|
children.push(...this.contract(method, documentation), ...this.layers(method));
|
|
805
819
|
if (method.body)
|
|
806
820
|
children.push(flow(this.statements(method.body)));
|
|
807
|
-
else if (method.externC)
|
|
808
|
-
|
|
821
|
+
else if (method.externC) {
|
|
822
|
+
const native = nativeFact(this.checked, method);
|
|
823
|
+
children.push(paragraph(native ? this.nativeDescription(native) : 'Native C implementation; only its declared contract is visible here.'));
|
|
824
|
+
}
|
|
809
825
|
return this.heading(name, method.span, owner && owner.node.kind !== 'function' ? 3 : 2, children);
|
|
810
826
|
}
|
|
811
827
|
exportLine(item) {
|
|
@@ -822,6 +838,10 @@ class SpecWriter {
|
|
|
822
838
|
}
|
|
823
839
|
declaration(item) {
|
|
824
840
|
switch (item.kind) {
|
|
841
|
+
case 'resource': {
|
|
842
|
+
const native = nativeFact(this.checked, item);
|
|
843
|
+
return this.heading(item.name, item.span, 2, [paragraph(native ? this.nativeDescription(native) : code(item.name) + ' is an opaque native resource with an unresolved package release contract.')], 'native resource');
|
|
844
|
+
}
|
|
825
845
|
case 'function': return this.callable(item);
|
|
826
846
|
case 'class': {
|
|
827
847
|
const def = this.definition(item.name);
|
|
@@ -932,7 +952,7 @@ class SpecWriter {
|
|
|
932
952
|
}
|
|
933
953
|
render() {
|
|
934
954
|
const exports = this.file.items.filter(item => item.kind === 'export');
|
|
935
|
-
const declarations = this.file.items.filter(item => ['class', 'interface', 'interceptor', 'function', 'composition'].includes(item.kind));
|
|
955
|
+
const declarations = this.file.items.filter(item => ['class', 'interface', 'interceptor', 'function', 'composition', 'resource'].includes(item.kind));
|
|
936
956
|
const providers = this.file.items.filter(item => item.kind === 'bind' || item.kind === 'include');
|
|
937
957
|
const startup = this.file.items.filter(item => item.kind !== 'import' && item.kind !== 'export' && item.kind !== 'test' && item.kind !== 'bind' && item.kind !== 'include' && !declarations.includes(item));
|
|
938
958
|
const children = [];
|
|
@@ -982,18 +1002,28 @@ export function updateSpecs(checked, check = false, options = {}) {
|
|
|
982
1002
|
const outputs = generateSpecs(checked, options), root = checked.project.root;
|
|
983
1003
|
const manifest = join(root, '.aug-spec', 'manifest.json');
|
|
984
1004
|
let previous = [];
|
|
1005
|
+
const previousDescriptors = new Map();
|
|
1006
|
+
const descriptorPath = (path) => /^\.aug-spec\/packages\/(?:@[^/]+\/)?[^/]+\/[^/]+\/native\.abi\.json$/.test(path) && !path.includes('\\') && !path.split('/').some(part => part === '.' || part === '..');
|
|
985
1007
|
if (options.manifest !== false && existsSync(manifest)) {
|
|
986
1008
|
const saved = JSON.parse(readFileSync(manifest, 'utf8'));
|
|
987
|
-
if (saved.format !== 1 || !Array.isArray(saved.files) || saved.files.some(path => typeof path !== 'string' || relative(root, resolve(root, path)).startsWith('..') || !path.endsWith('.aug') && !path.endsWith('.aug.md')))
|
|
1009
|
+
if (saved.format !== 1 || !Array.isArray(saved.files) || saved.files.some(path => typeof path !== 'string' || relative(root, resolve(root, path)).startsWith('..') || !path.endsWith('.aug') && !path.endsWith('.aug.md') && !descriptorPath(path)))
|
|
988
1010
|
throw new Error('Invalid generated specification manifest');
|
|
989
1011
|
previous = saved.files.map(path => resolve(root, path));
|
|
1012
|
+
for (const [path, digest] of Object.entries(saved.nativeDescriptors ?? {})) {
|
|
1013
|
+
if (!descriptorPath(path) || !saved.files.includes(path) || typeof digest !== 'string' || !/^[0-9a-f]{64}$/.test(digest))
|
|
1014
|
+
throw new Error('Invalid generated native descriptor manifest');
|
|
1015
|
+
previousDescriptors.set(resolve(root, path), digest);
|
|
1016
|
+
}
|
|
990
1017
|
}
|
|
991
1018
|
const artifacts = outputs.filter(output => output.kind !== 'source-hint');
|
|
992
1019
|
const names = new Set(artifacts.map(output => output.path));
|
|
993
1020
|
const removed = previous.filter(path => !names.has(path) && existsSync(path));
|
|
994
1021
|
const stale = outputs.filter(output => !existsSync(output.path) || readFileSync(output.path, 'utf8') !== output.text).map(output => relative(root, output.path));
|
|
995
1022
|
stale.push(...removed.map(path => relative(root, path)));
|
|
996
|
-
const
|
|
1023
|
+
const descriptors = artifacts.filter(output => output.kind === 'native-descriptor');
|
|
1024
|
+
const manifestText = JSON.stringify({ format: 1, files: artifacts.map(output => relative(root, output.path).replaceAll('\\', '/')),
|
|
1025
|
+
...(descriptors.length ? { nativeDescriptors: Object.fromEntries(descriptors.map(output => [relative(root, output.path).replaceAll('\\', '/'), hash(output.text)])) } : {}),
|
|
1026
|
+
digest: hash(artifacts.map(output => output.text).join('\0')) }, null, 2) + '\n';
|
|
997
1027
|
if (options.manifest !== false && (!existsSync(manifest) || readFileSync(manifest, 'utf8') !== manifestText))
|
|
998
1028
|
stale.push('.aug-spec/manifest.json');
|
|
999
1029
|
if (check)
|
|
@@ -1016,10 +1046,21 @@ export function updateSpecs(checked, check = false, options = {}) {
|
|
|
1016
1046
|
if (text !== checked.project.files.get(output.source)?.source)
|
|
1017
1047
|
throw new Error('Source changed during compilation; retry before generating specifications');
|
|
1018
1048
|
}
|
|
1049
|
+
else if (output.kind === 'native-descriptor') {
|
|
1050
|
+
// An unchanged descriptor from an earlier preview may be adopted. A
|
|
1051
|
+
// tracked copy must still match its recorded bytes before replacement.
|
|
1052
|
+
const tracked = previousDescriptors.get(output.path);
|
|
1053
|
+
if (tracked ? hash(text) !== tracked : text !== output.text)
|
|
1054
|
+
throw new Error(`Refusing to overwrite edited native descriptor ${output.path}`);
|
|
1055
|
+
}
|
|
1019
1056
|
else if (!text.startsWith(generated) && !text.startsWith(copied))
|
|
1020
1057
|
throw new Error(`Refusing to overwrite handwritten file ${output.path}`);
|
|
1021
1058
|
}
|
|
1022
1059
|
}
|
|
1060
|
+
for (const path of removed)
|
|
1061
|
+
if (previousDescriptors.has(path) &&
|
|
1062
|
+
(lstatSync(path).isSymbolicLink() || hash(readFileSync(path, 'utf8')) !== previousDescriptors.get(path)))
|
|
1063
|
+
throw new Error(`Refusing to remove edited native descriptor ${path}`);
|
|
1023
1064
|
for (const output of outputs) {
|
|
1024
1065
|
if (existsSync(output.path) && readFileSync(output.path, 'utf8') === output.text)
|
|
1025
1066
|
continue;
|
|
@@ -1038,7 +1079,7 @@ export function updateSpecs(checked, check = false, options = {}) {
|
|
|
1038
1079
|
}
|
|
1039
1080
|
for (const path of removed) {
|
|
1040
1081
|
const text = readFileSync(path, 'utf8');
|
|
1041
|
-
if (text.startsWith(generated) || text.startsWith(copied))
|
|
1082
|
+
if (previousDescriptors.has(path) || text.startsWith(generated) || text.startsWith(copied))
|
|
1042
1083
|
rmSync(path);
|
|
1043
1084
|
}
|
|
1044
1085
|
if (options.manifest !== false) {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|