예제 #1
0
        /// <summary>
        /// Emits a sequence end.
        /// </summary>
        /// <param name="event">The event.</param>
        private void EmitSequenceEnd(HclEvent @event)
        {
            GetTypedEvent <SequenceEnd>(@event);

            this.state = this.PopState();

            if (this.previousState == EmitterState.BlockList)
            {
                // End of block list
                while (this.state == EmitterState.BlockList)
                {
                    this.state = this.PopState();
                }

                return;
            }

            this.indent = this.indents.Pop();
            this.WriteIndent();
            this.WriteIndicator("]", false, false, false);

            if (this.state == EmitterState.Sequence)
            {
                this.Write(',');
            }
        }
예제 #2
0
        /// <summary>
        /// Emits the next event.
        /// Events are queued until an entire resource is collected, the that resource is written out.
        /// </summary>
        /// <param name="event">The event.</param>
        public void Emit(HclEvent @event)
        {
            this.events.Enqueue(@event);

            if (@event.Type != EventType.ResourceEnd)
            {
                return;
            }

            try
            {
                // Eliminate attributes we don't want to serialize,
                // thus everything remaining in the queue following
                // this operation will be emitted.
                new EventQueuePreprocessor(this.events).ProcessQueue();

                this.state = EmitterState.Resource;
                while (this.events.Any())
                {
                    this.EmitNode(this.events.Dequeue());
                }
            }
            catch (HclSerializerException)
            {
                throw;
            }
            catch (Exception e)
            {
                throw new HclSerializerException(
                          $"Internal error: {e.Message}",
                          this.currentResourceName,
                          this.currentResourceType,
                          e);
            }
        }
예제 #3
0
        /// <summary>
        /// Emits a mapping start.
        /// </summary>
        /// <param name="event">A <see cref="MappingStart"/> event.</param>
        private void EmitMappingStart(HclEvent @event)
        {
            GetTypedEvent <MappingStart>(@event);

            this.PushState(this.state);
            this.state = EmitterState.Mapping;
            this.WriteIndicator("{", true, false, false);
            this.IncreaseIndent();
            this.WriteIndent();
        }
예제 #4
0
        /// <summary>
        /// Asserts an event is of the requested type and casts to it.
        /// </summary>
        /// <typeparam name="T">Expected subtype of the event passed as argument.</typeparam>
        /// <param name="event">The event.</param>
        /// <returns>Type casted event.</returns>
        /// <exception cref="System.ArgumentException">Expected {typeof(T).Name} - event</exception>
        private static T GetTypedEvent <T>(HclEvent @event)
            where T : HclEvent
        {
            if (!(@event is T hclEvent))
            {
                throw new ArgumentException($"Expected {typeof(T).Name}", nameof(@event));
            }

            return(hclEvent);
        }
예제 #5
0
        /// <summary>
        /// Emits a mapping key.
        /// </summary>
        /// <param name="event">A <see cref="MappingKey"/> event.</param>
        private void EmitMappingKey(HclEvent @event)
        {
            var key = GetTypedEvent <MappingKey>(@event);

            if (EmitLifecycle.ContainsKey(this.currentResourceType) &&
                EmitLifecycle[this.currentResourceType].Contains(key.Path))
            {
                this.lifecycleKeys.Add(key.Path);
            }

            // Don't push path for repeating block key
            if (!key.IsBlockKey)
            {
                if (!this.isJson)
                {
                    this.currentPath = key.Path;
                }

                this.WriteIndent();
            }
            else
            {
                // ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault
                switch (key.InitialAnalysis)
                {
                case AttributeContent.BlockList:

                    this.blockKeys.Push(key);
                    this.currentBlockKey = key;
                    this.PushState(this.state);
                    this.state = EmitterState.BlockList;
                    break;

                case AttributeContent.BlockObject:

                    this.state = EmitterState.BlockObject;
                    break;

                default:

                    this.state = EmitterState.Mapping;
                    break;
                }

                this.WriteBreak();
                this.WriteIndent();
            }

            this.EmitScalar(@event);

            if (this.state == EmitterState.Mapping)
            {
                this.WriteIndicator("=", true, false, false);
            }
        }
예제 #6
0
        /// <summary>
        /// Emits a scalar value.
        /// </summary>
        /// <param name="event">A <see cref="ScalarValue"/> event.</param>
        private void EmitScalarValue(HclEvent @event)
        {
            var scalar = GetTypedEvent <ScalarValue>(@event);

            if (this.state == EmitterState.Sequence)
            {
                this.WriteIndent();
            }

            this.EmitScalar(this.resourceTraits.ApplyDefaultValue(this.currentPath, scalar));
        }
예제 #7
0
        /// <summary>
        /// Emits a policy start.
        /// </summary>
        /// <param name="event">The event.</param>
        private void EmitJsonStart(HclEvent @event)
        {
            GetTypedEvent <JsonStart>(@event);

            this.isJson = true;
            this.PushState(this.state);
            this.state = EmitterState.Json;
            this.WriteIndicator("jsonencode(", true, false, true);
            this.IncreaseIndent();
            this.WriteIndent();
        }
예제 #8
0
        /// <summary>
        /// Emits the resource start.
        /// </summary>
        /// <param name="event">A <see cref="ResourceStart"/> event.</param>
        private void EmitResourceStart(HclEvent @event)
        {
            var rs = GetTypedEvent <ResourceStart>(@event);

            this.Write("resource");
            this.isWhitespace        = false;
            this.resourceTraits      = AwsSchema.GetResourceTraits(rs.ResourceType);
            this.currentResourceName = rs.ResourceName;
            this.currentResourceType = rs.ResourceType;
            this.EmitScalar(new Scalar(rs.ResourceType, true));
            this.EmitScalar(new Scalar(rs.ResourceName, true));
        }
예제 #9
0
        /// <summary>
        /// Emits a policy end.
        /// </summary>
        /// <param name="event">The event.</param>
        private void EmitJsonEnd(HclEvent @event)
        {
            GetTypedEvent <JsonEnd>(@event);

            this.isJson = false;
            this.indent = this.indents.Pop();
            this.state  = this.PopState();
            this.WriteIndent();
            this.WriteIndicator(")", false, false, false);

            if (this.state == EmitterState.Sequence)
            {
                this.Write(',');
            }
        }
예제 #10
0
        /// <summary>
        /// Emits a scalar.
        /// </summary>
        /// <param name="event">The event.</param>
        private void EmitScalar(HclEvent @event)
        {
            var scalar = GetTypedEvent <Scalar>(@event);

            if (!this.isWhitespace)
            {
                this.Write(' ');
            }

            var value = NonInterpolatedTokenRegex.Replace(scalar.Value, match => "$" + match.Groups["token"].Value);

            if (value.Any(char.IsControl))
            {
                // The Unicode standard classifies the characters \u000A (LF), \u000C (FF), and \u000D (CR) as control characters
                // Emit as here doc
                this.Write("<<-EOT");
                foreach (var line in value.Split('\r', '\n'))
                {
                    this.WriteIndent();
                    this.Write(line);
                }

                this.WriteIndent();
                this.Write("EOT");
            }
            else
            {
                if (scalar.IsQuoted)
                {
                    this.Write('"');
                }

                this.Write(value);

                if (scalar.IsQuoted)
                {
                    this.Write('"');
                }
            }

            if (this.state == EmitterState.Sequence)
            {
                this.Write(',');
            }

            this.isWhitespace = false;
        }
            /// <summary>
            /// Emits the specified event.
            /// </summary>
            /// <param name="event">The event.</param>
            public void Emit(HclEvent @event)
            {
                switch (@event)
                {
                case JsonStart _:

                    this.IsJson = true;
                    break;

                case JsonEnd _:

                    this.IsJson = false;
                    break;
                }

                this.Emitter.Emit(@event);
            }
예제 #12
0
        /// <summary>
        /// Emits a mapping end.
        /// </summary>
        /// <param name="event">The event.</param>
        private void EmitMappingEnd(HclEvent @event)
        {
            GetTypedEvent <MappingEnd>(@event);

            if (this.state != EmitterState.Resource)
            {
                this.state = this.PopState();
            }

            this.indent = this.indents.Pop();

            this.WriteIndent();
            this.WriteIndicator("}", false, false, true);

            var mappingStart = this.events.Peek() as MappingStart;

            // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
            switch (this.state)
            {
            case EmitterState.BlockList when mappingStart != null:

                // Next element in a block list
                this.WriteIndent();
                this.indent = this.indents.Pop();
                this.EmitMappingKey(this.currentBlockKey);
                this.IncreaseIndent();

                return;

            case EmitterState.Sequence when mappingStart != null:

                this.Write(',');
                this.WriteIndent();
                break;
            }
        }
예제 #13
0
        /// <summary>
        /// Determines when the end of a nested block is found in the event queue (nesting level returns to zero)
        /// </summary>
        /// <param name="event">The event.</param>
        /// <returns><c>true</c> when end of nesting located.</returns>
        public bool Done(HclEvent @event)
        {
            this.level += @event.NestingIncrease;

            return(this.level == 0);
        }
예제 #14
0
 /// <summary>
 /// Adds an object to the end of the queue.
 /// </summary>
 /// <param name="event">The event.</param>
 public void Enqueue(HclEvent @event)
 {
     this.queue.AddLast(@event);
 }
예제 #15
0
 /// <summary>
 /// Finds the specified event.
 /// </summary>
 /// <param name="event">The event.</param>
 /// <returns>The event; else <c>null</c> if not found.</returns>
 public LinkedListNode <HclEvent> Find(HclEvent @event)
 {
     return(this.queue.Find(@event));
 }
예제 #16
0
        /// <summary>
        /// Emits the next node.
        /// </summary>
        /// <param name="event">The event to write.</param>
        private void EmitNode(HclEvent @event)
        {
            // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
            switch (@event.Type)
            {
            case EventType.ResourceStart:

                this.EmitResourceStart(@event);
                break;

            case EventType.MappingKey:

                this.EmitMappingKey(@event);
                break;

            case EventType.ScalarValue:

                this.EmitScalarValue(@event);
                break;

            case EventType.SequenceStart:

                this.EmitSequenceStart(@event);
                break;

            case EventType.SequenceEnd:

                this.EmitSequenceEnd(@event);
                break;

            case EventType.MappingStart:

                this.EmitMappingStart(@event);
                break;

            case EventType.MappingEnd:

                this.EmitMappingEnd(@event);
                break;

            case EventType.JsonStart:

                this.EmitJsonStart(@event);
                break;

            case EventType.JsonEnd:

                this.EmitJsonEnd(@event);
                break;

            case EventType.ResourceEnd:

                this.indents.Clear();
                this.lifecycleKeys.Clear();
                this.blockKeys.Clear();
                this.column         = 0;
                this.indent         = 0;
                this.resourceTraits = AwsSchema.TraitsAll;
                this.WriteBreak();
                this.WriteBreak();
                break;
            }
        }
예제 #17
0
        /// <summary>
        /// Emits a mapping end.
        /// </summary>
        /// <param name="event">The event.</param>
        private void EmitMappingEnd(HclEvent @event)
        {
            GetTypedEvent <MappingEnd>(@event);

            if (this.state != EmitterState.Resource)
            {
                this.state = this.PopState();
            }

            if (this.state == EmitterState.Resource && this.lifecycleKeys.Any())
            {
                /*
                 *  Needs to go ahead of ResourceEnd which should be next
                 *
                 *  BlockKey  (lifecycle)
                 *  SequenceStart
                 *  MappingStart
                 *  MappingKey (ignore_changes )
                 *  SequenceStart
                 *  Scalar (unquoted)
                 *  ...
                 *  SequenceEnd
                 *  MappingEnd
                 *  SequenceEnd
                 *  MappingEnd (end of resource)
                 *
                 */
                var resourceEnd = this.events.Dequeue();

                this.events.Enqueue(
                    new MappingKey(
                        "lifecycle",
                        new AttributePath("lifecycle"),
                        new ValueSchema {
                    Optional = true, ConfigMode = SchemaConfigMode.SchemaConfigModeBlock, Type = SchemaValueType.TypeList
                }));
                this.events.Enqueue(new SequenceStart());
                this.events.Enqueue(new MappingStart());
                this.events.Enqueue(
                    new MappingKey(
                        "ignore_changes",
                        new AttributePath("lifecycle.0.ignore_changes"),
                        new ValueSchema {
                    Optional = true, ConfigMode = SchemaConfigMode.SchemaConfigModeAuto
                }));
                this.events.Enqueue(new SequenceStart());

                foreach (var key in this.lifecycleKeys)
                {
                    this.events.Enqueue(new ScalarValue(key, false));
                }

                this.events.Enqueue(new SequenceEnd());
                this.events.Enqueue(new MappingEnd());
                this.events.Enqueue(new SequenceEnd());
                this.events.Enqueue(new MappingEnd());
                this.events.Enqueue(resourceEnd);
                this.lifecycleKeys.Clear();
                return;
            }

            this.indent = this.indents.Pop();

            this.WriteIndent();
            this.WriteIndicator("}", false, false, true);

            var mappingStart = this.events.Peek() as MappingStart;

            // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
            switch (this.state)
            {
            case EmitterState.BlockList when mappingStart != null:

                // Next element in a block list
                this.WriteIndent();
                this.indent = this.indents.Pop();
                this.EmitMappingKey(this.currentBlockKey);
                this.IncreaseIndent();

                return;

            case EmitterState.Sequence when mappingStart != null:

                this.Write(',');
                this.WriteIndent();
                break;
            }
        }