@tsonic/frontend 0.0.62 → 0.0.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/dependency-graph.d.ts +1 -1
- package/dist/dependency-graph.d.ts.map +1 -1
- package/dist/dependency-graph.js +1 -1
- package/dist/dependency-graph.js.map +1 -1
- package/dist/dotnet-metadata.d.ts +0 -12
- package/dist/dotnet-metadata.d.ts.map +1 -1
- package/dist/dotnet-metadata.js +0 -24
- package/dist/dotnet-metadata.js.map +1 -1
- package/dist/generic-function-values.d.ts +11 -0
- package/dist/generic-function-values.d.ts.map +1 -0
- package/dist/generic-function-values.js +243 -0
- package/dist/generic-function-values.js.map +1 -0
- package/dist/generic-function-values.test.d.ts +2 -0
- package/dist/generic-function-values.test.d.ts.map +1 -0
- package/dist/generic-function-values.test.js +256 -0
- package/dist/generic-function-values.test.js.map +1 -0
- package/dist/graph/extraction/imports.d.ts +5 -0
- package/dist/graph/extraction/imports.d.ts.map +1 -1
- package/dist/graph/extraction/imports.js +30 -0
- package/dist/graph/extraction/imports.js.map +1 -1
- package/dist/graph/extraction/index.d.ts +1 -1
- package/dist/graph/extraction/index.d.ts.map +1 -1
- package/dist/graph/extraction/index.js +1 -1
- package/dist/graph/extraction/index.js.map +1 -1
- package/dist/graph/extraction/orchestrator.d.ts.map +1 -1
- package/dist/graph/extraction/orchestrator.js +16 -2
- package/dist/graph/extraction/orchestrator.js.map +1 -1
- package/dist/graph/extraction.d.ts +1 -1
- package/dist/graph/extraction.d.ts.map +1 -1
- package/dist/graph/extraction.js +1 -1
- package/dist/graph/extraction.js.map +1 -1
- package/dist/ir/binding/binding-factory.d.ts +17 -0
- package/dist/ir/binding/binding-factory.d.ts.map +1 -0
- package/dist/ir/binding/binding-factory.js +765 -0
- package/dist/ir/binding/binding-factory.js.map +1 -0
- package/dist/ir/binding/binding-helpers.d.ts +90 -0
- package/dist/ir/binding/binding-helpers.d.ts.map +1 -0
- package/dist/ir/binding/binding-helpers.js +387 -0
- package/dist/ir/binding/binding-helpers.js.map +1 -0
- package/dist/ir/binding/binding-types.d.ts +203 -0
- package/dist/ir/binding/binding-types.d.ts.map +1 -0
- package/dist/ir/binding/binding-types.js +9 -0
- package/dist/ir/binding/binding-types.js.map +1 -0
- package/dist/ir/binding/index.d.ts +4 -158
- package/dist/ir/binding/index.d.ts.map +1 -1
- package/dist/ir/binding/index.js +3 -1134
- package/dist/ir/binding/index.js.map +1 -1
- package/dist/ir/builder.test.js +223 -0
- package/dist/ir/builder.test.js.map +1 -1
- package/dist/ir/converters/anonymous-synthesis.d.ts +3 -3
- package/dist/ir/converters/anonymous-synthesis.d.ts.map +1 -1
- package/dist/ir/converters/anonymous-synthesis.js +45 -8
- package/dist/ir/converters/anonymous-synthesis.js.map +1 -1
- package/dist/ir/converters/expressions/access/access-converter.d.ts +14 -0
- package/dist/ir/converters/expressions/access/access-converter.d.ts.map +1 -0
- package/dist/ir/converters/expressions/access/access-converter.js +141 -0
- package/dist/ir/converters/expressions/access/access-converter.js.map +1 -0
- package/dist/ir/converters/expressions/access/binding-resolution.d.ts +35 -0
- package/dist/ir/converters/expressions/access/binding-resolution.d.ts.map +1 -0
- package/dist/ir/converters/expressions/access/binding-resolution.js +384 -0
- package/dist/ir/converters/expressions/access/binding-resolution.js.map +1 -0
- package/dist/ir/converters/expressions/access/member-resolution.d.ts +67 -0
- package/dist/ir/converters/expressions/access/member-resolution.d.ts.map +1 -0
- package/dist/ir/converters/expressions/access/member-resolution.js +262 -0
- package/dist/ir/converters/expressions/access/member-resolution.js.map +1 -0
- package/dist/ir/converters/expressions/access.d.ts +1 -7
- package/dist/ir/converters/expressions/access.d.ts.map +1 -1
- package/dist/ir/converters/expressions/access.js +1 -720
- package/dist/ir/converters/expressions/access.js.map +1 -1
- package/dist/ir/converters/expressions/calls/call-converter.d.ts +23 -0
- package/dist/ir/converters/expressions/calls/call-converter.d.ts.map +1 -0
- package/dist/ir/converters/expressions/calls/call-converter.js +526 -0
- package/dist/ir/converters/expressions/calls/call-converter.js.map +1 -0
- package/dist/ir/converters/expressions/calls/call-site-analysis.d.ts +53 -0
- package/dist/ir/converters/expressions/calls/call-site-analysis.d.ts.map +1 -0
- package/dist/ir/converters/expressions/calls/call-site-analysis.js +554 -0
- package/dist/ir/converters/expressions/calls/call-site-analysis.js.map +1 -0
- package/dist/ir/converters/expressions/calls/new-converter.d.ts +21 -0
- package/dist/ir/converters/expressions/calls/new-converter.d.ts.map +1 -0
- package/dist/ir/converters/expressions/calls/new-converter.js +182 -0
- package/dist/ir/converters/expressions/calls/new-converter.js.map +1 -0
- package/dist/ir/converters/expressions/calls.d.ts +2 -28
- package/dist/ir/converters/expressions/calls.d.ts.map +1 -1
- package/dist/ir/converters/expressions/calls.js +2 -1344
- package/dist/ir/converters/expressions/calls.js.map +1 -1
- package/dist/ir/converters/expressions/collections.d.ts.map +1 -1
- package/dist/ir/converters/expressions/collections.js +37 -6
- package/dist/ir/converters/expressions/collections.js.map +1 -1
- package/dist/ir/converters/expressions/functions.js +1 -1
- package/dist/ir/converters/expressions/functions.js.map +1 -1
- package/dist/ir/converters/expressions/helpers.d.ts.map +1 -1
- package/dist/ir/converters/expressions/helpers.js +1 -0
- package/dist/ir/converters/expressions/helpers.js.map +1 -1
- package/dist/ir/converters/expressions/other.d.ts.map +1 -1
- package/dist/ir/converters/expressions/other.js +3 -2
- package/dist/ir/converters/expressions/other.js.map +1 -1
- package/dist/ir/converters/flow-narrowing.d.ts.map +1 -1
- package/dist/ir/converters/flow-narrowing.js +3 -2
- package/dist/ir/converters/flow-narrowing.js.map +1 -1
- package/dist/ir/converters/statements/declarations/classes/methods.js +1 -1
- package/dist/ir/converters/statements/declarations/classes/methods.js.map +1 -1
- package/dist/ir/converters/statements/declarations/type-aliases.js +1 -1
- package/dist/ir/converters/statements/declarations/type-aliases.js.map +1 -1
- package/dist/ir/converters/statements/declarations/variables.d.ts +2 -2
- package/dist/ir/converters/statements/declarations/variables.d.ts.map +1 -1
- package/dist/ir/converters/statements/declarations/variables.js +289 -2
- package/dist/ir/converters/statements/declarations/variables.js.map +1 -1
- package/dist/ir/expression-converter.d.ts +0 -1
- package/dist/ir/expression-converter.d.ts.map +1 -1
- package/dist/ir/expression-converter.js +0 -2
- package/dist/ir/expression-converter.js.map +1 -1
- package/dist/ir/generic-function-value-lowering.test.d.ts +2 -0
- package/dist/ir/generic-function-value-lowering.test.d.ts.map +1 -0
- package/dist/ir/generic-function-value-lowering.test.js +312 -0
- package/dist/ir/generic-function-value-lowering.test.js.map +1 -0
- package/dist/ir/generic-validator.d.ts +3 -4
- package/dist/ir/generic-validator.d.ts.map +1 -1
- package/dist/ir/generic-validator.js +3 -35
- package/dist/ir/generic-validator.js.map +1 -1
- package/dist/ir/program-context.d.ts +7 -0
- package/dist/ir/program-context.d.ts.map +1 -1
- package/dist/ir/program-context.js +1 -0
- package/dist/ir/program-context.js.map +1 -1
- package/dist/ir/statement-converter.d.ts +0 -2
- package/dist/ir/statement-converter.d.ts.map +1 -1
- package/dist/ir/statement-converter.js +0 -3
- package/dist/ir/statement-converter.js.map +1 -1
- package/dist/ir/type-system/internal/handle-types.d.ts +16 -16
- package/dist/ir/type-system/internal/handle-types.d.ts.map +1 -1
- package/dist/ir/type-system/internal/nominal-env.d.ts +0 -2
- package/dist/ir/type-system/internal/nominal-env.d.ts.map +1 -1
- package/dist/ir/type-system/internal/nominal-env.js +2 -6
- package/dist/ir/type-system/internal/nominal-env.js.map +1 -1
- package/dist/ir/type-system/internal/type-converter/converter.d.ts +3 -1
- package/dist/ir/type-system/internal/type-converter/converter.d.ts.map +1 -1
- package/dist/ir/type-system/internal/type-converter/converter.js +3 -1
- package/dist/ir/type-system/internal/type-converter/converter.js.map +1 -1
- package/dist/ir/type-system/internal/type-converter/objects.js +7 -1
- package/dist/ir/type-system/internal/type-converter/objects.js.map +1 -1
- package/dist/ir/type-system/internal/type-converter/orchestrator.d.ts +0 -2
- package/dist/ir/type-system/internal/type-converter/orchestrator.d.ts.map +1 -1
- package/dist/ir/type-system/internal/type-converter/orchestrator.js +315 -23
- package/dist/ir/type-system/internal/type-converter/orchestrator.js.map +1 -1
- package/dist/ir/type-system/internal/type-converter/orchestrator.test.d.ts +2 -0
- package/dist/ir/type-system/internal/type-converter/orchestrator.test.d.ts.map +1 -0
- package/dist/ir/type-system/internal/type-converter/orchestrator.test.js +265 -0
- package/dist/ir/type-system/internal/type-converter/orchestrator.test.js.map +1 -0
- package/dist/ir/type-system/internal/type-converter/primitives.d.ts.map +1 -1
- package/dist/ir/type-system/internal/type-converter/primitives.js +5 -0
- package/dist/ir/type-system/internal/type-converter/primitives.js.map +1 -1
- package/dist/ir/type-system/internal/type-converter/references.d.ts.map +1 -1
- package/dist/ir/type-system/internal/type-converter/references.js +67 -29
- package/dist/ir/type-system/internal/type-converter/references.js.map +1 -1
- package/dist/ir/type-system/internal/type-converter/utility-types.d.ts.map +1 -1
- package/dist/ir/type-system/internal/type-converter/utility-types.js +145 -0
- package/dist/ir/type-system/internal/type-converter/utility-types.js.map +1 -1
- package/dist/ir/type-system/internal/type-converter/utility-types.test.js +91 -1
- package/dist/ir/type-system/internal/type-converter/utility-types.test.js.map +1 -1
- package/dist/ir/type-system/internal/type-registry.d.ts +1 -1
- package/dist/ir/type-system/internal/type-registry.js +7 -7
- package/dist/ir/type-system/internal/type-registry.js.map +1 -1
- package/dist/ir/type-system/internal/universe/alias-table.d.ts +0 -14
- package/dist/ir/type-system/internal/universe/alias-table.d.ts.map +1 -1
- package/dist/ir/type-system/internal/universe/alias-table.js +0 -17
- package/dist/ir/type-system/internal/universe/alias-table.js.map +1 -1
- package/dist/ir/type-system/internal/universe/clr-catalog.d.ts +3 -0
- package/dist/ir/type-system/internal/universe/clr-catalog.d.ts.map +1 -1
- package/dist/ir/type-system/internal/universe/clr-catalog.js +4 -1044
- package/dist/ir/type-system/internal/universe/clr-catalog.js.map +1 -1
- package/dist/ir/type-system/internal/universe/clr-entry-converter.d.ts +51 -0
- package/dist/ir/type-system/internal/universe/clr-entry-converter.d.ts.map +1 -0
- package/dist/ir/type-system/internal/universe/clr-entry-converter.js +657 -0
- package/dist/ir/type-system/internal/universe/clr-entry-converter.js.map +1 -0
- package/dist/ir/type-system/internal/universe/clr-type-parser.d.ts +52 -0
- package/dist/ir/type-system/internal/universe/clr-type-parser.d.ts.map +1 -0
- package/dist/ir/type-system/internal/universe/clr-type-parser.js +415 -0
- package/dist/ir/type-system/internal/universe/clr-type-parser.js.map +1 -0
- package/dist/ir/type-system/internal/universe/index.d.ts +1 -1
- package/dist/ir/type-system/internal/universe/index.d.ts.map +1 -1
- package/dist/ir/type-system/internal/universe/index.js +1 -3
- package/dist/ir/type-system/internal/universe/index.js.map +1 -1
- package/dist/ir/type-system/internal/universe/unified-universe.test.js +2 -0
- package/dist/ir/type-system/internal/universe/unified-universe.test.js.map +1 -1
- package/dist/ir/type-system/type-system-call-resolution.d.ts +69 -0
- package/dist/ir/type-system/type-system-call-resolution.d.ts.map +1 -0
- package/dist/ir/type-system/type-system-call-resolution.js +1121 -0
- package/dist/ir/type-system/type-system-call-resolution.js.map +1 -0
- package/dist/ir/type-system/type-system-inference.d.ts +98 -0
- package/dist/ir/type-system/type-system-inference.d.ts.map +1 -0
- package/dist/ir/type-system/type-system-inference.js +1083 -0
- package/dist/ir/type-system/type-system-inference.js.map +1 -0
- package/dist/ir/type-system/type-system-relations.d.ts +15 -0
- package/dist/ir/type-system/type-system-relations.d.ts.map +1 -0
- package/dist/ir/type-system/type-system-relations.js +152 -0
- package/dist/ir/type-system/type-system-relations.js.map +1 -0
- package/dist/ir/type-system/type-system-state.d.ts +436 -0
- package/dist/ir/type-system/type-system-state.d.ts.map +1 -0
- package/dist/ir/type-system/type-system-state.js +212 -0
- package/dist/ir/type-system/type-system-state.js.map +1 -0
- package/dist/ir/type-system/type-system-utilities.d.ts +56 -0
- package/dist/ir/type-system/type-system-utilities.d.ts.map +1 -0
- package/dist/ir/type-system/type-system-utilities.js +373 -0
- package/dist/ir/type-system/type-system-utilities.js.map +1 -0
- package/dist/ir/type-system/type-system.d.ts +17 -358
- package/dist/ir/type-system/type-system.d.ts.map +1 -1
- package/dist/ir/type-system/type-system.js +67 -2945
- package/dist/ir/type-system/type-system.js.map +1 -1
- package/dist/ir/types/index.d.ts +1 -0
- package/dist/ir/types/index.d.ts.map +1 -1
- package/dist/ir/types/index.js +1 -0
- package/dist/ir/types/index.js.map +1 -1
- package/dist/ir/types/ir-substitution.js +1 -1
- package/dist/ir/types/ir-substitution.js.map +1 -1
- package/dist/ir/types/statements.d.ts +1 -1
- package/dist/ir/types/type-ops.d.ts +9 -0
- package/dist/ir/types/type-ops.d.ts.map +1 -0
- package/dist/ir/types/type-ops.js +134 -0
- package/dist/ir/types/type-ops.js.map +1 -0
- package/dist/ir/types/type-ops.test.d.ts +2 -0
- package/dist/ir/types/type-ops.test.d.ts.map +1 -0
- package/dist/ir/types/type-ops.test.js +73 -0
- package/dist/ir/types/type-ops.test.js.map +1 -0
- package/dist/ir/validation/attribute-collection/arg-extractor.d.ts +58 -0
- package/dist/ir/validation/attribute-collection/arg-extractor.d.ts.map +1 -0
- package/dist/ir/validation/attribute-collection/arg-extractor.js +284 -0
- package/dist/ir/validation/attribute-collection/arg-extractor.js.map +1 -0
- package/dist/ir/validation/attribute-collection/marker-parser.d.ts +28 -0
- package/dist/ir/validation/attribute-collection/marker-parser.d.ts.map +1 -0
- package/dist/ir/validation/attribute-collection/marker-parser.js +404 -0
- package/dist/ir/validation/attribute-collection/marker-parser.js.map +1 -0
- package/dist/ir/validation/attribute-collection/orchestrator.d.ts +28 -0
- package/dist/ir/validation/attribute-collection/orchestrator.d.ts.map +1 -0
- package/dist/ir/validation/attribute-collection/orchestrator.js +332 -0
- package/dist/ir/validation/attribute-collection/orchestrator.js.map +1 -0
- package/dist/ir/validation/attribute-collection-pass.d.ts +1 -23
- package/dist/ir/validation/attribute-collection-pass.d.ts.map +1 -1
- package/dist/ir/validation/attribute-collection-pass.js +1 -961
- package/dist/ir/validation/attribute-collection-pass.js.map +1 -1
- package/dist/ir/validation/attribute-collection-pass.test.js +12 -6
- package/dist/ir/validation/attribute-collection-pass.test.js.map +1 -1
- package/dist/ir/validation/soundness-gate.d.ts.map +1 -1
- package/dist/ir/validation/soundness-gate.js +2 -1
- package/dist/ir/validation/soundness-gate.js.map +1 -1
- package/dist/ir/validation/soundness-gate.test.js +69 -0
- package/dist/ir/validation/soundness-gate.test.js.map +1 -1
- package/dist/ir/validation/yield-lowering-pass.d.ts +11 -5
- package/dist/ir/validation/yield-lowering-pass.d.ts.map +1 -1
- package/dist/ir/validation/yield-lowering-pass.js +942 -48
- package/dist/ir/validation/yield-lowering-pass.js.map +1 -1
- package/dist/ir/validation/yield-lowering-pass.test.js +1333 -127
- package/dist/ir/validation/yield-lowering-pass.test.js.map +1 -1
- package/dist/program/binding-loader.d.ts +37 -0
- package/dist/program/binding-loader.d.ts.map +1 -0
- package/dist/program/binding-loader.js +155 -0
- package/dist/program/binding-loader.js.map +1 -0
- package/dist/program/binding-registry.d.ts +106 -0
- package/dist/program/binding-registry.d.ts.map +1 -0
- package/dist/program/binding-registry.js +590 -0
- package/dist/program/binding-registry.js.map +1 -0
- package/dist/program/binding-types.d.ts +166 -0
- package/dist/program/binding-types.d.ts.map +1 -0
- package/dist/program/binding-types.js +57 -0
- package/dist/program/binding-types.js.map +1 -0
- package/dist/program/bindings.d.ts +6 -271
- package/dist/program/bindings.d.ts.map +1 -1
- package/dist/program/bindings.js +7 -781
- package/dist/program/bindings.js.map +1 -1
- package/dist/resolver/clr-bindings-resolver.d.ts +0 -1
- package/dist/resolver/clr-bindings-resolver.d.ts.map +1 -1
- package/dist/resolver/clr-bindings-resolver.js +22 -32
- package/dist/resolver/clr-bindings-resolver.js.map +1 -1
- package/dist/resolver/clr-bindings-resolver.test.js +0 -27
- package/dist/resolver/clr-bindings-resolver.test.js.map +1 -1
- package/dist/resolver/import-resolution.d.ts +1 -1
- package/dist/resolver/import-resolution.d.ts.map +1 -1
- package/dist/resolver/import-resolution.js +2 -7
- package/dist/resolver/import-resolution.js.map +1 -1
- package/dist/resolver/naming.d.ts.map +1 -1
- package/dist/resolver/naming.js +1 -0
- package/dist/resolver/naming.js.map +1 -1
- package/dist/types/diagnostic.d.ts +1 -1
- package/dist/types/diagnostic.d.ts.map +1 -1
- package/dist/types/diagnostic.js.map +1 -1
- package/dist/validation/features.d.ts.map +1 -1
- package/dist/validation/features.js +38 -13
- package/dist/validation/features.js.map +1 -1
- package/dist/validation/features.test.d.ts +2 -0
- package/dist/validation/features.test.d.ts.map +1 -0
- package/dist/validation/features.test.js +273 -0
- package/dist/validation/features.test.js.map +1 -0
- package/dist/validation/generics.d.ts +1 -1
- package/dist/validation/generics.d.ts.map +1 -1
- package/dist/validation/generics.js +2 -26
- package/dist/validation/generics.js.map +1 -1
- package/dist/validation/imports.d.ts.map +1 -1
- package/dist/validation/imports.js +2 -1
- package/dist/validation/imports.js.map +1 -1
- package/dist/validation/imports.test.d.ts +2 -0
- package/dist/validation/imports.test.d.ts.map +1 -0
- package/dist/validation/imports.test.js +112 -0
- package/dist/validation/imports.test.js.map +1 -0
- package/dist/validation/static-safety.d.ts +6 -6
- package/dist/validation/static-safety.d.ts.map +1 -1
- package/dist/validation/static-safety.js +163 -109
- package/dist/validation/static-safety.js.map +1 -1
- package/dist/validation/unsupported-utility-types.d.ts +3 -3
- package/dist/validation/unsupported-utility-types.d.ts.map +1 -1
- package/dist/validation/unsupported-utility-types.js +4 -7
- package/dist/validation/unsupported-utility-types.js.map +1 -1
- package/dist/validator.maximus.test.d.ts +2 -0
- package/dist/validator.maximus.test.d.ts.map +1 -0
- package/dist/validator.maximus.test.js +1214 -0
- package/dist/validator.maximus.test.js.map +1 -0
- package/dist/validator.test.js +152 -18
- package/dist/validator.test.js.map +1 -1
- package/package.json +1 -1
- package/dist/ir/converters/statements/declarations/registry.d.ts +0 -96
- package/dist/ir/converters/statements/declarations/registry.d.ts.map +0 -1
- package/dist/ir/converters/statements/declarations/registry.js +0 -130
- package/dist/ir/converters/statements/declarations/registry.js.map +0 -1
- package/dist/ir/this-parameter-inference.test.d.ts +0 -13
- package/dist/ir/this-parameter-inference.test.d.ts.map +0 -1
- package/dist/ir/this-parameter-inference.test.js +0 -165
- package/dist/ir/this-parameter-inference.test.js.map +0 -1
- package/dist/metadata/bindings-loader.d.ts +0 -41
- package/dist/metadata/bindings-loader.d.ts.map +0 -1
- package/dist/metadata/bindings-loader.js +0 -308
- package/dist/metadata/bindings-loader.js.map +0 -1
- package/dist/metadata/bindings-loader.test.d.ts +0 -5
- package/dist/metadata/bindings-loader.test.d.ts.map +0 -1
- package/dist/metadata/bindings-loader.test.js +0 -117
- package/dist/metadata/bindings-loader.test.js.map +0 -1
- package/dist/metadata/index.d.ts +0 -8
- package/dist/metadata/index.d.ts.map +0 -1
- package/dist/metadata/index.js +0 -7
- package/dist/metadata/index.js.map +0 -1
- package/dist/metadata/library-loader.d.ts +0 -42
- package/dist/metadata/library-loader.d.ts.map +0 -1
- package/dist/metadata/library-loader.js +0 -126
- package/dist/metadata/library-loader.js.map +0 -1
- package/dist/metadata/loader.d.ts +0 -26
- package/dist/metadata/loader.d.ts.map +0 -1
- package/dist/metadata/loader.js +0 -333
- package/dist/metadata/loader.js.map +0 -1
- package/dist/metadata/loader.test.d.ts +0 -5
- package/dist/metadata/loader.test.d.ts.map +0 -1
- package/dist/metadata/loader.test.js +0 -119
- package/dist/metadata/loader.test.js.map +0 -1
- package/dist/resolver/naming-policy.d.ts +0 -20
- package/dist/resolver/naming-policy.d.ts.map +0 -1
- package/dist/resolver/naming-policy.js +0 -40
- package/dist/resolver/naming-policy.js.map +0 -1
- package/dist/types/bindings.d.ts +0 -153
- package/dist/types/bindings.d.ts.map +0 -1
- package/dist/types/bindings.js +0 -14
- package/dist/types/bindings.js.map +0 -1
- package/dist/types/metadata.d.ts +0 -196
- package/dist/types/metadata.d.ts.map +0 -1
- package/dist/types/metadata.js +0 -10
- package/dist/types/metadata.js.map +0 -1
- package/dist/types/nested-types.d.ts +0 -111
- package/dist/types/nested-types.d.ts.map +0 -1
- package/dist/types/nested-types.js +0 -176
- package/dist/types/nested-types.js.map +0 -1
- package/dist/types/nested-types.test.d.ts +0 -5
- package/dist/types/nested-types.test.d.ts.map +0 -1
- package/dist/types/nested-types.test.js +0 -135
- package/dist/types/nested-types.test.js.map +0 -1
- package/dist/types/ref-parameters.d.ts +0 -123
- package/dist/types/ref-parameters.d.ts.map +0 -1
- package/dist/types/ref-parameters.js +0 -203
- package/dist/types/ref-parameters.js.map +0 -1
- package/dist/types/ref-parameters.test.d.ts +0 -5
- package/dist/types/ref-parameters.test.d.ts.map +0 -1
- package/dist/types/ref-parameters.test.js +0 -147
- package/dist/types/ref-parameters.test.js.map +0 -1
|
@@ -12,969 +12,9 @@
|
|
|
12
12
|
* - add(A.attr(AttrCtor, ...args)) - Descriptor form
|
|
13
13
|
* - add(descriptor) where `const descriptor = A.attr(...)`
|
|
14
14
|
*
|
|
15
|
-
* Backward compatibility:
|
|
16
|
-
* - A.on(fn).type.add(AttrCtor, ...args) attaches to a function declaration
|
|
17
|
-
*
|
|
18
15
|
* Notes:
|
|
19
16
|
* - This API is compiler-only. All recognized marker statements are removed.
|
|
20
17
|
* - Invalid marker calls are errors (no silent drops).
|
|
21
18
|
*/
|
|
22
|
-
|
|
23
|
-
const ATTRIBUTES_IMPORT_SPECIFIER = "@tsonic/core/lang.js";
|
|
24
|
-
const ATTRIBUTE_TARGETS_EXPORT_NAME = "AttributeTargets";
|
|
25
|
-
const ATTRIBUTE_TARGETS = [
|
|
26
|
-
"assembly",
|
|
27
|
-
"module",
|
|
28
|
-
"type",
|
|
29
|
-
"method",
|
|
30
|
-
"property",
|
|
31
|
-
"field",
|
|
32
|
-
"event",
|
|
33
|
-
"param",
|
|
34
|
-
"return",
|
|
35
|
-
];
|
|
36
|
-
const ATTRIBUTE_TARGETS_SET = new Set(ATTRIBUTE_TARGETS);
|
|
37
|
-
/**
|
|
38
|
-
* Try to extract an attribute argument from an IR expression.
|
|
39
|
-
* Returns undefined if the expression is not a valid attribute argument.
|
|
40
|
-
*/
|
|
41
|
-
const tryExtractAttributeArg = (expr) => {
|
|
42
|
-
const tryExtractPrimitive = (e) => {
|
|
43
|
-
const extracted = tryExtractAttributeArg(e);
|
|
44
|
-
if (!extracted)
|
|
45
|
-
return undefined;
|
|
46
|
-
if (extracted.kind === "array")
|
|
47
|
-
return undefined;
|
|
48
|
-
return extracted;
|
|
49
|
-
};
|
|
50
|
-
if (expr.kind === "literal") {
|
|
51
|
-
if (typeof expr.value === "string") {
|
|
52
|
-
return { kind: "string", value: expr.value };
|
|
53
|
-
}
|
|
54
|
-
if (typeof expr.value === "number") {
|
|
55
|
-
return { kind: "number", value: expr.value };
|
|
56
|
-
}
|
|
57
|
-
if (typeof expr.value === "boolean") {
|
|
58
|
-
return { kind: "boolean", value: expr.value };
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
// Arrays of compile-time constants are valid attribute arguments in C#.
|
|
62
|
-
// Example: [Index(new[] { "PropertyId", "Ts" })]
|
|
63
|
-
if (expr.kind === "array") {
|
|
64
|
-
const arr = expr;
|
|
65
|
-
const elements = [];
|
|
66
|
-
if (arr.elements.length === 0)
|
|
67
|
-
return undefined;
|
|
68
|
-
for (const el of arr.elements) {
|
|
69
|
-
if (!el || el.kind === "spread") {
|
|
70
|
-
return undefined;
|
|
71
|
-
}
|
|
72
|
-
const v = tryExtractPrimitive(el);
|
|
73
|
-
if (!v)
|
|
74
|
-
return undefined;
|
|
75
|
-
elements.push(v);
|
|
76
|
-
}
|
|
77
|
-
return { kind: "array", elements };
|
|
78
|
-
}
|
|
79
|
-
// typeof(SomeType) → C# typeof(SomeType) attribute argument
|
|
80
|
-
if (expr.kind === "unary" && expr.operator === "typeof") {
|
|
81
|
-
const targetType = expr.expression.inferredType;
|
|
82
|
-
if (targetType && targetType.kind !== "unknownType") {
|
|
83
|
-
return { kind: "typeof", type: targetType };
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
// Enum.Member → enum literal argument
|
|
87
|
-
if (expr.kind === "memberAccess" &&
|
|
88
|
-
!expr.isComputed &&
|
|
89
|
-
typeof expr.property === "string") {
|
|
90
|
-
const object = expr.object;
|
|
91
|
-
const enumType = expr.inferredType && expr.inferredType.kind === "referenceType"
|
|
92
|
-
? expr.inferredType
|
|
93
|
-
: object.kind === "identifier" &&
|
|
94
|
-
object.inferredType &&
|
|
95
|
-
object.inferredType.kind === "referenceType"
|
|
96
|
-
? object.inferredType
|
|
97
|
-
: undefined;
|
|
98
|
-
if (enumType) {
|
|
99
|
-
const binding = expr.memberBinding;
|
|
100
|
-
const member = binding?.member ?? expr.property;
|
|
101
|
-
return { kind: "enum", type: enumType, member };
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return undefined;
|
|
105
|
-
};
|
|
106
|
-
const getAttributesApiLocalNames = (module) => {
|
|
107
|
-
const names = new Set();
|
|
108
|
-
for (const imp of module.imports) {
|
|
109
|
-
if (imp.source !== ATTRIBUTES_IMPORT_SPECIFIER)
|
|
110
|
-
continue;
|
|
111
|
-
for (const spec of imp.specifiers) {
|
|
112
|
-
if (spec.kind !== "named")
|
|
113
|
-
continue;
|
|
114
|
-
if (spec.name !== "attributes")
|
|
115
|
-
continue;
|
|
116
|
-
names.add(spec.localName);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return names;
|
|
120
|
-
};
|
|
121
|
-
const getAttributeTargetsApiLocalNames = (module) => {
|
|
122
|
-
const names = new Set();
|
|
123
|
-
for (const imp of module.imports) {
|
|
124
|
-
if (imp.source !== ATTRIBUTES_IMPORT_SPECIFIER)
|
|
125
|
-
continue;
|
|
126
|
-
for (const spec of imp.specifiers) {
|
|
127
|
-
if (spec.kind !== "named")
|
|
128
|
-
continue;
|
|
129
|
-
if (spec.name !== ATTRIBUTE_TARGETS_EXPORT_NAME)
|
|
130
|
-
continue;
|
|
131
|
-
names.add(spec.localName);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
return names;
|
|
135
|
-
};
|
|
136
|
-
const isAttributesApiIdentifier = (expr, apiNames) => expr.kind === "identifier" && apiNames.has(expr.name);
|
|
137
|
-
const parseAttributeTarget = (expr, module, attributeTargetsApiNames) => {
|
|
138
|
-
const fail = (message) => ({
|
|
139
|
-
kind: "error",
|
|
140
|
-
diagnostic: createDiagnostic("TSN4005", "error", message, createLocation(module.filePath, expr.sourceSpan)),
|
|
141
|
-
});
|
|
142
|
-
// Allow string literal: .target("return")
|
|
143
|
-
if (expr.kind === "literal" && typeof expr.value === "string") {
|
|
144
|
-
const value = expr.value;
|
|
145
|
-
if (ATTRIBUTE_TARGETS_SET.has(value)) {
|
|
146
|
-
return { kind: "ok", value: value };
|
|
147
|
-
}
|
|
148
|
-
return fail(`Invalid attribute target '${value}'. Expected one of: ${ATTRIBUTE_TARGETS.join(", ")}`);
|
|
149
|
-
}
|
|
150
|
-
// Allow AttributeTargets.return (imported local name can be aliased)
|
|
151
|
-
if (expr.kind === "memberAccess" &&
|
|
152
|
-
!expr.isComputed &&
|
|
153
|
-
typeof expr.property === "string" &&
|
|
154
|
-
expr.object.kind === "identifier" &&
|
|
155
|
-
attributeTargetsApiNames.has(expr.object.name)) {
|
|
156
|
-
const value = expr.property;
|
|
157
|
-
if (ATTRIBUTE_TARGETS_SET.has(value)) {
|
|
158
|
-
return { kind: "ok", value: value };
|
|
159
|
-
}
|
|
160
|
-
return fail(`Invalid attribute target '${value}'. Expected one of: ${ATTRIBUTE_TARGETS.join(", ")}`);
|
|
161
|
-
}
|
|
162
|
-
return fail(`Invalid attribute target. Expected a string literal (e.g., "return") or ${ATTRIBUTE_TARGETS_EXPORT_NAME}.<target>`);
|
|
163
|
-
};
|
|
164
|
-
const getMemberName = (expr) => {
|
|
165
|
-
if (expr.kind !== "memberAccess")
|
|
166
|
-
return undefined;
|
|
167
|
-
if (expr.isComputed)
|
|
168
|
-
return undefined;
|
|
169
|
-
if (typeof expr.property !== "string")
|
|
170
|
-
return undefined;
|
|
171
|
-
return expr.property;
|
|
172
|
-
};
|
|
173
|
-
const looksLikeAttributesApiUsage = (expr, apiNames) => {
|
|
174
|
-
switch (expr.kind) {
|
|
175
|
-
case "call":
|
|
176
|
-
return (looksLikeAttributesApiUsage(expr.callee, apiNames) ||
|
|
177
|
-
expr.arguments.some((arg) => arg.kind !== "spread" && looksLikeAttributesApiUsage(arg, apiNames)));
|
|
178
|
-
case "memberAccess":
|
|
179
|
-
return (looksLikeAttributesApiUsage(expr.object, apiNames) ||
|
|
180
|
-
(typeof expr.property === "string" &&
|
|
181
|
-
(expr.property === "on" || expr.property === "attr") &&
|
|
182
|
-
isAttributesApiIdentifier(expr.object, apiNames)));
|
|
183
|
-
case "arrowFunction":
|
|
184
|
-
return ((expr.body.kind === "blockStatement"
|
|
185
|
-
? expr.body.statements.some((s) => s.kind === "expressionStatement" &&
|
|
186
|
-
looksLikeAttributesApiUsage(s.expression, apiNames))
|
|
187
|
-
: looksLikeAttributesApiUsage(expr.body, apiNames)) || false);
|
|
188
|
-
case "functionExpression":
|
|
189
|
-
return expr.body.statements.some((s) => s.kind === "expressionStatement" &&
|
|
190
|
-
looksLikeAttributesApiUsage(s.expression, apiNames));
|
|
191
|
-
case "array":
|
|
192
|
-
return expr.elements.some((el) => el !== undefined &&
|
|
193
|
-
el.kind !== "spread" &&
|
|
194
|
-
looksLikeAttributesApiUsage(el, apiNames));
|
|
195
|
-
case "object":
|
|
196
|
-
return expr.properties.some((p) => {
|
|
197
|
-
if (p.kind === "spread")
|
|
198
|
-
return looksLikeAttributesApiUsage(p.expression, apiNames);
|
|
199
|
-
if (typeof p.key !== "string")
|
|
200
|
-
return looksLikeAttributesApiUsage(p.key, apiNames);
|
|
201
|
-
return looksLikeAttributesApiUsage(p.value, apiNames);
|
|
202
|
-
});
|
|
203
|
-
default:
|
|
204
|
-
return false;
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
|
-
const parseOnCall = (expr, module, apiNames) => {
|
|
208
|
-
if (expr.kind !== "call")
|
|
209
|
-
return { kind: "notMatch" };
|
|
210
|
-
const call = expr;
|
|
211
|
-
if (call.callee.kind !== "memberAccess")
|
|
212
|
-
return { kind: "notMatch" };
|
|
213
|
-
const member = call.callee;
|
|
214
|
-
if (member.isComputed || typeof member.property !== "string")
|
|
215
|
-
return { kind: "notMatch" };
|
|
216
|
-
if (member.property !== "on")
|
|
217
|
-
return { kind: "notMatch" };
|
|
218
|
-
if (!isAttributesApiIdentifier(member.object, apiNames))
|
|
219
|
-
return { kind: "notMatch" };
|
|
220
|
-
if (call.arguments.length !== 1) {
|
|
221
|
-
return {
|
|
222
|
-
kind: "error",
|
|
223
|
-
diagnostic: createDiagnostic("TSN4005", "error", `Invalid attribute marker: A.on(...) expects exactly 1 argument`, createLocation(module.filePath, call.sourceSpan)),
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
const arg0 = call.arguments[0];
|
|
227
|
-
if (!arg0 || arg0.kind === "spread") {
|
|
228
|
-
return {
|
|
229
|
-
kind: "error",
|
|
230
|
-
diagnostic: createDiagnostic("TSN4005", "error", `Invalid attribute marker: A.on(...) does not accept spread arguments`, createLocation(module.filePath, call.sourceSpan)),
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
if (arg0.kind !== "identifier") {
|
|
234
|
-
return {
|
|
235
|
-
kind: "error",
|
|
236
|
-
diagnostic: createDiagnostic("TSN4005", "error", `Invalid attribute marker: A.on(Target) target must be an identifier`, createLocation(module.filePath, call.sourceSpan)),
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
return {
|
|
240
|
-
kind: "ok",
|
|
241
|
-
value: {
|
|
242
|
-
target: arg0,
|
|
243
|
-
sourceSpan: call.sourceSpan,
|
|
244
|
-
},
|
|
245
|
-
};
|
|
246
|
-
};
|
|
247
|
-
const parseSelector = (selector, module) => {
|
|
248
|
-
if (selector.kind !== "arrowFunction") {
|
|
249
|
-
return {
|
|
250
|
-
kind: "error",
|
|
251
|
-
diagnostic: createDiagnostic("TSN4005", "error", `Invalid attribute marker: selector must be an arrow function (x => x.member)`, createLocation(module.filePath, selector.sourceSpan)),
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
const fn = selector;
|
|
255
|
-
if (fn.parameters.length !== 1) {
|
|
256
|
-
return {
|
|
257
|
-
kind: "error",
|
|
258
|
-
diagnostic: createDiagnostic("TSN4005", "error", `Invalid attribute marker: selector must have exactly 1 parameter`, createLocation(module.filePath, fn.sourceSpan)),
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
const p0 = fn.parameters[0];
|
|
262
|
-
if (!p0 || p0.pattern.kind !== "identifierPattern") {
|
|
263
|
-
return {
|
|
264
|
-
kind: "error",
|
|
265
|
-
diagnostic: createDiagnostic("TSN4005", "error", `Invalid attribute marker: selector parameter must be an identifier`, createLocation(module.filePath, fn.sourceSpan)),
|
|
266
|
-
};
|
|
267
|
-
}
|
|
268
|
-
const paramName = p0.pattern.name;
|
|
269
|
-
if (fn.body.kind !== "memberAccess") {
|
|
270
|
-
return {
|
|
271
|
-
kind: "error",
|
|
272
|
-
diagnostic: createDiagnostic("TSN4005", "error", `Invalid attribute marker: selector body must be a member access (x => x.member)`, createLocation(module.filePath, fn.sourceSpan)),
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
const body = fn.body;
|
|
276
|
-
if (body.isComputed || typeof body.property !== "string") {
|
|
277
|
-
return {
|
|
278
|
-
kind: "error",
|
|
279
|
-
diagnostic: createDiagnostic("TSN4005", "error", `Invalid attribute marker: selector must access a named member (no computed access)`, createLocation(module.filePath, fn.sourceSpan)),
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
if (body.object.kind !== "identifier" || body.object.name !== paramName) {
|
|
283
|
-
return {
|
|
284
|
-
kind: "error",
|
|
285
|
-
diagnostic: createDiagnostic("TSN4005", "error", `Invalid attribute marker: selector must be of the form (x) => x.member`, createLocation(module.filePath, fn.sourceSpan)),
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
return { kind: "ok", value: body.property };
|
|
289
|
-
};
|
|
290
|
-
const resolveClrTypeForAttributeCtor = (ctorIdent, module) => {
|
|
291
|
-
if (ctorIdent.resolvedClrType)
|
|
292
|
-
return ctorIdent.resolvedClrType;
|
|
293
|
-
// Prefer CLR imports: these are the authoritative mapping for runtime type names.
|
|
294
|
-
for (const imp of module.imports) {
|
|
295
|
-
if (!imp.isClr)
|
|
296
|
-
continue;
|
|
297
|
-
if (!imp.resolvedNamespace)
|
|
298
|
-
continue;
|
|
299
|
-
for (const spec of imp.specifiers) {
|
|
300
|
-
if (spec.kind !== "named")
|
|
301
|
-
continue;
|
|
302
|
-
if (spec.localName !== ctorIdent.name)
|
|
303
|
-
continue;
|
|
304
|
-
return `${imp.resolvedNamespace}.${spec.name}`;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
return undefined;
|
|
308
|
-
};
|
|
309
|
-
const makeAttributeType = (ctorIdent, module) => {
|
|
310
|
-
const resolvedClrType = resolveClrTypeForAttributeCtor(ctorIdent, module);
|
|
311
|
-
if (resolvedClrType) {
|
|
312
|
-
return {
|
|
313
|
-
kind: "ok",
|
|
314
|
-
value: {
|
|
315
|
-
kind: "referenceType",
|
|
316
|
-
name: ctorIdent.name,
|
|
317
|
-
resolvedClrType,
|
|
318
|
-
},
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
// Allow locally-emitted attribute types (non-ambient class declarations).
|
|
322
|
-
const hasLocalClass = module.body.some((s) => s.kind === "classDeclaration" && s.name === ctorIdent.name);
|
|
323
|
-
if (hasLocalClass) {
|
|
324
|
-
return {
|
|
325
|
-
kind: "ok",
|
|
326
|
-
value: { kind: "referenceType", name: ctorIdent.name },
|
|
327
|
-
};
|
|
328
|
-
}
|
|
329
|
-
return {
|
|
330
|
-
kind: "error",
|
|
331
|
-
diagnostic: createDiagnostic("TSN4004", "error", `Missing CLR binding for attribute constructor '${ctorIdent.name}'. Import the attribute type from a CLR bindings module (e.g., @tsonic/dotnet) or define it as a local class.`, createLocation(module.filePath, ctorIdent.sourceSpan)),
|
|
332
|
-
};
|
|
333
|
-
};
|
|
334
|
-
const parseAttrDescriptorCall = (expr, module, apiNames) => {
|
|
335
|
-
if (expr.kind !== "call")
|
|
336
|
-
return { kind: "notMatch" };
|
|
337
|
-
const call = expr;
|
|
338
|
-
if (call.callee.kind !== "memberAccess")
|
|
339
|
-
return { kind: "notMatch" };
|
|
340
|
-
const member = call.callee;
|
|
341
|
-
if (member.isComputed || typeof member.property !== "string")
|
|
342
|
-
return { kind: "notMatch" };
|
|
343
|
-
if (member.property !== "attr")
|
|
344
|
-
return { kind: "notMatch" };
|
|
345
|
-
if (!isAttributesApiIdentifier(member.object, apiNames))
|
|
346
|
-
return { kind: "notMatch" };
|
|
347
|
-
if (call.arguments.length < 1) {
|
|
348
|
-
return {
|
|
349
|
-
kind: "error",
|
|
350
|
-
diagnostic: createDiagnostic("TSN4005", "error", `Invalid attribute marker: A.attr(AttrCtor, ...args) requires at least the attribute constructor`, createLocation(module.filePath, call.sourceSpan)),
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
const rawArgs = [];
|
|
354
|
-
for (const arg of call.arguments) {
|
|
355
|
-
if (!arg || arg.kind === "spread") {
|
|
356
|
-
return {
|
|
357
|
-
kind: "error",
|
|
358
|
-
diagnostic: createDiagnostic("TSN4006", "error", `Invalid attribute argument: spreads are not allowed in attributes`, createLocation(module.filePath, call.sourceSpan)),
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
rawArgs.push(arg);
|
|
362
|
-
}
|
|
363
|
-
const ctorExpr = rawArgs[0];
|
|
364
|
-
if (!ctorExpr || ctorExpr.kind !== "identifier") {
|
|
365
|
-
return {
|
|
366
|
-
kind: "error",
|
|
367
|
-
diagnostic: createDiagnostic("TSN4005", "error", `Invalid attribute marker: A.attr(...) attribute constructor must be an identifier`, createLocation(module.filePath, call.sourceSpan)),
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
const attributeCtor = ctorExpr;
|
|
371
|
-
const attributeTypeResult = makeAttributeType(attributeCtor, module);
|
|
372
|
-
if (attributeTypeResult.kind !== "ok") {
|
|
373
|
-
return attributeTypeResult;
|
|
374
|
-
}
|
|
375
|
-
const positionalArgs = [];
|
|
376
|
-
const namedArgs = new Map();
|
|
377
|
-
let sawNamed = false;
|
|
378
|
-
for (const arg of rawArgs.slice(1)) {
|
|
379
|
-
if (arg.kind === "object") {
|
|
380
|
-
sawNamed = true;
|
|
381
|
-
const obj = arg;
|
|
382
|
-
for (const prop of obj.properties) {
|
|
383
|
-
if (prop.kind === "spread") {
|
|
384
|
-
return {
|
|
385
|
-
kind: "error",
|
|
386
|
-
diagnostic: createDiagnostic("TSN4006", "error", `Invalid attribute argument: spreads are not allowed in named arguments`, createLocation(module.filePath, obj.sourceSpan)),
|
|
387
|
-
};
|
|
388
|
-
}
|
|
389
|
-
if (prop.kind !== "property" || typeof prop.key !== "string") {
|
|
390
|
-
return {
|
|
391
|
-
kind: "error",
|
|
392
|
-
diagnostic: createDiagnostic("TSN4006", "error", `Invalid attribute argument: named arguments must be simple { Name: value } properties`, createLocation(module.filePath, obj.sourceSpan)),
|
|
393
|
-
};
|
|
394
|
-
}
|
|
395
|
-
const v = tryExtractAttributeArg(prop.value);
|
|
396
|
-
if (!v) {
|
|
397
|
-
return {
|
|
398
|
-
kind: "error",
|
|
399
|
-
diagnostic: createDiagnostic("TSN4006", "error", `Invalid attribute argument: named argument '${prop.key}' must be a compile-time constant`, createLocation(module.filePath, prop.value.sourceSpan)),
|
|
400
|
-
};
|
|
401
|
-
}
|
|
402
|
-
namedArgs.set(prop.key, v);
|
|
403
|
-
}
|
|
404
|
-
continue;
|
|
405
|
-
}
|
|
406
|
-
if (sawNamed) {
|
|
407
|
-
return {
|
|
408
|
-
kind: "error",
|
|
409
|
-
diagnostic: createDiagnostic("TSN4006", "error", `Invalid attribute argument: positional arguments cannot appear after named arguments`, createLocation(module.filePath, arg.sourceSpan)),
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
|
-
const v = tryExtractAttributeArg(arg);
|
|
413
|
-
if (!v) {
|
|
414
|
-
return {
|
|
415
|
-
kind: "error",
|
|
416
|
-
diagnostic: createDiagnostic("TSN4006", "error", `Invalid attribute argument: attribute arguments must be compile-time constants (string/number/boolean/typeof/enum/array)`, createLocation(module.filePath, arg.sourceSpan)),
|
|
417
|
-
};
|
|
418
|
-
}
|
|
419
|
-
positionalArgs.push(v);
|
|
420
|
-
}
|
|
421
|
-
return {
|
|
422
|
-
kind: "ok",
|
|
423
|
-
value: {
|
|
424
|
-
attributeType: attributeTypeResult.value,
|
|
425
|
-
positionalArgs,
|
|
426
|
-
namedArgs,
|
|
427
|
-
sourceSpan: call.sourceSpan,
|
|
428
|
-
},
|
|
429
|
-
};
|
|
430
|
-
};
|
|
431
|
-
/**
|
|
432
|
-
* Try to detect if a call expression is an attribute marker pattern.
|
|
433
|
-
*
|
|
434
|
-
* Patterns:
|
|
435
|
-
* - A.on(Target).type.add(...)
|
|
436
|
-
* - A.on(Target).ctor.add(...)
|
|
437
|
-
* - A.on(Target).method(selector).add(...)
|
|
438
|
-
* - A.on(Target).prop(selector).add(...)
|
|
439
|
-
*/
|
|
440
|
-
const tryDetectAttributeMarker = (call, module, apiNames, attributeTargetsApiNames, descriptors) => {
|
|
441
|
-
if (call.callee.kind !== "memberAccess")
|
|
442
|
-
return { kind: "notMatch" };
|
|
443
|
-
const outerMember = call.callee;
|
|
444
|
-
if (outerMember.isComputed || typeof outerMember.property !== "string") {
|
|
445
|
-
return { kind: "notMatch" };
|
|
446
|
-
}
|
|
447
|
-
if (outerMember.property !== "add")
|
|
448
|
-
return { kind: "notMatch" };
|
|
449
|
-
// Optional `.target(...)` before `.add(...)`
|
|
450
|
-
let attributeTarget;
|
|
451
|
-
let selectorRoot = outerMember.object;
|
|
452
|
-
if (selectorRoot.kind === "call") {
|
|
453
|
-
const maybeTargetCall = selectorRoot;
|
|
454
|
-
if (maybeTargetCall.callee.kind === "memberAccess") {
|
|
455
|
-
const targetMember = maybeTargetCall.callee;
|
|
456
|
-
const prop = getMemberName(targetMember);
|
|
457
|
-
if (prop === "target") {
|
|
458
|
-
if (maybeTargetCall.arguments.length !== 1) {
|
|
459
|
-
return {
|
|
460
|
-
kind: "error",
|
|
461
|
-
diagnostic: createDiagnostic("TSN4005", "error", `Invalid attribute marker: .target(...) expects exactly 1 argument`, createLocation(module.filePath, maybeTargetCall.sourceSpan)),
|
|
462
|
-
};
|
|
463
|
-
}
|
|
464
|
-
const arg0 = maybeTargetCall.arguments[0];
|
|
465
|
-
if (!arg0 || arg0.kind === "spread") {
|
|
466
|
-
return {
|
|
467
|
-
kind: "error",
|
|
468
|
-
diagnostic: createDiagnostic("TSN4005", "error", `Invalid attribute marker: .target(...) does not accept spread arguments`, createLocation(module.filePath, maybeTargetCall.sourceSpan)),
|
|
469
|
-
};
|
|
470
|
-
}
|
|
471
|
-
const parsedTarget = parseAttributeTarget(arg0, module, attributeTargetsApiNames);
|
|
472
|
-
if (parsedTarget.kind !== "ok")
|
|
473
|
-
return parsedTarget;
|
|
474
|
-
attributeTarget = parsedTarget.value;
|
|
475
|
-
selectorRoot = targetMember.object;
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
// Determine the target selector: `.type`, `.ctor`, `.method(selector)`, `.prop(selector)`
|
|
480
|
-
let selector;
|
|
481
|
-
let selectedMemberName;
|
|
482
|
-
let onCallExpr;
|
|
483
|
-
if (selectorRoot.kind === "memberAccess") {
|
|
484
|
-
const targetMember = selectorRoot;
|
|
485
|
-
const prop = getMemberName(targetMember);
|
|
486
|
-
if (prop !== "type" && prop !== "ctor")
|
|
487
|
-
return { kind: "notMatch" };
|
|
488
|
-
selector = prop;
|
|
489
|
-
onCallExpr = targetMember.object;
|
|
490
|
-
}
|
|
491
|
-
else if (selectorRoot.kind === "call") {
|
|
492
|
-
const selectorCall = selectorRoot;
|
|
493
|
-
if (selectorCall.callee.kind !== "memberAccess")
|
|
494
|
-
return { kind: "notMatch" };
|
|
495
|
-
const selectorMember = selectorCall.callee;
|
|
496
|
-
const prop = getMemberName(selectorMember);
|
|
497
|
-
if (prop !== "method" && prop !== "prop")
|
|
498
|
-
return { kind: "notMatch" };
|
|
499
|
-
selector = prop;
|
|
500
|
-
if (selectorCall.arguments.length !== 1) {
|
|
501
|
-
return {
|
|
502
|
-
kind: "error",
|
|
503
|
-
diagnostic: createDiagnostic("TSN4005", "error", `Invalid attribute marker: .${prop}(selector) expects exactly 1 argument`, createLocation(module.filePath, selectorCall.sourceSpan)),
|
|
504
|
-
};
|
|
505
|
-
}
|
|
506
|
-
const arg0 = selectorCall.arguments[0];
|
|
507
|
-
if (!arg0 || arg0.kind === "spread") {
|
|
508
|
-
return {
|
|
509
|
-
kind: "error",
|
|
510
|
-
diagnostic: createDiagnostic("TSN4005", "error", `Invalid attribute marker: selector cannot be a spread argument`, createLocation(module.filePath, selectorCall.sourceSpan)),
|
|
511
|
-
};
|
|
512
|
-
}
|
|
513
|
-
const sel = parseSelector(arg0, module);
|
|
514
|
-
if (sel.kind !== "ok")
|
|
515
|
-
return sel;
|
|
516
|
-
selectedMemberName = sel.value;
|
|
517
|
-
onCallExpr = selectorMember.object;
|
|
518
|
-
}
|
|
519
|
-
else {
|
|
520
|
-
return { kind: "notMatch" };
|
|
521
|
-
}
|
|
522
|
-
if (!onCallExpr)
|
|
523
|
-
return { kind: "notMatch" };
|
|
524
|
-
const on = parseOnCall(onCallExpr, module, apiNames);
|
|
525
|
-
if (on.kind !== "ok")
|
|
526
|
-
return on;
|
|
527
|
-
const targetName = on.value.target.name;
|
|
528
|
-
// Parse `.add(...)` arguments
|
|
529
|
-
if (call.arguments.length < 1) {
|
|
530
|
-
return {
|
|
531
|
-
kind: "error",
|
|
532
|
-
diagnostic: createDiagnostic("TSN4005", "error", `Invalid attribute marker: .add(...) requires at least one argument`, createLocation(module.filePath, call.sourceSpan)),
|
|
533
|
-
};
|
|
534
|
-
}
|
|
535
|
-
const addArgs = [];
|
|
536
|
-
for (const arg of call.arguments) {
|
|
537
|
-
if (!arg || arg.kind === "spread") {
|
|
538
|
-
return {
|
|
539
|
-
kind: "error",
|
|
540
|
-
diagnostic: createDiagnostic("TSN4006", "error", `Invalid attribute argument: spreads are not allowed in attributes`, createLocation(module.filePath, call.sourceSpan)),
|
|
541
|
-
};
|
|
542
|
-
}
|
|
543
|
-
addArgs.push(arg);
|
|
544
|
-
}
|
|
545
|
-
const first = addArgs[0];
|
|
546
|
-
if (!first) {
|
|
547
|
-
return {
|
|
548
|
-
kind: "error",
|
|
549
|
-
diagnostic: createDiagnostic("TSN4005", "error", `Invalid attribute marker: .add(...) first argument is missing`, createLocation(module.filePath, call.sourceSpan)),
|
|
550
|
-
};
|
|
551
|
-
}
|
|
552
|
-
// .add(A.attr(...)) inline descriptor
|
|
553
|
-
if (addArgs.length === 1) {
|
|
554
|
-
const descCall = parseAttrDescriptorCall(first, module, apiNames);
|
|
555
|
-
if (descCall.kind === "ok") {
|
|
556
|
-
return {
|
|
557
|
-
kind: "ok",
|
|
558
|
-
value: {
|
|
559
|
-
targetName,
|
|
560
|
-
targetSelector: selector,
|
|
561
|
-
selectedMemberName,
|
|
562
|
-
attributeTarget,
|
|
563
|
-
attributeType: descCall.value.attributeType,
|
|
564
|
-
positionalArgs: descCall.value.positionalArgs,
|
|
565
|
-
namedArgs: descCall.value.namedArgs,
|
|
566
|
-
sourceSpan: call.sourceSpan,
|
|
567
|
-
},
|
|
568
|
-
};
|
|
569
|
-
}
|
|
570
|
-
// .add(descriptorVar)
|
|
571
|
-
if (first.kind === "identifier") {
|
|
572
|
-
const desc = descriptors.get(first.name);
|
|
573
|
-
if (desc) {
|
|
574
|
-
return {
|
|
575
|
-
kind: "ok",
|
|
576
|
-
value: {
|
|
577
|
-
targetName,
|
|
578
|
-
targetSelector: selector,
|
|
579
|
-
selectedMemberName,
|
|
580
|
-
attributeTarget,
|
|
581
|
-
attributeType: desc.attributeType,
|
|
582
|
-
positionalArgs: desc.positionalArgs,
|
|
583
|
-
namedArgs: desc.namedArgs,
|
|
584
|
-
sourceSpan: call.sourceSpan,
|
|
585
|
-
},
|
|
586
|
-
};
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
// .add(AttrCtor, ...args)
|
|
591
|
-
if (first.kind !== "identifier") {
|
|
592
|
-
return {
|
|
593
|
-
kind: "error",
|
|
594
|
-
diagnostic: createDiagnostic("TSN4005", "error", `Invalid attribute marker: .add(AttrCtor, ...args) requires attribute constructor to be an identifier`, createLocation(module.filePath, call.sourceSpan)),
|
|
595
|
-
};
|
|
596
|
-
}
|
|
597
|
-
const attributeTypeResult = makeAttributeType(first, module);
|
|
598
|
-
if (attributeTypeResult.kind !== "ok") {
|
|
599
|
-
return attributeTypeResult;
|
|
600
|
-
}
|
|
601
|
-
const positionalArgs = [];
|
|
602
|
-
const namedArgs = new Map();
|
|
603
|
-
let sawNamed = false;
|
|
604
|
-
for (const arg of addArgs.slice(1)) {
|
|
605
|
-
if (arg.kind === "object") {
|
|
606
|
-
sawNamed = true;
|
|
607
|
-
const obj = arg;
|
|
608
|
-
for (const prop of obj.properties) {
|
|
609
|
-
if (prop.kind === "spread") {
|
|
610
|
-
return {
|
|
611
|
-
kind: "error",
|
|
612
|
-
diagnostic: createDiagnostic("TSN4006", "error", `Invalid attribute argument: spreads are not allowed in named arguments`, createLocation(module.filePath, obj.sourceSpan)),
|
|
613
|
-
};
|
|
614
|
-
}
|
|
615
|
-
if (prop.kind !== "property" || typeof prop.key !== "string") {
|
|
616
|
-
return {
|
|
617
|
-
kind: "error",
|
|
618
|
-
diagnostic: createDiagnostic("TSN4006", "error", `Invalid attribute argument: named arguments must be simple { Name: value } properties`, createLocation(module.filePath, obj.sourceSpan)),
|
|
619
|
-
};
|
|
620
|
-
}
|
|
621
|
-
const v = tryExtractAttributeArg(prop.value);
|
|
622
|
-
if (!v) {
|
|
623
|
-
return {
|
|
624
|
-
kind: "error",
|
|
625
|
-
diagnostic: createDiagnostic("TSN4006", "error", `Invalid attribute argument: named argument '${prop.key}' must be a compile-time constant`, createLocation(module.filePath, prop.value.sourceSpan)),
|
|
626
|
-
};
|
|
627
|
-
}
|
|
628
|
-
namedArgs.set(prop.key, v);
|
|
629
|
-
}
|
|
630
|
-
continue;
|
|
631
|
-
}
|
|
632
|
-
if (sawNamed) {
|
|
633
|
-
return {
|
|
634
|
-
kind: "error",
|
|
635
|
-
diagnostic: createDiagnostic("TSN4006", "error", `Invalid attribute argument: positional arguments cannot appear after named arguments`, createLocation(module.filePath, arg.sourceSpan)),
|
|
636
|
-
};
|
|
637
|
-
}
|
|
638
|
-
const v = tryExtractAttributeArg(arg);
|
|
639
|
-
if (!v) {
|
|
640
|
-
return {
|
|
641
|
-
kind: "error",
|
|
642
|
-
diagnostic: createDiagnostic("TSN4006", "error", `Invalid attribute argument: attribute arguments must be compile-time constants (string/number/boolean/typeof/enum/array)`, createLocation(module.filePath, arg.sourceSpan)),
|
|
643
|
-
};
|
|
644
|
-
}
|
|
645
|
-
positionalArgs.push(v);
|
|
646
|
-
}
|
|
647
|
-
return {
|
|
648
|
-
kind: "ok",
|
|
649
|
-
value: {
|
|
650
|
-
targetName,
|
|
651
|
-
targetSelector: selector,
|
|
652
|
-
selectedMemberName,
|
|
653
|
-
attributeTarget,
|
|
654
|
-
attributeType: attributeTypeResult.value,
|
|
655
|
-
positionalArgs,
|
|
656
|
-
namedArgs,
|
|
657
|
-
sourceSpan: call.sourceSpan,
|
|
658
|
-
},
|
|
659
|
-
};
|
|
660
|
-
};
|
|
661
|
-
/**
|
|
662
|
-
* Create a source location for error reporting
|
|
663
|
-
*/
|
|
664
|
-
const createLocation = (filePath, sourceSpan) => sourceSpan ?? { file: filePath, line: 1, column: 1, length: 1 };
|
|
665
|
-
/**
|
|
666
|
-
* Process a single module: detect attribute markers and attach to declarations
|
|
667
|
-
*/
|
|
668
|
-
const processModule = (module, diagnostics) => {
|
|
669
|
-
const apiNames = getAttributesApiLocalNames(module);
|
|
670
|
-
const attributeTargetsApiNames = getAttributeTargetsApiLocalNames(module);
|
|
671
|
-
if (apiNames.size === 0) {
|
|
672
|
-
return module;
|
|
673
|
-
}
|
|
674
|
-
// Collect detected attribute descriptors declared as variables:
|
|
675
|
-
// const d = A.attr(AttrCtor, ...args)
|
|
676
|
-
const descriptors = new Map();
|
|
677
|
-
const removedStatementIndices = new Set();
|
|
678
|
-
module.body.forEach((stmt, i) => {
|
|
679
|
-
if (stmt.kind !== "variableDeclaration")
|
|
680
|
-
return;
|
|
681
|
-
const decl = stmt;
|
|
682
|
-
// Only handle simple, single declarator `const name = A.attr(...)`.
|
|
683
|
-
if (decl.declarationKind !== "const")
|
|
684
|
-
return;
|
|
685
|
-
if (decl.declarations.length !== 1)
|
|
686
|
-
return;
|
|
687
|
-
const d0 = decl.declarations[0];
|
|
688
|
-
if (!d0)
|
|
689
|
-
return;
|
|
690
|
-
if (d0.name.kind !== "identifierPattern")
|
|
691
|
-
return;
|
|
692
|
-
if (!d0.initializer)
|
|
693
|
-
return;
|
|
694
|
-
const parsed = parseAttrDescriptorCall(d0.initializer, module, apiNames);
|
|
695
|
-
if (parsed.kind === "notMatch")
|
|
696
|
-
return;
|
|
697
|
-
if (parsed.kind === "error") {
|
|
698
|
-
diagnostics.push(parsed.diagnostic);
|
|
699
|
-
removedStatementIndices.add(i);
|
|
700
|
-
return;
|
|
701
|
-
}
|
|
702
|
-
descriptors.set(d0.name.name, parsed.value);
|
|
703
|
-
removedStatementIndices.add(i);
|
|
704
|
-
});
|
|
705
|
-
// Collect detected attribute markers
|
|
706
|
-
const markers = [];
|
|
707
|
-
// Walk statements looking for attribute markers
|
|
708
|
-
module.body.forEach((stmt, i) => {
|
|
709
|
-
if (removedStatementIndices.has(i))
|
|
710
|
-
return;
|
|
711
|
-
if (stmt.kind !== "expressionStatement")
|
|
712
|
-
return;
|
|
713
|
-
const expr = stmt.expression;
|
|
714
|
-
if (expr.kind !== "call")
|
|
715
|
-
return;
|
|
716
|
-
const marker = tryDetectAttributeMarker(expr, module, apiNames, attributeTargetsApiNames, descriptors);
|
|
717
|
-
if (marker.kind === "ok") {
|
|
718
|
-
markers.push(marker.value);
|
|
719
|
-
removedStatementIndices.add(i);
|
|
720
|
-
return;
|
|
721
|
-
}
|
|
722
|
-
if (marker.kind === "error") {
|
|
723
|
-
diagnostics.push(marker.diagnostic);
|
|
724
|
-
removedStatementIndices.add(i);
|
|
725
|
-
return;
|
|
726
|
-
}
|
|
727
|
-
// If it looks like an attribute API call but doesn't match a supported marker,
|
|
728
|
-
// fail deterministically instead of leaving runtime-dead code in the output.
|
|
729
|
-
if (looksLikeAttributesApiUsage(expr, apiNames)) {
|
|
730
|
-
diagnostics.push(createDiagnostic("TSN4005", "error", `Invalid attribute marker call. Expected one of: A.on(X).type.add(...), A.on(X).ctor.add(...), A.on(X).method(x => x.m).add(...), A.on(X).prop(x => x.p).add(...), with optional .target(...) before .add(...)`, createLocation(module.filePath, expr.sourceSpan)));
|
|
731
|
-
removedStatementIndices.add(i);
|
|
732
|
-
}
|
|
733
|
-
});
|
|
734
|
-
// If nothing to do, return module unchanged
|
|
735
|
-
if (markers.length === 0 && removedStatementIndices.size === 0) {
|
|
736
|
-
return module;
|
|
737
|
-
}
|
|
738
|
-
// Build map of declaration names to their indices
|
|
739
|
-
const classDeclarations = new Map();
|
|
740
|
-
const functionDeclarations = new Map();
|
|
741
|
-
module.body.forEach((stmt, i) => {
|
|
742
|
-
if (stmt.kind === "classDeclaration") {
|
|
743
|
-
classDeclarations.set(stmt.name, i);
|
|
744
|
-
}
|
|
745
|
-
else if (stmt.kind === "functionDeclaration") {
|
|
746
|
-
functionDeclarations.set(stmt.name, i);
|
|
747
|
-
}
|
|
748
|
-
});
|
|
749
|
-
// Build map of attributes per declaration
|
|
750
|
-
const classAttributes = new Map();
|
|
751
|
-
const classCtorAttributes = new Map();
|
|
752
|
-
const classMethodAttributes = new Map();
|
|
753
|
-
const classPropAttributes = new Map();
|
|
754
|
-
const functionAttributes = new Map();
|
|
755
|
-
for (const marker of markers) {
|
|
756
|
-
const classIndex = classDeclarations.get(marker.targetName);
|
|
757
|
-
const funcIndex = functionDeclarations.get(marker.targetName);
|
|
758
|
-
const attr = {
|
|
759
|
-
kind: "attribute",
|
|
760
|
-
target: marker.attributeTarget,
|
|
761
|
-
attributeType: marker.attributeType,
|
|
762
|
-
positionalArgs: marker.positionalArgs,
|
|
763
|
-
namedArgs: marker.namedArgs,
|
|
764
|
-
};
|
|
765
|
-
if (marker.targetSelector === "type") {
|
|
766
|
-
if (classIndex !== undefined && funcIndex !== undefined) {
|
|
767
|
-
diagnostics.push(createDiagnostic("TSN4005", "error", `Attribute target '${marker.targetName}' is ambiguous (matches both class and function)`, createLocation(module.filePath, marker.sourceSpan)));
|
|
768
|
-
continue;
|
|
769
|
-
}
|
|
770
|
-
if (classIndex !== undefined) {
|
|
771
|
-
if (marker.attributeTarget !== undefined &&
|
|
772
|
-
marker.attributeTarget !== "type") {
|
|
773
|
-
diagnostics.push(createDiagnostic("TSN4005", "error", `Invalid attribute target '${marker.attributeTarget}' for type attribute. Expected 'type' or omit .target(...)`, createLocation(module.filePath, marker.sourceSpan)));
|
|
774
|
-
continue;
|
|
775
|
-
}
|
|
776
|
-
const attrs = classAttributes.get(classIndex) ?? [];
|
|
777
|
-
attrs.push(attr);
|
|
778
|
-
classAttributes.set(classIndex, attrs);
|
|
779
|
-
continue;
|
|
780
|
-
}
|
|
781
|
-
if (funcIndex !== undefined) {
|
|
782
|
-
if (marker.attributeTarget !== undefined) {
|
|
783
|
-
diagnostics.push(createDiagnostic("TSN4005", "error", `.target(...) is not supported for function attributes via A.on(fn).type. Use A.on(Class).method(...) instead.`, createLocation(module.filePath, marker.sourceSpan)));
|
|
784
|
-
continue;
|
|
785
|
-
}
|
|
786
|
-
const attrs = functionAttributes.get(funcIndex) ?? [];
|
|
787
|
-
attrs.push(attr);
|
|
788
|
-
functionAttributes.set(funcIndex, attrs);
|
|
789
|
-
continue;
|
|
790
|
-
}
|
|
791
|
-
diagnostics.push(createDiagnostic("TSN4007", "error", `Attribute target '${marker.targetName}' not found in module`, createLocation(module.filePath, marker.sourceSpan)));
|
|
792
|
-
continue;
|
|
793
|
-
}
|
|
794
|
-
if (classIndex === undefined) {
|
|
795
|
-
diagnostics.push(createDiagnostic("TSN4007", "error", `Attribute target '${marker.targetName}' not found in module`, createLocation(module.filePath, marker.sourceSpan)));
|
|
796
|
-
continue;
|
|
797
|
-
}
|
|
798
|
-
const classStmt = module.body[classIndex];
|
|
799
|
-
if (marker.targetSelector === "ctor") {
|
|
800
|
-
if (marker.attributeTarget !== undefined &&
|
|
801
|
-
marker.attributeTarget !== "method") {
|
|
802
|
-
diagnostics.push(createDiagnostic("TSN4005", "error", `Invalid attribute target '${marker.attributeTarget}' for constructor attribute. Expected 'method' or omit .target(...)`, createLocation(module.filePath, marker.sourceSpan)));
|
|
803
|
-
continue;
|
|
804
|
-
}
|
|
805
|
-
const hasCtor = classStmt.members.some((m) => m.kind === "constructorDeclaration");
|
|
806
|
-
if (classStmt.isStruct && !hasCtor) {
|
|
807
|
-
diagnostics.push(createDiagnostic("TSN4005", "error", `Cannot apply constructor attributes to struct '${classStmt.name}' without an explicit constructor`, createLocation(module.filePath, marker.sourceSpan)));
|
|
808
|
-
continue;
|
|
809
|
-
}
|
|
810
|
-
const attrs = classCtorAttributes.get(classIndex) ?? [];
|
|
811
|
-
attrs.push(attr);
|
|
812
|
-
classCtorAttributes.set(classIndex, attrs);
|
|
813
|
-
continue;
|
|
814
|
-
}
|
|
815
|
-
if (marker.targetSelector === "method") {
|
|
816
|
-
if (marker.attributeTarget !== undefined &&
|
|
817
|
-
marker.attributeTarget !== "method" &&
|
|
818
|
-
marker.attributeTarget !== "return") {
|
|
819
|
-
diagnostics.push(createDiagnostic("TSN4005", "error", `Invalid attribute target '${marker.attributeTarget}' for method attribute. Expected 'method', 'return', or omit .target(...)`, createLocation(module.filePath, marker.sourceSpan)));
|
|
820
|
-
continue;
|
|
821
|
-
}
|
|
822
|
-
const memberName = marker.selectedMemberName;
|
|
823
|
-
if (!memberName) {
|
|
824
|
-
diagnostics.push(createDiagnostic("TSN4005", "error", `Invalid attribute marker: method target missing member name`, createLocation(module.filePath, marker.sourceSpan)));
|
|
825
|
-
continue;
|
|
826
|
-
}
|
|
827
|
-
const hasMember = classStmt.members.some((m) => m.kind === "methodDeclaration" && m.name === memberName);
|
|
828
|
-
if (!hasMember) {
|
|
829
|
-
diagnostics.push(createDiagnostic("TSN4007", "error", `Method '${classStmt.name}.${memberName}' not found for attribute target`, createLocation(module.filePath, marker.sourceSpan)));
|
|
830
|
-
continue;
|
|
831
|
-
}
|
|
832
|
-
const perClass = classMethodAttributes.get(classIndex) ?? new Map();
|
|
833
|
-
const attrs = perClass.get(memberName) ?? [];
|
|
834
|
-
attrs.push(attr);
|
|
835
|
-
perClass.set(memberName, attrs);
|
|
836
|
-
classMethodAttributes.set(classIndex, perClass);
|
|
837
|
-
continue;
|
|
838
|
-
}
|
|
839
|
-
if (marker.targetSelector === "prop") {
|
|
840
|
-
const memberName = marker.selectedMemberName;
|
|
841
|
-
if (!memberName) {
|
|
842
|
-
diagnostics.push(createDiagnostic("TSN4005", "error", `Invalid attribute marker: property target missing member name`, createLocation(module.filePath, marker.sourceSpan)));
|
|
843
|
-
continue;
|
|
844
|
-
}
|
|
845
|
-
const member = classStmt.members.find((m) => m.kind === "propertyDeclaration" && m.name === memberName);
|
|
846
|
-
if (!member || member.kind !== "propertyDeclaration") {
|
|
847
|
-
diagnostics.push(createDiagnostic("TSN4007", "error", `Property '${classStmt.name}.${memberName}' not found for attribute target`, createLocation(module.filePath, marker.sourceSpan)));
|
|
848
|
-
continue;
|
|
849
|
-
}
|
|
850
|
-
if (marker.attributeTarget !== undefined) {
|
|
851
|
-
if (member.emitAsField) {
|
|
852
|
-
if (marker.attributeTarget !== "field") {
|
|
853
|
-
diagnostics.push(createDiagnostic("TSN4005", "error", `Invalid attribute target '${marker.attributeTarget}' for field-emitted property '${classStmt.name}.${memberName}'. Expected 'field' or omit .target(...)`, createLocation(module.filePath, marker.sourceSpan)));
|
|
854
|
-
continue;
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
|
-
else if (marker.attributeTarget !== "property" &&
|
|
858
|
-
marker.attributeTarget !== "field") {
|
|
859
|
-
diagnostics.push(createDiagnostic("TSN4005", "error", `Invalid attribute target '${marker.attributeTarget}' for property attribute. Expected 'property', 'field', or omit .target(...)`, createLocation(module.filePath, marker.sourceSpan)));
|
|
860
|
-
continue;
|
|
861
|
-
}
|
|
862
|
-
if (marker.attributeTarget === "field") {
|
|
863
|
-
const isAccessorProperty = member.getterBody !== undefined || member.setterBody !== undefined;
|
|
864
|
-
if (isAccessorProperty) {
|
|
865
|
-
diagnostics.push(createDiagnostic("TSN4005", "error", `Cannot apply [field: ...] attribute target to accessor property '${classStmt.name}.${memberName}'. Apply the attribute to the actual field instead.`, createLocation(module.filePath, marker.sourceSpan)));
|
|
866
|
-
continue;
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
const perClass = classPropAttributes.get(classIndex) ?? new Map();
|
|
871
|
-
const attrs = perClass.get(memberName) ?? [];
|
|
872
|
-
attrs.push(attr);
|
|
873
|
-
perClass.set(memberName, attrs);
|
|
874
|
-
classPropAttributes.set(classIndex, perClass);
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
// Rebuild module body:
|
|
878
|
-
// 1. Filter out marker statements
|
|
879
|
-
// 2. Update declarations with attached attributes
|
|
880
|
-
const newBody = [];
|
|
881
|
-
module.body.forEach((stmt, i) => {
|
|
882
|
-
// Skip marker statements
|
|
883
|
-
if (removedStatementIndices.has(i))
|
|
884
|
-
return;
|
|
885
|
-
if (stmt.kind === "classDeclaration") {
|
|
886
|
-
// Update class with attributes
|
|
887
|
-
const classStmt = stmt;
|
|
888
|
-
const existingAttrs = classStmt.attributes ?? [];
|
|
889
|
-
const typeAttrs = classAttributes.get(i) ?? [];
|
|
890
|
-
const ctorAttrs = classCtorAttributes.get(i) ?? [];
|
|
891
|
-
const methodAttrs = classMethodAttributes.get(i);
|
|
892
|
-
const propAttrs = classPropAttributes.get(i);
|
|
893
|
-
const updatedMembers = methodAttrs || propAttrs
|
|
894
|
-
? classStmt.members.map((m) => {
|
|
895
|
-
if (m.kind === "methodDeclaration" && methodAttrs) {
|
|
896
|
-
const extras = methodAttrs.get(m.name);
|
|
897
|
-
if (extras && extras.length > 0) {
|
|
898
|
-
return {
|
|
899
|
-
...m,
|
|
900
|
-
attributes: [...(m.attributes ?? []), ...extras],
|
|
901
|
-
};
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
if (m.kind === "propertyDeclaration" && propAttrs) {
|
|
905
|
-
const extras = propAttrs.get(m.name);
|
|
906
|
-
if (extras && extras.length > 0) {
|
|
907
|
-
return {
|
|
908
|
-
...m,
|
|
909
|
-
attributes: [...(m.attributes ?? []), ...extras],
|
|
910
|
-
};
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
return m;
|
|
914
|
-
})
|
|
915
|
-
: classStmt.members;
|
|
916
|
-
const updated = {
|
|
917
|
-
...classStmt,
|
|
918
|
-
members: updatedMembers,
|
|
919
|
-
attributes: typeAttrs.length > 0
|
|
920
|
-
? [...existingAttrs, ...typeAttrs]
|
|
921
|
-
: classStmt.attributes,
|
|
922
|
-
ctorAttributes: ctorAttrs.length > 0
|
|
923
|
-
? [...(classStmt.ctorAttributes ?? []), ...ctorAttrs]
|
|
924
|
-
: classStmt.ctorAttributes,
|
|
925
|
-
};
|
|
926
|
-
// Avoid allocating new nodes when there are no changes.
|
|
927
|
-
if (typeAttrs.length === 0 &&
|
|
928
|
-
ctorAttrs.length === 0 &&
|
|
929
|
-
!methodAttrs &&
|
|
930
|
-
!propAttrs) {
|
|
931
|
-
newBody.push(classStmt);
|
|
932
|
-
}
|
|
933
|
-
else {
|
|
934
|
-
newBody.push(updated);
|
|
935
|
-
}
|
|
936
|
-
return;
|
|
937
|
-
}
|
|
938
|
-
if (stmt.kind === "functionDeclaration" && functionAttributes.has(i)) {
|
|
939
|
-
// Update function with attributes
|
|
940
|
-
const funcStmt = stmt;
|
|
941
|
-
const existingAttrs = funcStmt.attributes ?? [];
|
|
942
|
-
const newAttrs = functionAttributes.get(i) ?? [];
|
|
943
|
-
newBody.push({
|
|
944
|
-
...funcStmt,
|
|
945
|
-
attributes: [...existingAttrs, ...newAttrs],
|
|
946
|
-
});
|
|
947
|
-
return;
|
|
948
|
-
}
|
|
949
|
-
// Keep statement unchanged
|
|
950
|
-
newBody.push(stmt);
|
|
951
|
-
});
|
|
952
|
-
return {
|
|
953
|
-
...module,
|
|
954
|
-
body: newBody,
|
|
955
|
-
};
|
|
956
|
-
};
|
|
957
|
-
/**
|
|
958
|
-
* Run the attribute collection pass on a set of modules.
|
|
959
|
-
*
|
|
960
|
-
* This pass:
|
|
961
|
-
* 1. Detects attribute marker calls (A.on(X).type.add(Y))
|
|
962
|
-
* 2. Attaches IrAttribute nodes to the corresponding declarations
|
|
963
|
-
* 3. Removes the marker statements from the module body
|
|
964
|
-
* 4. Emits diagnostics for invalid patterns
|
|
965
|
-
*/
|
|
966
|
-
export const runAttributeCollectionPass = (modules) => {
|
|
967
|
-
const diagnostics = [];
|
|
968
|
-
const processedModules = [];
|
|
969
|
-
for (const module of modules) {
|
|
970
|
-
const processed = processModule(module, diagnostics);
|
|
971
|
-
processedModules.push(processed);
|
|
972
|
-
}
|
|
973
|
-
const hasErrors = diagnostics.some((d) => d.severity === "error");
|
|
974
|
-
return {
|
|
975
|
-
ok: !hasErrors,
|
|
976
|
-
modules: processedModules,
|
|
977
|
-
diagnostics,
|
|
978
|
-
};
|
|
979
|
-
};
|
|
19
|
+
export { runAttributeCollectionPass, } from "./attribute-collection/orchestrator.js";
|
|
980
20
|
//# sourceMappingURL=attribute-collection-pass.js.map
|