aws-iam-ls 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.direnv/bin/nix-direnv-reload +19 -0
- package/.direnv/flake-profile-a5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa.rc +2156 -0
- package/.github/workflows/publish.yml +37 -0
- package/.github/workflows/test.yml +16 -0
- package/.vscodeignore +17 -0
- package/LICENSE +21 -0
- package/package.json +53 -0
- package/readme.md +25 -0
- package/src/data/condition-keys/global.json +362 -0
- package/src/data/servicereference/actions.json +1 -0
- package/src/data/servicereference/service-principals.json +1 -0
- package/src/data/servicereference/services/a2c.json +1 -0
- package/src/data/servicereference/services/a4b.json +1 -0
- package/src/data/servicereference/services/access-analyzer.json +1 -0
- package/src/data/servicereference/services/account.json +1 -0
- package/src/data/servicereference/services/acm-pca.json +1 -0
- package/src/data/servicereference/services/acm.json +1 -0
- package/src/data/servicereference/services/aco-automation.json +1 -0
- package/src/data/servicereference/services/action-recommendations.json +1 -0
- package/src/data/servicereference/services/activate.json +1 -0
- package/src/data/servicereference/services/aidevops.json +1 -0
- package/src/data/servicereference/services/aiops.json +1 -0
- package/src/data/servicereference/services/airflow-serverless.json +1 -0
- package/src/data/servicereference/services/airflow.json +1 -0
- package/src/data/servicereference/services/amplify.json +1 -0
- package/src/data/servicereference/services/amplifybackend.json +1 -0
- package/src/data/servicereference/services/amplifyuibuilder.json +1 -0
- package/src/data/servicereference/services/aoss.json +1 -0
- package/src/data/servicereference/services/apigateway.json +1 -0
- package/src/data/servicereference/services/app-integrations.json +1 -0
- package/src/data/servicereference/services/appconfig.json +1 -0
- package/src/data/servicereference/services/appfabric.json +1 -0
- package/src/data/servicereference/services/appflow.json +1 -0
- package/src/data/servicereference/services/application-autoscaling.json +1 -0
- package/src/data/servicereference/services/application-signals.json +1 -0
- package/src/data/servicereference/services/application-transformation.json +1 -0
- package/src/data/servicereference/services/applicationinsights.json +1 -0
- package/src/data/servicereference/services/appmesh-preview.json +1 -0
- package/src/data/servicereference/services/appmesh.json +1 -0
- package/src/data/servicereference/services/apprunner.json +1 -0
- package/src/data/servicereference/services/appstream.json +1 -0
- package/src/data/servicereference/services/appstudio.json +1 -0
- package/src/data/servicereference/services/appsync.json +1 -0
- package/src/data/servicereference/services/apptest.json +1 -0
- package/src/data/servicereference/services/aps.json +1 -0
- package/src/data/servicereference/services/arc-region-switch.json +1 -0
- package/src/data/servicereference/services/arc-zonal-shift.json +1 -0
- package/src/data/servicereference/services/arsenal.json +1 -0
- package/src/data/servicereference/services/artifact.json +1 -0
- package/src/data/servicereference/services/athena.json +1 -0
- package/src/data/servicereference/services/auditmanager.json +1 -0
- package/src/data/servicereference/services/autoscaling-plans.json +1 -0
- package/src/data/servicereference/services/autoscaling.json +1 -0
- package/src/data/servicereference/services/aws-marketplace-management.json +1 -0
- package/src/data/servicereference/services/aws-marketplace.json +1 -0
- package/src/data/servicereference/services/aws-mcp.json +1 -0
- package/src/data/servicereference/services/aws-portal.json +1 -0
- package/src/data/servicereference/services/awsconnector.json +1 -0
- package/src/data/servicereference/services/b2bi.json +1 -0
- package/src/data/servicereference/services/backup-gateway.json +1 -0
- package/src/data/servicereference/services/backup-search.json +1 -0
- package/src/data/servicereference/services/backup-storage.json +1 -0
- package/src/data/servicereference/services/backup.json +1 -0
- package/src/data/servicereference/services/batch.json +1 -0
- package/src/data/servicereference/services/bcm-dashboards.json +1 -0
- package/src/data/servicereference/services/bcm-data-exports.json +1 -0
- package/src/data/servicereference/services/bcm-pricing-calculator.json +1 -0
- package/src/data/servicereference/services/bcm-recommended-actions.json +1 -0
- package/src/data/servicereference/services/bedrock-agentcore.json +1 -0
- package/src/data/servicereference/services/bedrock-mantle.json +1 -0
- package/src/data/servicereference/services/bedrock.json +1 -0
- package/src/data/servicereference/services/billing.json +1 -0
- package/src/data/servicereference/services/billingconductor.json +1 -0
- package/src/data/servicereference/services/braket.json +1 -0
- package/src/data/servicereference/services/budgets.json +1 -0
- package/src/data/servicereference/services/bugbust.json +1 -0
- package/src/data/servicereference/services/cases.json +1 -0
- package/src/data/servicereference/services/cassandra.json +1 -0
- package/src/data/servicereference/services/ce.json +1 -0
- package/src/data/servicereference/services/chatbot.json +1 -0
- package/src/data/servicereference/services/chime.json +1 -0
- package/src/data/servicereference/services/cleanrooms-ml.json +1 -0
- package/src/data/servicereference/services/cleanrooms.json +1 -0
- package/src/data/servicereference/services/cloud9.json +1 -0
- package/src/data/servicereference/services/clouddirectory.json +1 -0
- package/src/data/servicereference/services/cloudformation.json +1 -0
- package/src/data/servicereference/services/cloudfront-keyvaluestore.json +1 -0
- package/src/data/servicereference/services/cloudfront.json +1 -0
- package/src/data/servicereference/services/cloudhsm.json +1 -0
- package/src/data/servicereference/services/cloudsearch.json +1 -0
- package/src/data/servicereference/services/cloudshell.json +1 -0
- package/src/data/servicereference/services/cloudtrail-data.json +1 -0
- package/src/data/servicereference/services/cloudtrail.json +1 -0
- package/src/data/servicereference/services/cloudwatch.json +1 -0
- package/src/data/servicereference/services/codeartifact.json +1 -0
- package/src/data/servicereference/services/codebuild.json +1 -0
- package/src/data/servicereference/services/codecatalyst.json +1 -0
- package/src/data/servicereference/services/codecommit.json +1 -0
- package/src/data/servicereference/services/codeconnections.json +1 -0
- package/src/data/servicereference/services/codedeploy-commands-secure.json +1 -0
- package/src/data/servicereference/services/codedeploy.json +1 -0
- package/src/data/servicereference/services/codeguru-profiler.json +1 -0
- package/src/data/servicereference/services/codeguru-reviewer.json +1 -0
- package/src/data/servicereference/services/codeguru-security.json +1 -0
- package/src/data/servicereference/services/codeguru.json +1 -0
- package/src/data/servicereference/services/codepipeline.json +1 -0
- package/src/data/servicereference/services/codestar-connections.json +1 -0
- package/src/data/servicereference/services/codestar-notifications.json +1 -0
- package/src/data/servicereference/services/codestar.json +1 -0
- package/src/data/servicereference/services/codewhisperer.json +1 -0
- package/src/data/servicereference/services/cognito-identity.json +1 -0
- package/src/data/servicereference/services/cognito-idp.json +1 -0
- package/src/data/servicereference/services/cognito-sync.json +1 -0
- package/src/data/servicereference/services/comprehend.json +1 -0
- package/src/data/servicereference/services/comprehendmedical.json +1 -0
- package/src/data/servicereference/services/compute-optimizer.json +1 -0
- package/src/data/servicereference/services/config.json +1 -0
- package/src/data/servicereference/services/connect-campaigns.json +1 -0
- package/src/data/servicereference/services/connect.json +1 -0
- package/src/data/servicereference/services/consoleapp.json +1 -0
- package/src/data/servicereference/services/consolidatedbilling.json +1 -0
- package/src/data/servicereference/services/controlcatalog.json +1 -0
- package/src/data/servicereference/services/controltower.json +1 -0
- package/src/data/servicereference/services/cost-optimization-hub.json +1 -0
- package/src/data/servicereference/services/cur.json +1 -0
- package/src/data/servicereference/services/customer-verification.json +1 -0
- package/src/data/servicereference/services/databrew.json +1 -0
- package/src/data/servicereference/services/dataexchange.json +1 -0
- package/src/data/servicereference/services/datapipeline.json +1 -0
- package/src/data/servicereference/services/datasync.json +1 -0
- package/src/data/servicereference/services/datazone.json +1 -0
- package/src/data/servicereference/services/dax.json +1 -0
- package/src/data/servicereference/services/dbqms.json +1 -0
- package/src/data/servicereference/services/deadline.json +1 -0
- package/src/data/servicereference/services/detective.json +1 -0
- package/src/data/servicereference/services/devicefarm.json +1 -0
- package/src/data/servicereference/services/devops-guru.json +1 -0
- package/src/data/servicereference/services/directconnect.json +1 -0
- package/src/data/servicereference/services/discovery.json +1 -0
- package/src/data/servicereference/services/dlm.json +1 -0
- package/src/data/servicereference/services/dms.json +1 -0
- package/src/data/servicereference/services/docdb-elastic.json +1 -0
- package/src/data/servicereference/services/drs.json +1 -0
- package/src/data/servicereference/services/ds-data.json +1 -0
- package/src/data/servicereference/services/ds.json +1 -0
- package/src/data/servicereference/services/dsql.json +1 -0
- package/src/data/servicereference/services/dynamodb.json +1 -0
- package/src/data/servicereference/services/ebs.json +1 -0
- package/src/data/servicereference/services/ec2-instance-connect.json +1 -0
- package/src/data/servicereference/services/ec2.json +1 -0
- package/src/data/servicereference/services/ec2messages.json +1 -0
- package/src/data/servicereference/services/ecr-public.json +1 -0
- package/src/data/servicereference/services/ecr.json +1 -0
- package/src/data/servicereference/services/ecs-mcp.json +1 -0
- package/src/data/servicereference/services/ecs.json +1 -0
- package/src/data/servicereference/services/eks-auth.json +1 -0
- package/src/data/servicereference/services/eks-mcp.json +1 -0
- package/src/data/servicereference/services/eks.json +1 -0
- package/src/data/servicereference/services/elasticache.json +1 -0
- package/src/data/servicereference/services/elasticbeanstalk.json +1 -0
- package/src/data/servicereference/services/elasticfilesystem.json +1 -0
- package/src/data/servicereference/services/elasticloadbalancing.json +1 -0
- package/src/data/servicereference/services/elasticmapreduce.json +1 -0
- package/src/data/servicereference/services/elastictranscoder.json +1 -0
- package/src/data/servicereference/services/elemental-activations.json +1 -0
- package/src/data/servicereference/services/elemental-appliances-software.json +1 -0
- package/src/data/servicereference/services/elemental-inference.json +1 -0
- package/src/data/servicereference/services/elemental-support-cases.json +1 -0
- package/src/data/servicereference/services/elemental-support-content.json +1 -0
- package/src/data/servicereference/services/emr-containers.json +1 -0
- package/src/data/servicereference/services/emr-serverless.json +1 -0
- package/src/data/servicereference/services/entityresolution.json +1 -0
- package/src/data/servicereference/services/es.json +1 -0
- package/src/data/servicereference/services/events.json +1 -0
- package/src/data/servicereference/services/evidently.json +1 -0
- package/src/data/servicereference/services/evs.json +1 -0
- package/src/data/servicereference/services/execute-api.json +1 -0
- package/src/data/servicereference/services/finspace-api.json +1 -0
- package/src/data/servicereference/services/finspace.json +1 -0
- package/src/data/servicereference/services/firehose.json +1 -0
- package/src/data/servicereference/services/fis.json +1 -0
- package/src/data/servicereference/services/fms.json +1 -0
- package/src/data/servicereference/services/forecast.json +1 -0
- package/src/data/servicereference/services/frauddetector.json +1 -0
- package/src/data/servicereference/services/freertos.json +1 -0
- package/src/data/servicereference/services/freetier.json +1 -0
- package/src/data/servicereference/services/fsx.json +1 -0
- package/src/data/servicereference/services/gamelift.json +1 -0
- package/src/data/servicereference/services/gameliftstreams.json +1 -0
- package/src/data/servicereference/services/geo-maps.json +1 -0
- package/src/data/servicereference/services/geo-places.json +1 -0
- package/src/data/servicereference/services/geo-routes.json +1 -0
- package/src/data/servicereference/services/geo.json +1 -0
- package/src/data/servicereference/services/glacier.json +1 -0
- package/src/data/servicereference/services/globalaccelerator.json +1 -0
- package/src/data/servicereference/services/glue.json +1 -0
- package/src/data/servicereference/services/grafana.json +1 -0
- package/src/data/servicereference/services/greengrass.json +1 -0
- package/src/data/servicereference/services/groundstation.json +1 -0
- package/src/data/servicereference/services/groundtruthlabeling.json +1 -0
- package/src/data/servicereference/services/guardduty.json +1 -0
- package/src/data/servicereference/services/health-agent.json +1 -0
- package/src/data/servicereference/services/health.json +1 -0
- package/src/data/servicereference/services/healthlake.json +1 -0
- package/src/data/servicereference/services/honeycode.json +1 -0
- package/src/data/servicereference/services/iam.json +1 -0
- package/src/data/servicereference/services/identity-sync.json +1 -0
- package/src/data/servicereference/services/identitystore-auth.json +1 -0
- package/src/data/servicereference/services/identitystore.json +1 -0
- package/src/data/servicereference/services/imagebuilder.json +1 -0
- package/src/data/servicereference/services/importexport.json +1 -0
- package/src/data/servicereference/services/inspector-scan.json +1 -0
- package/src/data/servicereference/services/inspector.json +1 -0
- package/src/data/servicereference/services/inspector2-telemetry.json +1 -0
- package/src/data/servicereference/services/inspector2.json +1 -0
- package/src/data/servicereference/services/interconnect.json +1 -0
- package/src/data/servicereference/services/internetmonitor.json +1 -0
- package/src/data/servicereference/services/invoicing.json +1 -0
- package/src/data/servicereference/services/iot-device-tester.json +1 -0
- package/src/data/servicereference/services/iot.json +1 -0
- package/src/data/servicereference/services/iotanalytics.json +1 -0
- package/src/data/servicereference/services/iotdeviceadvisor.json +1 -0
- package/src/data/servicereference/services/iotevents.json +1 -0
- package/src/data/servicereference/services/iotfleethub.json +1 -0
- package/src/data/servicereference/services/iotfleetwise.json +1 -0
- package/src/data/servicereference/services/iotjobsdata.json +1 -0
- package/src/data/servicereference/services/iotmanagedintegrations.json +1 -0
- package/src/data/servicereference/services/iotsitewise.json +1 -0
- package/src/data/servicereference/services/iottwinmaker.json +1 -0
- package/src/data/servicereference/services/iotwireless.json +1 -0
- package/src/data/servicereference/services/iq-permission.json +1 -0
- package/src/data/servicereference/services/iq.json +1 -0
- package/src/data/servicereference/services/ivs.json +1 -0
- package/src/data/servicereference/services/ivschat.json +1 -0
- package/src/data/servicereference/services/kafka-cluster.json +1 -0
- package/src/data/servicereference/services/kafka.json +1 -0
- package/src/data/servicereference/services/kafkaconnect.json +1 -0
- package/src/data/servicereference/services/kendra-ranking.json +1 -0
- package/src/data/servicereference/services/kendra.json +1 -0
- package/src/data/servicereference/services/kinesis.json +1 -0
- package/src/data/servicereference/services/kinesisanalytics.json +1 -0
- package/src/data/servicereference/services/kinesisvideo.json +1 -0
- package/src/data/servicereference/services/kms.json +1 -0
- package/src/data/servicereference/services/lakeformation.json +1 -0
- package/src/data/servicereference/services/lambda.json +1 -0
- package/src/data/servicereference/services/launchwizard.json +1 -0
- package/src/data/servicereference/services/lex.json +1 -0
- package/src/data/servicereference/services/license-manager-linux-subscriptions.json +1 -0
- package/src/data/servicereference/services/license-manager-user-subscriptions.json +1 -0
- package/src/data/servicereference/services/license-manager.json +1 -0
- package/src/data/servicereference/services/lightsail.json +1 -0
- package/src/data/servicereference/services/logs.json +1 -0
- package/src/data/servicereference/services/lookoutequipment.json +1 -0
- package/src/data/servicereference/services/lookoutmetrics.json +1 -0
- package/src/data/servicereference/services/lookoutvision.json +1 -0
- package/src/data/servicereference/services/m2.json +1 -0
- package/src/data/servicereference/services/machinelearning.json +1 -0
- package/src/data/servicereference/services/macie2.json +1 -0
- package/src/data/servicereference/services/managedblockchain-query.json +1 -0
- package/src/data/servicereference/services/managedblockchain.json +1 -0
- package/src/data/servicereference/services/mapcredits.json +1 -0
- package/src/data/servicereference/services/marketplacecommerceanalytics.json +1 -0
- package/src/data/servicereference/services/mechanicalturk.json +1 -0
- package/src/data/servicereference/services/mediaconnect.json +1 -0
- package/src/data/servicereference/services/mediaconvert.json +1 -0
- package/src/data/servicereference/services/mediaimport.json +1 -0
- package/src/data/servicereference/services/medialive.json +1 -0
- package/src/data/servicereference/services/mediapackage-vod.json +1 -0
- package/src/data/servicereference/services/mediapackage.json +1 -0
- package/src/data/servicereference/services/mediapackagev2.json +1 -0
- package/src/data/servicereference/services/mediastore.json +1 -0
- package/src/data/servicereference/services/mediatailor.json +1 -0
- package/src/data/servicereference/services/medical-imaging.json +1 -0
- package/src/data/servicereference/services/memorydb.json +1 -0
- package/src/data/servicereference/services/mgh.json +1 -0
- package/src/data/servicereference/services/mgn.json +1 -0
- package/src/data/servicereference/services/migrationhub-orchestrator.json +1 -0
- package/src/data/servicereference/services/migrationhub-strategy.json +1 -0
- package/src/data/servicereference/services/mobileanalytics.json +1 -0
- package/src/data/servicereference/services/mobiletargeting.json +1 -0
- package/src/data/servicereference/services/monitron.json +1 -0
- package/src/data/servicereference/services/mpa.json +1 -0
- package/src/data/servicereference/services/mq.json +1 -0
- package/src/data/servicereference/services/neptune-db.json +1 -0
- package/src/data/servicereference/services/neptune-graph.json +1 -0
- package/src/data/servicereference/services/network-firewall.json +1 -0
- package/src/data/servicereference/services/network-security-director.json +1 -0
- package/src/data/servicereference/services/networkflowmonitor.json +1 -0
- package/src/data/servicereference/services/networkmanager-chat.json +1 -0
- package/src/data/servicereference/services/networkmanager.json +1 -0
- package/src/data/servicereference/services/networkmonitor.json +1 -0
- package/src/data/servicereference/services/nimble.json +1 -0
- package/src/data/servicereference/services/notifications-contacts.json +1 -0
- package/src/data/servicereference/services/notifications.json +1 -0
- package/src/data/servicereference/services/nova-act.json +1 -0
- package/src/data/servicereference/services/oam.json +1 -0
- package/src/data/servicereference/services/observabilityadmin.json +1 -0
- package/src/data/servicereference/services/odb.json +1 -0
- package/src/data/servicereference/services/omics.json +1 -0
- package/src/data/servicereference/services/one.json +1 -0
- package/src/data/servicereference/services/opensearch.json +1 -0
- package/src/data/servicereference/services/opsworks-cm.json +1 -0
- package/src/data/servicereference/services/opsworks.json +1 -0
- package/src/data/servicereference/services/organizations.json +1 -0
- package/src/data/servicereference/services/osis.json +1 -0
- package/src/data/servicereference/services/outposts.json +1 -0
- package/src/data/servicereference/services/panorama.json +1 -0
- package/src/data/servicereference/services/partnercentral-account-management.json +1 -0
- package/src/data/servicereference/services/partnercentral.json +1 -0
- package/src/data/servicereference/services/payment-cryptography.json +1 -0
- package/src/data/servicereference/services/payments.json +1 -0
- package/src/data/servicereference/services/pca-connector-ad.json +1 -0
- package/src/data/servicereference/services/pca-connector-scep.json +1 -0
- package/src/data/servicereference/services/pcs.json +1 -0
- package/src/data/servicereference/services/personalize.json +1 -0
- package/src/data/servicereference/services/pi.json +1 -0
- package/src/data/servicereference/services/pipes.json +1 -0
- package/src/data/servicereference/services/polly.json +1 -0
- package/src/data/servicereference/services/pricing.json +1 -0
- package/src/data/servicereference/services/pricingplanmanager.json +1 -0
- package/src/data/servicereference/services/private-networks.json +1 -0
- package/src/data/servicereference/services/profile.json +1 -0
- package/src/data/servicereference/services/proton.json +1 -0
- package/src/data/servicereference/services/purchase-orders.json +1 -0
- package/src/data/servicereference/services/q.json +1 -0
- package/src/data/servicereference/services/qapps.json +1 -0
- package/src/data/servicereference/services/qbusiness.json +1 -0
- package/src/data/servicereference/services/qdeveloper.json +1 -0
- package/src/data/servicereference/services/qldb.json +1 -0
- package/src/data/servicereference/services/quicksight.json +1 -0
- package/src/data/servicereference/services/ram.json +1 -0
- package/src/data/servicereference/services/rbin.json +1 -0
- package/src/data/servicereference/services/rds-data.json +1 -0
- package/src/data/servicereference/services/rds-db.json +1 -0
- package/src/data/servicereference/services/rds.json +1 -0
- package/src/data/servicereference/services/redshift-data.json +1 -0
- package/src/data/servicereference/services/redshift-serverless.json +1 -0
- package/src/data/servicereference/services/redshift.json +1 -0
- package/src/data/servicereference/services/refactor-spaces.json +1 -0
- package/src/data/servicereference/services/rekognition.json +1 -0
- package/src/data/servicereference/services/repostspace.json +1 -0
- package/src/data/servicereference/services/resiliencehub.json +1 -0
- package/src/data/servicereference/services/resource-explorer-2.json +1 -0
- package/src/data/servicereference/services/resource-explorer.json +1 -0
- package/src/data/servicereference/services/resource-groups.json +1 -0
- package/src/data/servicereference/services/rhelkb.json +1 -0
- package/src/data/servicereference/services/robomaker.json +1 -0
- package/src/data/servicereference/services/rolesanywhere.json +1 -0
- package/src/data/servicereference/services/route53-recovery-cluster.json +1 -0
- package/src/data/servicereference/services/route53-recovery-control-config.json +1 -0
- package/src/data/servicereference/services/route53-recovery-readiness.json +1 -0
- package/src/data/servicereference/services/route53.json +1 -0
- package/src/data/servicereference/services/route53domains.json +1 -0
- package/src/data/servicereference/services/route53globalresolver.json +1 -0
- package/src/data/servicereference/services/route53profiles.json +1 -0
- package/src/data/servicereference/services/route53resolver.json +1 -0
- package/src/data/servicereference/services/rtbfabric.json +1 -0
- package/src/data/servicereference/services/rum.json +1 -0
- package/src/data/servicereference/services/s3-object-lambda.json +1 -0
- package/src/data/servicereference/services/s3-outposts.json +1 -0
- package/src/data/servicereference/services/s3.json +1 -0
- package/src/data/servicereference/services/s3express.json +1 -0
- package/src/data/servicereference/services/s3tables.json +1 -0
- package/src/data/servicereference/services/s3vectors.json +1 -0
- package/src/data/servicereference/services/sagemaker-data-science-assistant.json +1 -0
- package/src/data/servicereference/services/sagemaker-geospatial.json +1 -0
- package/src/data/servicereference/services/sagemaker-mlflow.json +1 -0
- package/src/data/servicereference/services/sagemaker-unified-studio-mcp.json +1 -0
- package/src/data/servicereference/services/sagemaker.json +1 -0
- package/src/data/servicereference/services/savingsplans.json +1 -0
- package/src/data/servicereference/services/scheduler.json +1 -0
- package/src/data/servicereference/services/schemas.json +1 -0
- package/src/data/servicereference/services/scn.json +1 -0
- package/src/data/servicereference/services/sdb.json +1 -0
- package/src/data/servicereference/services/secretsmanager.json +1 -0
- package/src/data/servicereference/services/security-ir.json +1 -0
- package/src/data/servicereference/services/securityagent.json +1 -0
- package/src/data/servicereference/services/securityhub.json +1 -0
- package/src/data/servicereference/services/securitylake.json +1 -0
- package/src/data/servicereference/services/serverlessrepo.json +1 -0
- package/src/data/servicereference/services/servicecatalog.json +1 -0
- package/src/data/servicereference/services/servicediscovery.json +1 -0
- package/src/data/servicereference/services/serviceextract.json +1 -0
- package/src/data/servicereference/services/servicequotas.json +1 -0
- package/src/data/servicereference/services/ses.json +1 -0
- package/src/data/servicereference/services/shield.json +1 -0
- package/src/data/servicereference/services/signer.json +1 -0
- package/src/data/servicereference/services/signin.json +1 -0
- package/src/data/servicereference/services/simspaceweaver.json +1 -0
- package/src/data/servicereference/services/sms-voice.json +1 -0
- package/src/data/servicereference/services/sms.json +1 -0
- package/src/data/servicereference/services/snow-device-management.json +1 -0
- package/src/data/servicereference/services/snowball.json +1 -0
- package/src/data/servicereference/services/sns.json +1 -0
- package/src/data/servicereference/services/social-messaging.json +1 -0
- package/src/data/servicereference/services/sqlworkbench.json +1 -0
- package/src/data/servicereference/services/sqs.json +1 -0
- package/src/data/servicereference/services/ssm-contacts.json +1 -0
- package/src/data/servicereference/services/ssm-guiconnect.json +1 -0
- package/src/data/servicereference/services/ssm-incidents.json +1 -0
- package/src/data/servicereference/services/ssm-quicksetup.json +1 -0
- package/src/data/servicereference/services/ssm-sap.json +1 -0
- package/src/data/servicereference/services/ssm.json +1 -0
- package/src/data/servicereference/services/ssmmessages.json +1 -0
- package/src/data/servicereference/services/sso-directory.json +1 -0
- package/src/data/servicereference/services/sso-oauth.json +1 -0
- package/src/data/servicereference/services/sso.json +1 -0
- package/src/data/servicereference/services/states.json +1 -0
- package/src/data/servicereference/services/storagegateway.json +1 -0
- package/src/data/servicereference/services/sts.json +1 -0
- package/src/data/servicereference/services/support-console.json +1 -0
- package/src/data/servicereference/services/support.json +1 -0
- package/src/data/servicereference/services/supportapp.json +1 -0
- package/src/data/servicereference/services/supportplans.json +1 -0
- package/src/data/servicereference/services/sustainability.json +1 -0
- package/src/data/servicereference/services/swf.json +1 -0
- package/src/data/servicereference/services/synthetics.json +1 -0
- package/src/data/servicereference/services/tag.json +1 -0
- package/src/data/servicereference/services/tax.json +1 -0
- package/src/data/servicereference/services/textract.json +1 -0
- package/src/data/servicereference/services/thinclient.json +1 -0
- package/src/data/servicereference/services/timestream-influxdb.json +1 -0
- package/src/data/servicereference/services/timestream.json +1 -0
- package/src/data/servicereference/services/tiros.json +1 -0
- package/src/data/servicereference/services/tnb.json +1 -0
- package/src/data/servicereference/services/transcribe.json +1 -0
- package/src/data/servicereference/services/transfer.json +1 -0
- package/src/data/servicereference/services/transform-custom.json +1 -0
- package/src/data/servicereference/services/transform.json +1 -0
- package/src/data/servicereference/services/translate.json +1 -0
- package/src/data/servicereference/services/trustedadvisor.json +1 -0
- package/src/data/servicereference/services/ts.json +1 -0
- package/src/data/servicereference/services/user-subscriptions.json +1 -0
- package/src/data/servicereference/services/uxc.json +1 -0
- package/src/data/servicereference/services/vendor-insights.json +1 -0
- package/src/data/servicereference/services/verified-access.json +1 -0
- package/src/data/servicereference/services/verifiedpermissions.json +1 -0
- package/src/data/servicereference/services/voiceid.json +1 -0
- package/src/data/servicereference/services/vpc-lattice-svcs.json +1 -0
- package/src/data/servicereference/services/vpc-lattice.json +1 -0
- package/src/data/servicereference/services/vpce.json +1 -0
- package/src/data/servicereference/services/waf-regional.json +1 -0
- package/src/data/servicereference/services/waf.json +1 -0
- package/src/data/servicereference/services/wafv2.json +1 -0
- package/src/data/servicereference/services/wam.json +1 -0
- package/src/data/servicereference/services/wellarchitected.json +1 -0
- package/src/data/servicereference/services/wickr.json +1 -0
- package/src/data/servicereference/services/wisdom.json +1 -0
- package/src/data/servicereference/services/workdocs.json +1 -0
- package/src/data/servicereference/services/worklink.json +1 -0
- package/src/data/servicereference/services/workmail.json +1 -0
- package/src/data/servicereference/services/workmailmessageflow.json +1 -0
- package/src/data/servicereference/services/workspaces-instances.json +1 -0
- package/src/data/servicereference/services/workspaces-web.json +1 -0
- package/src/data/servicereference/services/workspaces.json +1 -0
- package/src/data/servicereference/services/xray.json +1 -0
- package/src/data/servicereference/services.json +1 -0
- package/src/extension.d.ts +3 -0
- package/src/extension.js +23 -0
- package/src/grammars/tree-sitter-hcl.wasm +0 -0
- package/src/grammars/tree-sitter-json.wasm +0 -0
- package/src/grammars/tree-sitter-yaml.wasm +0 -0
- package/src/handlers/completion/action-value.d.ts +4 -0
- package/src/handlers/completion/action-value.js +46 -0
- package/src/handlers/completion/condition-block.d.ts +4 -0
- package/src/handlers/completion/condition-block.js +31 -0
- package/src/handlers/completion/condition-key.d.ts +4 -0
- package/src/handlers/completion/condition-key.js +80 -0
- package/src/handlers/completion/condition-operator.d.ts +4 -0
- package/src/handlers/completion/condition-operator.js +22 -0
- package/src/handlers/completion/effect-value.d.ts +4 -0
- package/src/handlers/completion/effect-value.js +14 -0
- package/src/handlers/completion/index.d.ts +14 -0
- package/src/handlers/completion/index.js +96 -0
- package/src/handlers/completion/principal-block-identifier.d.ts +4 -0
- package/src/handlers/completion/principal-block-identifier.js +4 -0
- package/src/handlers/completion/principal-block-type.d.ts +4 -0
- package/src/handlers/completion/principal-block-type.js +24 -0
- package/src/handlers/completion/principal-block.d.ts +4 -0
- package/src/handlers/completion/principal-block.js +28 -0
- package/src/handlers/completion/principal-identifier-completions.d.ts +2 -0
- package/src/handlers/completion/principal-identifier-completions.js +131 -0
- package/src/handlers/completion/principal-type.d.ts +4 -0
- package/src/handlers/completion/principal-type.js +23 -0
- package/src/handlers/completion/principal-typed-value.d.ts +4 -0
- package/src/handlers/completion/principal-typed-value.js +4 -0
- package/src/handlers/completion/principal-value.d.ts +4 -0
- package/src/handlers/completion/principal-value.js +18 -0
- package/src/handlers/completion/resource-value.d.ts +4 -0
- package/src/handlers/completion/resource-value.js +144 -0
- package/src/handlers/completion/statement-block.d.ts +10 -0
- package/src/handlers/completion/statement-block.js +51 -0
- package/src/handlers/completion/statement-key.d.ts +4 -0
- package/src/handlers/completion/statement-key.js +41 -0
- package/src/lib/iam-policy/condition-operators.d.ts +317 -0
- package/src/lib/iam-policy/condition-operators.js +129 -0
- package/src/lib/iam-policy/location.d.ts +71 -0
- package/src/lib/iam-policy/location.js +82 -0
- package/src/lib/iam-policy/partitions.d.ts +116 -0
- package/src/lib/iam-policy/partitions.js +51 -0
- package/src/lib/iam-policy/principals.d.ts +21 -0
- package/src/lib/iam-policy/principals.js +37 -0
- package/src/lib/iam-policy/reference/services.d.ts +22 -0
- package/src/lib/iam-policy/reference/services.js +99 -0
- package/src/lib/iam-policy/reference/types.d.ts +71 -0
- package/src/lib/iam-policy/reference/types.js +1 -0
- package/src/lib/iam-policy/statement-keys.d.ts +8 -0
- package/src/lib/iam-policy/statement-keys.js +159 -0
- package/src/lib/iam-policy/wildcard.d.ts +2 -0
- package/src/lib/iam-policy/wildcard.js +14 -0
- package/src/lib/treesitter/base.d.ts +35 -0
- package/src/lib/treesitter/base.js +50 -0
- package/src/lib/treesitter/hcl.d.ts +9 -0
- package/src/lib/treesitter/hcl.js +888 -0
- package/src/lib/treesitter/json.d.ts +9 -0
- package/src/lib/treesitter/json.js +376 -0
- package/src/lib/treesitter/manager.d.ts +9 -0
- package/src/lib/treesitter/manager.js +66 -0
- package/src/lib/treesitter/yaml.d.ts +9 -0
- package/src/lib/treesitter/yaml.js +878 -0
- package/src/server.d.ts +2 -0
- package/src/server.js +26 -0
|
@@ -0,0 +1,878 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { Language } from 'web-tree-sitter';
|
|
3
|
+
import { TreeBase } from "./base.js";
|
|
4
|
+
export class TreeYaml extends TreeBase {
|
|
5
|
+
static async init() {
|
|
6
|
+
const grammarDir = resolve(import.meta.dirname, '../../grammars');
|
|
7
|
+
const language = await Language.load(resolve(grammarDir, 'tree-sitter-yaml.wasm'));
|
|
8
|
+
return new TreeYaml(language);
|
|
9
|
+
}
|
|
10
|
+
getCursorContext(uri, position) {
|
|
11
|
+
const node = this.getNodeAtPosition(uri, position);
|
|
12
|
+
if (!node)
|
|
13
|
+
return null;
|
|
14
|
+
const nodeBefore = position.column > 0 ? this.getNodeAtPosition(uri, { line: position.line, column: position.column - 1 }) : null;
|
|
15
|
+
const root = this.getTree(uri)?.rootNode;
|
|
16
|
+
if (!root)
|
|
17
|
+
return null;
|
|
18
|
+
const candidates = this.#findAllStatementMappings(root);
|
|
19
|
+
if (candidates.length === 0)
|
|
20
|
+
return this.#tryRecoverFromError(node, position);
|
|
21
|
+
const match = this.#pickStatementMapping(candidates, position);
|
|
22
|
+
if (!match) {
|
|
23
|
+
return this.#resolveEmptyStatementItem(node, candidates, position) ?? this.#tryRecoverFromError(node, position);
|
|
24
|
+
}
|
|
25
|
+
if (match.relationship === 'contains') {
|
|
26
|
+
const context1 = this.#resolveCursorContext(node, match.mapping, position);
|
|
27
|
+
const context2 = nodeBefore ? this.#resolveCursorContext(nodeBefore, match.mapping, position) : null;
|
|
28
|
+
return this.#pickBestCursorContext(context1, context2);
|
|
29
|
+
}
|
|
30
|
+
// relationship === 'extended': cursor is past the mapping
|
|
31
|
+
const context1 = this.#resolveExtendedContext(node, match.mapping, position);
|
|
32
|
+
const context2 = nodeBefore ? this.#resolveExtendedContext(nodeBefore, match.mapping, position) : null;
|
|
33
|
+
return this.#pickBestCursorContext(context1, context2);
|
|
34
|
+
}
|
|
35
|
+
getStatementContext(uri, position) {
|
|
36
|
+
const node = this.getNodeAtPosition(uri, position);
|
|
37
|
+
if (!node)
|
|
38
|
+
return null;
|
|
39
|
+
const root = this.getTree(uri)?.rootNode;
|
|
40
|
+
if (!root)
|
|
41
|
+
return null;
|
|
42
|
+
const candidates = this.#findAllStatementMappings(root);
|
|
43
|
+
const match = this.#pickStatementMapping(candidates, position);
|
|
44
|
+
if (!match)
|
|
45
|
+
return null;
|
|
46
|
+
return this.#extractStatementContext(match.mapping);
|
|
47
|
+
}
|
|
48
|
+
getSiblingKeys(uri, position) {
|
|
49
|
+
const node = this.getNodeAtPosition(uri, position);
|
|
50
|
+
if (!node)
|
|
51
|
+
return [];
|
|
52
|
+
const root = this.getTree(uri)?.rootNode;
|
|
53
|
+
if (!root)
|
|
54
|
+
return [];
|
|
55
|
+
const candidates = this.#findAllStatementMappings(root);
|
|
56
|
+
const match = this.#pickStatementMapping(candidates, position);
|
|
57
|
+
if (!match)
|
|
58
|
+
return [];
|
|
59
|
+
const cursorPath = this.#buildCursorPath(node, match.mapping, position);
|
|
60
|
+
if (!cursorPath || cursorPath.role !== 'key')
|
|
61
|
+
return [];
|
|
62
|
+
return this.#collectExistingKeysAtPath(match.mapping, cursorPath.keys);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Traverse the tree from root, collecting every block_mapping that sits inside
|
|
66
|
+
* a Statement sequence. Skip descendants of matched mappings (they can't nest).
|
|
67
|
+
*/
|
|
68
|
+
#findAllStatementMappings(root) {
|
|
69
|
+
const results = [];
|
|
70
|
+
const visit = (node) => {
|
|
71
|
+
if (node.type === 'block_mapping' && this.#isInsideStatementSequence(node)) {
|
|
72
|
+
results.push(node);
|
|
73
|
+
return; // statement mappings can't nest
|
|
74
|
+
}
|
|
75
|
+
for (const child of node.namedChildren) {
|
|
76
|
+
visit(child);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
visit(root);
|
|
80
|
+
return results;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Pick the best statement mapping for the cursor position.
|
|
84
|
+
* - 'contains': cursor is within the mapping's row span
|
|
85
|
+
* - 'extended': cursor is past the mapping's end but aligned with it
|
|
86
|
+
*/
|
|
87
|
+
#pickStatementMapping(candidates, position) {
|
|
88
|
+
// First, try to find a mapping that contains the cursor
|
|
89
|
+
let containsMatch = null;
|
|
90
|
+
for (const mapping of candidates) {
|
|
91
|
+
if (mapping.startPosition.row <= position.line && position.line <= mapping.endPosition.row) {
|
|
92
|
+
// Prefer deepest (highest startPosition.row)
|
|
93
|
+
if (!containsMatch || mapping.startPosition.row > containsMatch.startPosition.row) {
|
|
94
|
+
containsMatch = mapping;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (containsMatch)
|
|
99
|
+
return { mapping: containsMatch, relationship: 'contains' };
|
|
100
|
+
// Next, try 'extended': cursor is past the mapping's end, column >= mapping's key column,
|
|
101
|
+
// and no other candidate starts between the mapping's end and cursor line
|
|
102
|
+
let extendedMatch = null;
|
|
103
|
+
for (const mapping of candidates) {
|
|
104
|
+
const pastEnd = position.line > mapping.endPosition.row ||
|
|
105
|
+
(position.line === mapping.endPosition.row && position.column >= mapping.endPosition.column);
|
|
106
|
+
if (!pastEnd)
|
|
107
|
+
continue;
|
|
108
|
+
if (position.column < mapping.startPosition.column)
|
|
109
|
+
continue;
|
|
110
|
+
// Don't extend across sibling statement items. If a sibling block_sequence_item
|
|
111
|
+
// starts between this mapping's end and the cursor, the cursor is in a different statement.
|
|
112
|
+
if (this.#hasSiblingItemBetween(mapping, position))
|
|
113
|
+
continue;
|
|
114
|
+
// Don't extend into a different Statement sequence. If the cursor is inside
|
|
115
|
+
// another Statement block_sequence (different from the one containing this mapping),
|
|
116
|
+
// skip this candidate.
|
|
117
|
+
const parentSequence = this.#getParentStatementSequence(mapping);
|
|
118
|
+
if (parentSequence) {
|
|
119
|
+
const cursorInDifferentSequence = candidates.some((other) => {
|
|
120
|
+
if (other.id === mapping.id)
|
|
121
|
+
return false;
|
|
122
|
+
const otherSequence = this.#getParentStatementSequence(other);
|
|
123
|
+
if (!otherSequence || otherSequence.id === parentSequence.id)
|
|
124
|
+
return false;
|
|
125
|
+
return position.line >= otherSequence.startPosition.row && position.line <= otherSequence.endPosition.row;
|
|
126
|
+
});
|
|
127
|
+
if (cursorInDifferentSequence)
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
// Check no other candidate starts between this mapping's end and cursor
|
|
131
|
+
const hasIntervening = candidates.some((other) => other.id !== mapping.id &&
|
|
132
|
+
other.startPosition.row > mapping.endPosition.row &&
|
|
133
|
+
other.startPosition.row <= position.line);
|
|
134
|
+
if (hasIntervening)
|
|
135
|
+
continue;
|
|
136
|
+
// Prefer closest endPosition.row
|
|
137
|
+
if (!extendedMatch || mapping.endPosition.row > extendedMatch.endPosition.row) {
|
|
138
|
+
extendedMatch = mapping;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (extendedMatch)
|
|
142
|
+
return { mapping: extendedMatch, relationship: 'extended' };
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Handle the 'extended' case where the cursor is past the statement mapping.
|
|
147
|
+
* Uses resolveWithinMapping to determine context relative to the mapping.
|
|
148
|
+
*/
|
|
149
|
+
#resolveExtendedContext(cursorNode, statementMapping, position) {
|
|
150
|
+
const resolved = this.#resolveWithinMapping(statementMapping, position);
|
|
151
|
+
if (!resolved)
|
|
152
|
+
return null;
|
|
153
|
+
const partial = this.#extractPartial(cursorNode, position);
|
|
154
|
+
return {
|
|
155
|
+
keys: resolved.keys,
|
|
156
|
+
role: resolved.role,
|
|
157
|
+
partial,
|
|
158
|
+
policyFormat: 'standard',
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Check if a sibling block_sequence_item starts between a mapping's end and the
|
|
163
|
+
* cursor position. This detects when the cursor is in a different statement item.
|
|
164
|
+
*/
|
|
165
|
+
#hasSiblingItemBetween(mapping, position) {
|
|
166
|
+
const containingItem = this.#skipBlockNode(mapping.parent);
|
|
167
|
+
if (containingItem?.type !== 'block_sequence_item')
|
|
168
|
+
return false;
|
|
169
|
+
const sequence = containingItem.parent;
|
|
170
|
+
if (sequence?.type !== 'block_sequence')
|
|
171
|
+
return false;
|
|
172
|
+
return sequence.namedChildren.some((sibling) => sibling.type === 'block_sequence_item' &&
|
|
173
|
+
sibling.id !== containingItem.id &&
|
|
174
|
+
sibling.startPosition.row > mapping.endPosition.row &&
|
|
175
|
+
sibling.startPosition.row <= position.line);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Check if the cursor is inside a Statement sequence in an area with no block_mapping
|
|
179
|
+
* (e.g., a new empty `- ` entry, or past the `-` on the block_sequence node itself).
|
|
180
|
+
* Returns statement-key context if so.
|
|
181
|
+
*
|
|
182
|
+
* Two strategies:
|
|
183
|
+
* 1. Walk up from cursor node — works when cursor lands on/inside the sequence or item.
|
|
184
|
+
* 2. Use candidates' parent sequences — works when cursor lands on an ancestor above
|
|
185
|
+
* the sequence (e.g., a root block_mapping that contains the Statement pair).
|
|
186
|
+
*/
|
|
187
|
+
#resolveEmptyStatementItem(node, candidates, position) {
|
|
188
|
+
// Strategy 1: walk up from cursor node
|
|
189
|
+
let current = node;
|
|
190
|
+
while (current) {
|
|
191
|
+
if (current.type === 'block_sequence_item') {
|
|
192
|
+
const sequence = current.parent;
|
|
193
|
+
if (sequence?.type === 'block_sequence' && this.#isStatementSequence(sequence)) {
|
|
194
|
+
return {
|
|
195
|
+
keys: [],
|
|
196
|
+
role: 'key',
|
|
197
|
+
partial: this.#extractPartial(node, position),
|
|
198
|
+
policyFormat: 'standard',
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (current.type === 'block_sequence' && this.#isStatementSequence(current)) {
|
|
203
|
+
return {
|
|
204
|
+
keys: [],
|
|
205
|
+
role: 'key',
|
|
206
|
+
partial: this.#extractPartial(node, position),
|
|
207
|
+
policyFormat: 'standard',
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
current = current.parent;
|
|
211
|
+
}
|
|
212
|
+
// Strategy 2: check if any candidate's sibling sequence item is empty and on the cursor line
|
|
213
|
+
for (const mapping of candidates) {
|
|
214
|
+
const containingItem = this.#skipBlockNode(mapping.parent);
|
|
215
|
+
if (containingItem?.type !== 'block_sequence_item')
|
|
216
|
+
continue;
|
|
217
|
+
const sequence = containingItem.parent;
|
|
218
|
+
if (sequence?.type !== 'block_sequence')
|
|
219
|
+
continue;
|
|
220
|
+
for (const sibling of sequence.namedChildren) {
|
|
221
|
+
if (sibling.type !== 'block_sequence_item')
|
|
222
|
+
continue;
|
|
223
|
+
if (sibling.startPosition.row !== position.line)
|
|
224
|
+
continue;
|
|
225
|
+
const hasMapping = sibling.namedChildren.some((child) => child.type === 'block_mapping' ||
|
|
226
|
+
(child.type === 'block_node' &&
|
|
227
|
+
child.namedChildren.some((grandChild) => grandChild.type === 'block_mapping')));
|
|
228
|
+
if (!hasMapping) {
|
|
229
|
+
return {
|
|
230
|
+
keys: [],
|
|
231
|
+
role: 'key',
|
|
232
|
+
partial: this.#extractPartial(node, position),
|
|
233
|
+
policyFormat: 'standard',
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Check if a block_sequence is the value of a "Statement" mapping pair.
|
|
242
|
+
*/
|
|
243
|
+
#isStatementSequence(sequence) {
|
|
244
|
+
const sequenceParent = this.#skipBlockNode(sequence.parent);
|
|
245
|
+
return sequenceParent?.type === 'block_mapping_pair' && this.#getPairKeyText(sequenceParent) === 'Statement';
|
|
246
|
+
}
|
|
247
|
+
#resolveCursorContext(node, statementMapping, position) {
|
|
248
|
+
const cursorPath = this.#buildCursorPath(node, statementMapping, position);
|
|
249
|
+
if (!cursorPath)
|
|
250
|
+
return null;
|
|
251
|
+
return { ...cursorPath, policyFormat: 'standard' };
|
|
252
|
+
}
|
|
253
|
+
#pickBestCursorContext(a, b) {
|
|
254
|
+
if (!a)
|
|
255
|
+
return b;
|
|
256
|
+
if (!b)
|
|
257
|
+
return a;
|
|
258
|
+
if (a.partial === '' && b.partial !== '')
|
|
259
|
+
return b;
|
|
260
|
+
if (a.partial === '' && b.partial === '' && b.keys.length > a.keys.length)
|
|
261
|
+
return b;
|
|
262
|
+
return a;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Walk up from cursor to statement mapping, building the chain of mapping pair
|
|
266
|
+
* keys crossed along the way.
|
|
267
|
+
*/
|
|
268
|
+
#buildCursorPath(cursorNode, statementMapping, position) {
|
|
269
|
+
// If cursor lands on a block_sequence on an empty line (no child spans it)
|
|
270
|
+
// and the column is deeper than the nearest ancestor mapping's key column,
|
|
271
|
+
// the user is in a value area but hasn't started an item — no completion context.
|
|
272
|
+
// If the column matches the ancestor mapping's key column, the user is typing
|
|
273
|
+
// a new sibling key, so let the traversal continue.
|
|
274
|
+
if (cursorNode.type === 'block_sequence') {
|
|
275
|
+
const hasChildOnLine = cursorNode.namedChildren.some((child) => child.startPosition.row <= position.line && position.line <= child.endPosition.row);
|
|
276
|
+
if (!hasChildOnLine) {
|
|
277
|
+
const ancestorMapping = this.#findAncestorMapping(cursorNode);
|
|
278
|
+
const keyColumn = ancestorMapping
|
|
279
|
+
? ancestorMapping.startPosition.column
|
|
280
|
+
: statementMapping.startPosition.column;
|
|
281
|
+
if (position.column > keyColumn)
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
const keys = [];
|
|
286
|
+
let role = null;
|
|
287
|
+
let previous = null;
|
|
288
|
+
let current = cursorNode;
|
|
289
|
+
let colonPartial = '';
|
|
290
|
+
while (current && current.id !== statementMapping.id) {
|
|
291
|
+
if (current.type === 'block_mapping' && role === null) {
|
|
292
|
+
// Check for colon-induced mapping (e.g., "- s3:" in a sequence is parsed as
|
|
293
|
+
// a mapping {s3: null} instead of a scalar). If the mapping has one pair with
|
|
294
|
+
// no value and sits inside a block_sequence_item, collapse it: treat the key
|
|
295
|
+
// text + ":" as a partial value and skip past the mapping.
|
|
296
|
+
if (this.#isColonInducedMapping(current)) {
|
|
297
|
+
const pair = current.namedChildren.find((child) => child.type === 'block_mapping_pair');
|
|
298
|
+
const keyText = pair ? this.#getPairKeyText(pair) : null;
|
|
299
|
+
if (keyText) {
|
|
300
|
+
colonPartial = `${keyText}:`;
|
|
301
|
+
previous = current;
|
|
302
|
+
current = current.parent;
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
// Check if cursor is in the value area of a pair on the same line that has
|
|
307
|
+
// no value child (e.g., "Service: $cursor$" where the pair ends at the colon).
|
|
308
|
+
const pairOnLine = current.namedChildren.find((child) => child.type === 'block_mapping_pair' &&
|
|
309
|
+
child.startPosition.row === position.line &&
|
|
310
|
+
child.namedChildren.length === 1 &&
|
|
311
|
+
position.column > child.endPosition.column);
|
|
312
|
+
if (pairOnLine) {
|
|
313
|
+
const pairKey = this.#getPairKeyText(pairOnLine);
|
|
314
|
+
if (pairKey) {
|
|
315
|
+
keys.unshift(pairKey);
|
|
316
|
+
role = 'value';
|
|
317
|
+
previous = current;
|
|
318
|
+
current = current.parent;
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
// When cursor lands on an inner block_mapping (not the statement mapping),
|
|
323
|
+
// check if the cursor is actually outside this mapping (column < key column).
|
|
324
|
+
// If so, skip it — the cursor belongs to a parent mapping level.
|
|
325
|
+
if (current.id !== statementMapping.id && position.column < current.startPosition.column) {
|
|
326
|
+
previous = current;
|
|
327
|
+
current = current.parent;
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
// Resolve within the inner mapping to detect nested pair context (e.g.,
|
|
331
|
+
// cursor on empty line inside "StringEquals:" maps to keys=['StringEquals'], role='key').
|
|
332
|
+
if (current.id !== statementMapping.id) {
|
|
333
|
+
const resolved = this.#resolveWithinMapping(current, position);
|
|
334
|
+
if (resolved && resolved.keys.length > 0) {
|
|
335
|
+
keys.unshift(...resolved.keys);
|
|
336
|
+
role = resolved.role;
|
|
337
|
+
previous = current;
|
|
338
|
+
current = current.parent;
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
role = 'key';
|
|
343
|
+
}
|
|
344
|
+
// When nodeBefore lands on the ":" inside a colon-induced mapping, we enter
|
|
345
|
+
// via the inner pair (setting role='value', keys=['s3']). When we reach the
|
|
346
|
+
// parent mapping, undo that contribution and collapse to colonPartial.
|
|
347
|
+
if (current.type === 'block_mapping' && role !== null && this.#isColonInducedMapping(current)) {
|
|
348
|
+
const pair = current.namedChildren.find((child) => child.type === 'block_mapping_pair');
|
|
349
|
+
const keyText = pair ? this.#getPairKeyText(pair) : null;
|
|
350
|
+
if (keyText && keys.length > 0 && keys[0] === keyText) {
|
|
351
|
+
keys.shift();
|
|
352
|
+
colonPartial = `${keyText}:`;
|
|
353
|
+
role = null;
|
|
354
|
+
previous = current;
|
|
355
|
+
current = current.parent;
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (current.type === 'block_mapping_pair') {
|
|
360
|
+
const pairKey = this.#getPairKeyText(current);
|
|
361
|
+
if (role === null) {
|
|
362
|
+
// Innermost pair — determine key vs value
|
|
363
|
+
const isOnKey = previous && current.namedChildren[0] && previous.id === current.namedChildren[0].id;
|
|
364
|
+
// Tree-sitter extends a pair's value span to cover trailing whitespace.
|
|
365
|
+
// If the cursor column matches the parent mapping's key column, the user
|
|
366
|
+
// is typing a new sibling key, not editing this pair's value.
|
|
367
|
+
const parentMapping = current.parent;
|
|
368
|
+
const isAtParentKeyColumn = parentMapping?.type === 'block_mapping' && position.column === parentMapping.startPosition.column;
|
|
369
|
+
if (isOnKey || isAtParentKeyColumn) {
|
|
370
|
+
role = 'key';
|
|
371
|
+
}
|
|
372
|
+
else {
|
|
373
|
+
role = 'value';
|
|
374
|
+
if (pairKey)
|
|
375
|
+
keys.unshift(pairKey);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
// Outer pair — cursor was in its value subtree
|
|
380
|
+
if (pairKey)
|
|
381
|
+
keys.unshift(pairKey);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
previous = current;
|
|
385
|
+
current = current.parent;
|
|
386
|
+
}
|
|
387
|
+
// When cursor falls on the statementMapping (e.g., after an incomplete pair or
|
|
388
|
+
// in a multi-line pair's value area), find the owning pair. If the cursor is
|
|
389
|
+
// indented past the mapping's key column, it's in a value area — find the
|
|
390
|
+
// last pair starting before the cursor position.
|
|
391
|
+
if (role === null && cursorNode.id === statementMapping.id) {
|
|
392
|
+
const resolved = this.#resolveWithinMapping(statementMapping, position);
|
|
393
|
+
if (!resolved)
|
|
394
|
+
return null;
|
|
395
|
+
keys.push(...resolved.keys);
|
|
396
|
+
role = resolved.role;
|
|
397
|
+
}
|
|
398
|
+
if (role === null)
|
|
399
|
+
role = 'key';
|
|
400
|
+
const partial = colonPartial || this.#extractPartial(cursorNode, position);
|
|
401
|
+
return { keys, role, partial };
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Resolve the cursor's position within a block_mapping by finding the pair covering
|
|
405
|
+
* the cursor line and recursively descending into nested mappings.
|
|
406
|
+
*/
|
|
407
|
+
#resolveWithinMapping(mapping, position) {
|
|
408
|
+
const keyColumn = mapping.startPosition.column;
|
|
409
|
+
if (position.column < keyColumn)
|
|
410
|
+
return null;
|
|
411
|
+
if (position.column === keyColumn)
|
|
412
|
+
return { keys: [], role: 'key' };
|
|
413
|
+
let pairBeforeCursor = null;
|
|
414
|
+
for (const child of mapping.namedChildren) {
|
|
415
|
+
if (child.type !== 'block_mapping_pair')
|
|
416
|
+
continue;
|
|
417
|
+
if (child.startPosition.row > position.line)
|
|
418
|
+
break;
|
|
419
|
+
pairBeforeCursor = child;
|
|
420
|
+
}
|
|
421
|
+
if (!pairBeforeCursor)
|
|
422
|
+
return null;
|
|
423
|
+
const pairKey = this.#getPairKeyText(pairBeforeCursor);
|
|
424
|
+
if (!pairKey)
|
|
425
|
+
return null;
|
|
426
|
+
if (position.line > pairBeforeCursor.endPosition.row) {
|
|
427
|
+
// Cursor is past the pair — if the pair has no value, the cursor is at a key
|
|
428
|
+
// position within the pair's value area (e.g., `Principal:\n $cursor$`).
|
|
429
|
+
const hasValue = pairBeforeCursor.namedChildren.length > 1;
|
|
430
|
+
if (!hasValue) {
|
|
431
|
+
return { keys: [pairKey], role: 'key' };
|
|
432
|
+
}
|
|
433
|
+
// The pair has a value and cursor is past it — try descending into a nested
|
|
434
|
+
// mapping (e.g., cursor on empty line after `Service:` entries, at the same
|
|
435
|
+
// column as the nested mapping's keys).
|
|
436
|
+
const nestedMapping = this.#findValueBlockMapping(pairBeforeCursor);
|
|
437
|
+
if (nestedMapping) {
|
|
438
|
+
const inner = this.#resolveWithinMapping(nestedMapping, position);
|
|
439
|
+
if (inner)
|
|
440
|
+
return { keys: [pairKey, ...inner.keys], role: inner.role };
|
|
441
|
+
}
|
|
442
|
+
// Check if the pair's value is a block_sequence and the cursor is within
|
|
443
|
+
// or immediately after it at the sequence's item column (e.g., adding a
|
|
444
|
+
// new `- ` entry under `Service:`).
|
|
445
|
+
const valueSequence = this.#findValueBlockSequence(pairBeforeCursor);
|
|
446
|
+
if (valueSequence &&
|
|
447
|
+
position.line <= valueSequence.endPosition.row &&
|
|
448
|
+
position.column >= valueSequence.startPosition.column) {
|
|
449
|
+
return { keys: [pairKey], role: 'value' };
|
|
450
|
+
}
|
|
451
|
+
return null;
|
|
452
|
+
}
|
|
453
|
+
// Cursor is within the pair's span — try to descend into a nested block_mapping.
|
|
454
|
+
const nestedMapping = this.#findValueBlockMapping(pairBeforeCursor);
|
|
455
|
+
if (nestedMapping) {
|
|
456
|
+
const inner = this.#resolveWithinMapping(nestedMapping, position);
|
|
457
|
+
if (inner) {
|
|
458
|
+
return { keys: [pairKey, ...inner.keys], role: inner.role };
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return { keys: [pairKey], role: 'value' };
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Find a block_mapping in a pair's value, unwrapping block_node if present.
|
|
465
|
+
*/
|
|
466
|
+
#findValueBlockMapping(pair) {
|
|
467
|
+
if (pair.namedChildren.length < 2)
|
|
468
|
+
return null;
|
|
469
|
+
let value = pair.namedChildren[1];
|
|
470
|
+
if (value.type === 'block_node')
|
|
471
|
+
value = value.namedChildren[0] ?? null;
|
|
472
|
+
return value?.type === 'block_mapping' ? value : null;
|
|
473
|
+
}
|
|
474
|
+
/**
|
|
475
|
+
* Find a block_sequence in a pair's value, unwrapping block_node if present.
|
|
476
|
+
*/
|
|
477
|
+
#findValueBlockSequence(pair) {
|
|
478
|
+
if (pair.namedChildren.length < 2)
|
|
479
|
+
return null;
|
|
480
|
+
let value = pair.namedChildren[1];
|
|
481
|
+
if (value.type === 'block_node')
|
|
482
|
+
value = value.namedChildren[0] ?? null;
|
|
483
|
+
return value?.type === 'block_sequence' ? value : null;
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Find the nearest ancestor block_mapping above a node, skipping block_node wrappers.
|
|
487
|
+
*/
|
|
488
|
+
#findAncestorMapping(node) {
|
|
489
|
+
let current = node.parent;
|
|
490
|
+
while (current) {
|
|
491
|
+
if (current.type === 'block_mapping')
|
|
492
|
+
return current;
|
|
493
|
+
current = current.parent;
|
|
494
|
+
}
|
|
495
|
+
return null;
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Detect a colon-induced mapping: a block_mapping with exactly one pair that has
|
|
499
|
+
* no value, sitting inside a block_sequence_item (e.g., "- s3:" parsed as {s3: null}).
|
|
500
|
+
*/
|
|
501
|
+
#isColonInducedMapping(mapping) {
|
|
502
|
+
const pairs = mapping.namedChildren.filter((child) => child.type === 'block_mapping_pair');
|
|
503
|
+
if (pairs.length !== 1)
|
|
504
|
+
return false;
|
|
505
|
+
if (pairs[0].namedChildren.length > 1)
|
|
506
|
+
return false;
|
|
507
|
+
let parent = mapping.parent;
|
|
508
|
+
while (parent && parent.type === 'block_node')
|
|
509
|
+
parent = parent.parent;
|
|
510
|
+
return parent?.type === 'block_sequence_item';
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Walk up, skipping block_node wrappers.
|
|
514
|
+
*/
|
|
515
|
+
#skipBlockNode(node) {
|
|
516
|
+
return node?.type === 'block_node' ? node.parent : node;
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Check that a block_mapping is a direct child of a block_sequence_item
|
|
520
|
+
* whose parent block_sequence is the value of a "Statement" mapping pair.
|
|
521
|
+
*
|
|
522
|
+
* Expected chain (block_node is optional at each level):
|
|
523
|
+
* block_mapping > block_node? > block_sequence_item > block_sequence > block_node? > block_mapping_pair
|
|
524
|
+
*/
|
|
525
|
+
#getParentStatementSequence(mapping) {
|
|
526
|
+
const item = this.#skipBlockNode(mapping.parent);
|
|
527
|
+
if (item?.type !== 'block_sequence_item')
|
|
528
|
+
return null;
|
|
529
|
+
const sequence = item.parent;
|
|
530
|
+
if (sequence?.type !== 'block_sequence')
|
|
531
|
+
return null;
|
|
532
|
+
return sequence;
|
|
533
|
+
}
|
|
534
|
+
#isInsideStatementSequence(mapping) {
|
|
535
|
+
let node = this.#skipBlockNode(mapping.parent);
|
|
536
|
+
if (node?.type !== 'block_sequence_item')
|
|
537
|
+
return false;
|
|
538
|
+
node = node.parent;
|
|
539
|
+
if (node?.type !== 'block_sequence')
|
|
540
|
+
return false;
|
|
541
|
+
node = this.#skipBlockNode(node.parent);
|
|
542
|
+
if (node?.type !== 'block_mapping_pair')
|
|
543
|
+
return false;
|
|
544
|
+
return this.#getPairKeyText(node) === 'Statement';
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Get the unquoted text of a block_mapping_pair's key.
|
|
548
|
+
*/
|
|
549
|
+
#getPairKeyText(pair) {
|
|
550
|
+
const keyFlow = pair.namedChildren.find((child) => child.type === 'flow_node');
|
|
551
|
+
return this.#getScalarText(keyFlow);
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Get the unquoted text content of a flow_node's scalar child.
|
|
555
|
+
*/
|
|
556
|
+
#getScalarText(flowNode) {
|
|
557
|
+
const scalar = flowNode?.namedChildren.find((child) => child.type !== 'tag');
|
|
558
|
+
if (!scalar)
|
|
559
|
+
return null;
|
|
560
|
+
if (scalar.type === 'plain_scalar') {
|
|
561
|
+
return scalar.namedChildren.find((child) => child.type === 'string_scalar')?.text ?? null;
|
|
562
|
+
}
|
|
563
|
+
if (scalar.type === 'double_quote_scalar' || scalar.type === 'single_quote_scalar') {
|
|
564
|
+
return scalar.text.slice(1, -1);
|
|
565
|
+
}
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* Walk down a mapping following a key path, then collect existing keys from
|
|
570
|
+
* the innermost mapping. E.g., path=['Condition'] finds the Condition pair's
|
|
571
|
+
* value mapping and returns its keys.
|
|
572
|
+
*/
|
|
573
|
+
#collectExistingKeysAtPath(mapping, keys) {
|
|
574
|
+
let current = mapping;
|
|
575
|
+
for (const key of keys) {
|
|
576
|
+
const pair = current.namedChildren.find((child) => child.type === 'block_mapping_pair' && this.#getPairKeyText(child) === key);
|
|
577
|
+
if (!pair)
|
|
578
|
+
return [];
|
|
579
|
+
const nested = this.#findValueBlockMapping(pair);
|
|
580
|
+
if (!nested)
|
|
581
|
+
return [];
|
|
582
|
+
current = nested;
|
|
583
|
+
}
|
|
584
|
+
return this.#collectExistingKeys(current);
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Collect all key names from block_mapping_pair children of a block_mapping.
|
|
588
|
+
*/
|
|
589
|
+
#collectExistingKeys(mapping) {
|
|
590
|
+
return mapping.namedChildren
|
|
591
|
+
.filter((child) => child.type === 'block_mapping_pair')
|
|
592
|
+
.map((pair) => this.#getPairKeyText(pair))
|
|
593
|
+
.filter((key) => key !== null);
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Extract the partial text the user has typed, from the nearest scalar node
|
|
597
|
+
* up to the cursor position.
|
|
598
|
+
*/
|
|
599
|
+
#extractPartial(node, position) {
|
|
600
|
+
let current = node;
|
|
601
|
+
while (current) {
|
|
602
|
+
if (current.type === 'string_scalar') {
|
|
603
|
+
return this.#sliceToPosition(current.text, current.startPosition.column, position, node);
|
|
604
|
+
}
|
|
605
|
+
if (current.type === 'double_quote_scalar' || current.type === 'single_quote_scalar') {
|
|
606
|
+
return this.#sliceToPosition(current.text.slice(1, -1), current.startPosition.column + 1, position, node);
|
|
607
|
+
}
|
|
608
|
+
if (current.type === 'block_mapping' || current.type === 'block_mapping_pair')
|
|
609
|
+
break;
|
|
610
|
+
current = current.parent;
|
|
611
|
+
}
|
|
612
|
+
return '';
|
|
613
|
+
}
|
|
614
|
+
#sliceToPosition(text, startColumn, position, node) {
|
|
615
|
+
if (position.line === node.startPosition.row) {
|
|
616
|
+
return text.slice(0, position.column - startColumn);
|
|
617
|
+
}
|
|
618
|
+
return text;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* When tree-sitter produces a root-level ERROR (e.g., unterminated quote in
|
|
622
|
+
* "Effect: "), try to recover context from the ERROR node's children.
|
|
623
|
+
*/
|
|
624
|
+
#tryRecoverFromError(node, position) {
|
|
625
|
+
let errorNode = node;
|
|
626
|
+
while (errorNode && errorNode.type !== 'ERROR') {
|
|
627
|
+
errorNode = errorNode.parent;
|
|
628
|
+
}
|
|
629
|
+
// If no ERROR ancestor, look for an ERROR sibling in the root tree
|
|
630
|
+
// (e.g., `Action: s3:` splits into ERROR + document at the colon boundary)
|
|
631
|
+
if (!errorNode) {
|
|
632
|
+
let root = node;
|
|
633
|
+
while (root.parent)
|
|
634
|
+
root = root.parent;
|
|
635
|
+
for (const child of root.children) {
|
|
636
|
+
if (child.type === 'ERROR' && child.endPosition.row >= position.line) {
|
|
637
|
+
errorNode = child;
|
|
638
|
+
break;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
if (!errorNode)
|
|
643
|
+
return null;
|
|
644
|
+
// Scan ERROR children for a Statement-like structure: "Statement" + ":"
|
|
645
|
+
let foundStatement = false;
|
|
646
|
+
let lastKey = null;
|
|
647
|
+
for (const child of errorNode.children) {
|
|
648
|
+
if (!foundStatement) {
|
|
649
|
+
if (child.type === 'flow_node') {
|
|
650
|
+
const text = this.#getScalarText(child);
|
|
651
|
+
if (text === 'Statement')
|
|
652
|
+
foundStatement = true;
|
|
653
|
+
}
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
// After finding "Statement", look for a key on the cursor line
|
|
657
|
+
if (child.type === 'flow_node' && child.startPosition.row === position.line) {
|
|
658
|
+
const keyText = this.#getScalarText(child);
|
|
659
|
+
if (!keyText)
|
|
660
|
+
continue;
|
|
661
|
+
return {
|
|
662
|
+
keys: [keyText],
|
|
663
|
+
role: 'value',
|
|
664
|
+
partial: '',
|
|
665
|
+
policyFormat: 'standard',
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
// Handle block_mapping_pair on cursor line (e.g., `Action: s3:` where
|
|
669
|
+
// the pair is inside the ERROR but the colon splits into a new document)
|
|
670
|
+
if (child.type === 'block_mapping_pair' && child.startPosition.row === position.line) {
|
|
671
|
+
const pairKey = this.#getPairKeyText(child);
|
|
672
|
+
if (!pairKey)
|
|
673
|
+
continue;
|
|
674
|
+
const valueText = this.#getPairValueText(child) ?? '';
|
|
675
|
+
// If cursor is past the ERROR end (colon continuation), append ":"
|
|
676
|
+
const colonSuffix = errorNode.endPosition.row === position.line && position.column > errorNode.endPosition.column ? ':' : '';
|
|
677
|
+
return {
|
|
678
|
+
keys: [pairKey],
|
|
679
|
+
role: 'value',
|
|
680
|
+
partial: valueText + colonSuffix,
|
|
681
|
+
policyFormat: 'standard',
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
// Track the last statement-level key seen before the cursor line (e.g.,
|
|
685
|
+
// "Resource" on line 4 when cursor is on line 5 inside a broken sequence item)
|
|
686
|
+
if (child.type === 'flow_node' && child.startPosition.row < position.line) {
|
|
687
|
+
const keyText = this.#getScalarText(child);
|
|
688
|
+
if (keyText) {
|
|
689
|
+
lastKey = keyText;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
// If we found a key before cursor line and the cursor is in its value area
|
|
694
|
+
// (e.g., `Resource:\n - !Sub "arn:` where the open quote breaks the parse)
|
|
695
|
+
if (lastKey) {
|
|
696
|
+
const partial = this.#extractPartialFromErrorNode(errorNode, position);
|
|
697
|
+
return {
|
|
698
|
+
keys: [lastKey],
|
|
699
|
+
role: 'value',
|
|
700
|
+
partial,
|
|
701
|
+
policyFormat: 'standard',
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
return null;
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Extract the partial text from an ERROR node for the cursor line.
|
|
708
|
+
* Scans ERROR children on the cursor line to find the last child before/at the
|
|
709
|
+
* cursor, then takes the substring from its end to the cursor column.
|
|
710
|
+
*/
|
|
711
|
+
#extractPartialFromErrorNode(errorNode, position) {
|
|
712
|
+
// Find the rightmost child on the cursor line that ends at or before the cursor
|
|
713
|
+
let afterColumn = 0;
|
|
714
|
+
for (const child of errorNode.children) {
|
|
715
|
+
if (child.startPosition.row !== position.line)
|
|
716
|
+
continue;
|
|
717
|
+
if (child.endPosition.column <= position.column) {
|
|
718
|
+
afterColumn = child.endPosition.column;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
// Extract from the ERROR node's text: find the cursor line and slice
|
|
722
|
+
const lines = errorNode.text.split('\n');
|
|
723
|
+
const lineIndex = position.line - errorNode.startPosition.row;
|
|
724
|
+
if (lineIndex < 0 || lineIndex >= lines.length)
|
|
725
|
+
return '';
|
|
726
|
+
const line = lines[lineIndex];
|
|
727
|
+
const startColumn = lineIndex === 0 ? errorNode.startPosition.column : 0;
|
|
728
|
+
return line.slice(afterColumn - startColumn, position.column - startColumn);
|
|
729
|
+
}
|
|
730
|
+
#getPairValueText(pair) {
|
|
731
|
+
const flowNodes = pair.namedChildren.filter((child) => child.type === 'flow_node');
|
|
732
|
+
return flowNodes.length >= 2 ? this.#getScalarText(flowNodes[1]) : null;
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Read string values from a mapping pair's value (scalar, block sequence, or flow sequence).
|
|
736
|
+
*/
|
|
737
|
+
#readPairStringValues(pair) {
|
|
738
|
+
if (pair.namedChildren.length < 2)
|
|
739
|
+
return [];
|
|
740
|
+
const valueNode = pair.namedChildren[1];
|
|
741
|
+
// Direct flow_node scalar
|
|
742
|
+
if (valueNode.type === 'flow_node') {
|
|
743
|
+
const text = this.#getScalarText(valueNode);
|
|
744
|
+
return text ? [text] : [];
|
|
745
|
+
}
|
|
746
|
+
// block_node wrapping a block_sequence or flow_node
|
|
747
|
+
const inner = valueNode.type === 'block_node' ? (valueNode.namedChildren[0] ?? null) : valueNode;
|
|
748
|
+
if (!inner)
|
|
749
|
+
return [];
|
|
750
|
+
if (inner.type === 'flow_node') {
|
|
751
|
+
const text = this.#getScalarText(inner);
|
|
752
|
+
return text ? [text] : [];
|
|
753
|
+
}
|
|
754
|
+
// Block sequence (e.g., Action:\n - s3:GetObject\n - s3:PutObject)
|
|
755
|
+
if (inner.type === 'block_sequence') {
|
|
756
|
+
const values = [];
|
|
757
|
+
for (const item of inner.namedChildren) {
|
|
758
|
+
if (item.type !== 'block_sequence_item')
|
|
759
|
+
continue;
|
|
760
|
+
const flowNode = item.namedChildren.find((child) => child.type === 'flow_node');
|
|
761
|
+
const text = this.#getScalarText(flowNode);
|
|
762
|
+
if (text)
|
|
763
|
+
values.push(text);
|
|
764
|
+
}
|
|
765
|
+
return values;
|
|
766
|
+
}
|
|
767
|
+
// Flow sequence (e.g., Action: [s3:GetObject, s3:PutObject])
|
|
768
|
+
if (inner.type === 'flow_sequence') {
|
|
769
|
+
const values = [];
|
|
770
|
+
for (const flowItem of inner.namedChildren) {
|
|
771
|
+
if (flowItem.type !== 'flow_node')
|
|
772
|
+
continue;
|
|
773
|
+
const text = this.#getScalarText(flowItem);
|
|
774
|
+
if (text)
|
|
775
|
+
values.push(text);
|
|
776
|
+
}
|
|
777
|
+
return values;
|
|
778
|
+
}
|
|
779
|
+
return [];
|
|
780
|
+
}
|
|
781
|
+
/**
|
|
782
|
+
* Extract the statement structure from a YAML statement block_mapping.
|
|
783
|
+
*/
|
|
784
|
+
#extractStatementContext(statementMapping) {
|
|
785
|
+
const context = {};
|
|
786
|
+
for (const child of statementMapping.namedChildren) {
|
|
787
|
+
if (child.type !== 'block_mapping_pair')
|
|
788
|
+
continue;
|
|
789
|
+
const key = this.#getPairKeyText(child);
|
|
790
|
+
if (key === 'Sid') {
|
|
791
|
+
const text = this.#getPairValueText(child);
|
|
792
|
+
if (text)
|
|
793
|
+
context.Sid = text;
|
|
794
|
+
}
|
|
795
|
+
else if (key === 'Effect') {
|
|
796
|
+
const text = this.#getPairValueText(child);
|
|
797
|
+
if (text)
|
|
798
|
+
context.Effect = text;
|
|
799
|
+
}
|
|
800
|
+
else if (key === 'Action') {
|
|
801
|
+
context.Action = this.#readPairStringValues(child);
|
|
802
|
+
}
|
|
803
|
+
else if (key === 'NotAction') {
|
|
804
|
+
context.NotAction = this.#readPairStringValues(child);
|
|
805
|
+
}
|
|
806
|
+
else if (key === 'Resource') {
|
|
807
|
+
context.Resource = this.#readPairStringValues(child);
|
|
808
|
+
}
|
|
809
|
+
else if (key === 'NotResource') {
|
|
810
|
+
context.NotResource = this.#readPairStringValues(child);
|
|
811
|
+
}
|
|
812
|
+
else if (key === 'Principal' || key === 'NotPrincipal') {
|
|
813
|
+
const value = this.#readPrincipalValue(child);
|
|
814
|
+
if (value) {
|
|
815
|
+
if (key === 'Principal')
|
|
816
|
+
context.Principal = value;
|
|
817
|
+
else
|
|
818
|
+
context.NotPrincipal = value;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
else if (key === 'Condition') {
|
|
822
|
+
context.Condition = this.#readConditionValue(child);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
return context;
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* Read a Principal/NotPrincipal value: either "*" (bare string) or a mapping of type → values.
|
|
829
|
+
*/
|
|
830
|
+
#readPrincipalValue(pair) {
|
|
831
|
+
const values = this.#readPairStringValues(pair);
|
|
832
|
+
if (values.length === 1 && values[0] === '*')
|
|
833
|
+
return '*';
|
|
834
|
+
const mapping = this.#findValueBlockMapping(pair);
|
|
835
|
+
if (!mapping)
|
|
836
|
+
return null;
|
|
837
|
+
const result = {};
|
|
838
|
+
for (const child of mapping.namedChildren) {
|
|
839
|
+
if (child.type !== 'block_mapping_pair')
|
|
840
|
+
continue;
|
|
841
|
+
const typeKey = this.#getPairKeyText(child);
|
|
842
|
+
if (typeKey)
|
|
843
|
+
result[typeKey] = this.#readPairStringValues(child);
|
|
844
|
+
}
|
|
845
|
+
return Object.keys(result).length > 0 ? result : null;
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* Read a Condition block: mapping of operator → (mapping of key → values).
|
|
849
|
+
*/
|
|
850
|
+
#readConditionValue(pair) {
|
|
851
|
+
const result = {};
|
|
852
|
+
const outerMapping = this.#findValueBlockMapping(pair);
|
|
853
|
+
if (!outerMapping)
|
|
854
|
+
return result;
|
|
855
|
+
for (const operatorPair of outerMapping.namedChildren) {
|
|
856
|
+
if (operatorPair.type !== 'block_mapping_pair')
|
|
857
|
+
continue;
|
|
858
|
+
const operator = this.#getPairKeyText(operatorPair);
|
|
859
|
+
if (!operator)
|
|
860
|
+
continue;
|
|
861
|
+
const innerMapping = this.#findValueBlockMapping(operatorPair);
|
|
862
|
+
if (!innerMapping) {
|
|
863
|
+
result[operator] = {};
|
|
864
|
+
continue;
|
|
865
|
+
}
|
|
866
|
+
const keys = {};
|
|
867
|
+
for (const keyPair of innerMapping.namedChildren) {
|
|
868
|
+
if (keyPair.type !== 'block_mapping_pair')
|
|
869
|
+
continue;
|
|
870
|
+
const conditionKey = this.#getPairKeyText(keyPair);
|
|
871
|
+
if (conditionKey)
|
|
872
|
+
keys[conditionKey] = this.#readPairStringValues(keyPair);
|
|
873
|
+
}
|
|
874
|
+
result[operator] = keys;
|
|
875
|
+
}
|
|
876
|
+
return result;
|
|
877
|
+
}
|
|
878
|
+
}
|