/// <summary> /// Resolves the model field interfaces of a data model configurationfrom a ParsedPartial. /// </summary> /// <param name="parsedFragment">The partially parsed extension.</param> /// <returns>The field interfaces of the data model configuration.</returns> public static Typo3ExtensionGenerator.Model.Configuration.Interface.Interface Resolve( Fragment parsedFragment ) { Typo3ExtensionGenerator.Model.Configuration.Interface.Interface @interface = new Typo3ExtensionGenerator.Model.Configuration.Interface.Interface { Target = parsedFragment.Parameters, SourceFragment = parsedFragment }; if( parsedFragment.Fragments.Any() ) { foreach( Fragment setting in parsedFragment.Fragments ) { @interface.Settings.Add( new KeyValuePair<string, string>( setting.Keyword, setting.Parameters ) ); } } // Parse any settings we know for( int settingIndex = 0; settingIndex < @interface.Settings.Count; settingIndex++ ) { KeyValuePair<string, string> setting = @interface.Settings[ settingIndex ]; if( setting.Key == Keywords.ConfigurationDirectives.InterfaceDirectives.Exclude ) { @interface.Exclude = ParseHelper.ParseBool( setting.Value ); } else if( setting.Key == Keywords.Title ) { @interface.Title = setting.Value; } else if( setting.Key == Keywords.ConfigurationDirectives.InterfaceDirectives.Representation ) { @interface.DisplayTypeTarget = setting.Value; DisplayTypeResolver.Resolve( parsedFragment, @interface, setting.Value ); } else if( setting.Key == Keywords.ConfigurationDirectives.InterfaceDirectives.DefaultValue ) { @interface.DefaultValue = setting.Value; } } return @interface; }
/// <summary> /// Resolves the models of an extension from a ParsedPartial. /// </summary> /// <param name="parsedFragment">The partially parsed extension.</param> /// <returns>The models of the extension</returns> public static List<Repository> Resolve( Fragment parsedFragment ) { IEnumerable<Fragment> repositoryPartials = parsedFragment.Fragments.Where( p => p.Keyword == Keywords.ExtensionDirectives.DeclareRepository ); if( !repositoryPartials.Any() ) return null; List<Repository> repositories = new List<Repository>(); foreach( Fragment repositoryPartial in repositoryPartials ) { Repository repository = new Repository { TargetModelName = repositoryPartial.Parameters, SourceFragment = repositoryPartial, }; repositories.Add( repository ); if( repositoryPartial.Fragments.Any() ) { foreach( Fragment dataMember in repositoryPartial.Fragments ) { if( dataMember.Keyword == Keywords.PluginDirectives.Action ) { Action action = ActionResolver.ResolveAction( dataMember ); repository.Methods.Add( action ); } else if( dataMember.Keyword == Keywords.Implementation) { repository.Implementation = dataMember.Parameters; } else if( dataMember.Keyword == Keywords.InternalType ) { repository.InternalType = dataMember.Parameters; } } } } return repositories; }
/// <summary> /// Resolves a palette definition of data model configuration of an extension from a ParsedPartial. /// </summary> /// <param name="parsedFragment">The partially parsed extension.</param> /// <returns>The palette definition.</returns> /// <exception cref="ParserException">Palette does not define an interface.</exception> public static Palette Resolve( Fragment parsedFragment ) { // Check if the palette defines an interface Fragment interfacePartial = parsedFragment.Fragments.SingleOrDefault( p => p.Keyword == Keywords.DefineInterface ); if( null == interfacePartial ) { throw new ParserException( string.Format( "Palette '{0}' does not define an interface.", parsedFragment.Parameters ), parsedFragment.SourceDocument ); } Palette parsedPalette = new Palette { Name = parsedFragment.Parameters, Interface = interfacePartial.Parameters, Visibility = Palette.PaletteVisibility.Default, SourceFragment = interfacePartial }; if( parsedFragment.Fragments.Any() ) { foreach( Fragment configurationDirective in parsedFragment.Fragments ) { // Find configuration directives if( Keywords.ConfigurationDirectives.Visibility.Hidden == configurationDirective.Keyword ) { parsedPalette.Visibility = Palette.PaletteVisibility.ShowNever; } else if( Keywords.ConfigurationDirectives.Visibility.Show == configurationDirective.Keyword ) { if( Keywords.ConfigurationDirectives.Visibility.Always == configurationDirective.Parameters ) { parsedPalette.Visibility = Palette.PaletteVisibility.ShowAlways; } } } } return parsedPalette; }
/// <summary> /// Resolves the models of an extension from a ParsedPartial. /// </summary> /// <param name="parsedFragment">The partially parsed extension.</param> /// <returns>The models of the extension</returns> public static List<DataModel> Resolve( Fragment parsedFragment ) { IEnumerable<Fragment> modelPartials = parsedFragment.Fragments.Where( p => p.Keyword == Keywords.ExtensionDirectives.DeclareModel ); if( !modelPartials.Any() ) return null; List<DataModel> dataModels = new List<DataModel>(); foreach( Fragment modelPartial in modelPartials ) { DataModel dataModel = new DataModel {Name = modelPartial.Parameters, SourceFragment = modelPartial}; dataModels.Add( dataModel ); if( modelPartial.Fragments.Any() ) { foreach( Fragment dataMember in modelPartial.Fragments ) { if( dataMember.Keyword == Keywords.InternalType ) { dataModel.InternalType = dataMember.Parameters; } else { dataModel.Members.Add( new DataModel.DataModelMember {Name = dataMember.Keyword, Value = dataMember.Parameters} ); } } } } // Resolve any foreign key references ForeignKeyResolver.Resolve( dataModels ); return dataModels; }
/// <summary> /// Resolves the plugins of an extension from a fragment. /// </summary> /// <param name="parsedFragment">The partially parsed extension.</param> /// <returns>The plugins of the extension</returns> /// <exception cref="GeneratorException">A plugin must contain exactly one model.</exception> public static List<Typo3ExtensionGenerator.Model.Plugin.Plugin> Resolve( Fragment parsedFragment ) { IEnumerable<Fragment> pluginPartials = parsedFragment.Fragments.Where( p => p.Keyword == Keywords.ExtensionDirectives.DeclarePlugin ); if( !pluginPartials.Any() ) return null; List<Typo3ExtensionGenerator.Model.Plugin.Plugin> plugins = new List<Typo3ExtensionGenerator.Model.Plugin.Plugin>(); foreach( Fragment pluginPartial in pluginPartials ) { // Construct the plugin with the given name Typo3ExtensionGenerator.Model.Plugin.Plugin plugin = new Typo3ExtensionGenerator.Model.Plugin.Plugin {Name = pluginPartial.Parameters,SourceFragment = pluginPartial }; // Find the data models that are defined for this plugin List<DataModel> dataModels = ModelResolver.Resolve( pluginPartial ); if( null == dataModels || dataModels.Count > 1 ) { throw new GeneratorException( "A plugin must contain exactly one model.", pluginPartial.SourceDocument ); } plugin.Model = dataModels[ 0 ]; plugin.Model.Name = "flexform"; // Resolve plugin foreach( Fragment pluginParameter in pluginPartial.Fragments ) { if( pluginParameter.Keyword == Keywords.Title) { plugin.Title = pluginParameter.Parameters; } else if( pluginParameter.Keyword == Keywords.DefineInterface ) { Typo3ExtensionGenerator.Model.Configuration.Interface.Interface @interface = InterfaceResolver.Resolve( pluginParameter ); @interface.ParentModelTarget = "flexform"; @interface.ParentModel = plugin.Model; plugin.Interfaces.Add( @interface ); } else if( pluginParameter.Keyword == Keywords.PluginDirectives.Action ) { Action action = ActionResolver.ResolveAction( pluginParameter ); plugin.Actions.Add( action ); } else if( pluginParameter.Keyword == Keywords.PluginDirectives.Listener ) { Listener listener = ListenerResolver.ResolveListener( pluginParameter ); plugin.Actions.Add( listener.TargetAction ); plugin.Listeners.Add( listener ); } else if( pluginParameter.Keyword == Keywords.Implementation ) { plugin.Implementation = pluginParameter.Parameters; } } // If no name was defined, use the common placeholder names if( string.IsNullOrEmpty( plugin.Name ) ) { plugin.Name = string.Format( "Pi{0}", ( plugins.Count + 1 ) ); } plugins.Add( plugin ); } return plugins; }
/// <summary> /// Resolves the configurations of data models of an extension from a ParsedPartial. /// </summary> /// <param name="parsedFragment">The partially parsed extension.</param> /// <returns>The configurations of the extension</returns> public static List<Typo3ExtensionGenerator.Model.Configuration.Configuration> Resolve( Fragment parsedFragment ) { IEnumerable<Fragment> configurationPartials = parsedFragment.Fragments.Where( p => p.Keyword == Keywords.ExtensionDirectives.DeclareConfiguration ); if( !configurationPartials.Any() ) return null; List<Typo3ExtensionGenerator.Model.Configuration.Configuration> configurations = new List<Typo3ExtensionGenerator.Model.Configuration.Configuration>(); foreach( Fragment configurationPartial in configurationPartials ) { Typo3ExtensionGenerator.Model.Configuration.Configuration configuration = new Typo3ExtensionGenerator.Model.Configuration.Configuration { Target = configurationPartial.Parameters }; configurations.Add( configuration ); if( configurationPartial.Fragments.Any() ) { foreach( Fragment configurationDirective in configurationPartial.Fragments ) { // Find configuration directives if( Keywords.ConfigurationDirectives.Label == configurationDirective.Keyword ) { configuration.Label = configurationDirective.Parameters; } else if( Keywords.ConfigurationDirectives.LabelAlternative == configurationDirective.Keyword ) { configuration.LabelAlternative = configurationDirective.Parameters; } else if( Keywords.ConfigurationDirectives.LabelHook == configurationDirective.Keyword ) { configuration.LabelHook = true; } else if( Keywords.ConfigurationDirectives.SearchFields == configurationDirective.Keyword ) { configuration.SearchFields = configurationDirective.Parameters; } else if( Keywords.ConfigurationDirectives.Thumbnail == configurationDirective.Keyword ) { configuration.Thumbnail = configurationDirective.Parameters; } else if( Keywords.ConfigurationDirectives.InterfaceInfo == configurationDirective.Keyword ) { configuration.InterfaceInfo = configurationDirective.Parameters; } else if( Keywords.ConfigurationDirectives.TypeDeclaration == configurationDirective.Keyword ) { configuration.Types.Add( TypeResolver.Resolve( configurationDirective ) ); } else if( Keywords.ConfigurationDirectives.PaletteDeclaration == configurationDirective.Keyword ) { configuration.Palettes.Add( PaletteResolver.Resolve( configurationDirective ) ); } else if( Keywords.DefineInterface == configurationDirective.Keyword ) { Typo3ExtensionGenerator.Model.Configuration.Interface.Interface @interface = InterfaceResolver.Resolve( configurationDirective ); @interface.ParentModelTarget = configuration.Target; configuration.Interfaces.Add( @interface ); } else if( Keywords.Title == configurationDirective.Keyword ) { configuration.Title = configurationDirective.Parameters; } else if( Keywords.ConfigurationDirectives.Visibility.Hidden == configurationDirective.Keyword ) { configuration.Hidden = true; } } } } return configurations; }
/// <summary> /// Parses a ParsedPartial that should contain an extension definition. /// </summary> /// <param name="fragment"></param> /// <returns></returns> /// <exception cref="ParserException">Missing extension declaration.</exception> private static Extension Parse( Fragment fragment ) { // The fragment MUST be an extension definition if( fragment.Header.Length < Keywords.DeclareExtension.Length || Keywords.DeclareExtension != fragment.Header.Substring( 0, Keywords.DeclareExtension.Length ) ) { throw new ParserException( "Missing extension declaration.", fragment.SourceDocument ); } Extension result = ExtensionResolver.Resolve( fragment ); result.SourceFragment = fragment; return result; }
/// <summary> /// Resolves an extension model from a parsed fragment. /// </summary> /// <param name="parsedFragment"></param> /// <returns></returns> public static Typo3ExtensionGenerator.Model.Extension Resolve( Fragment parsedFragment ) { string extensionKey = parsedFragment.Header.Substring( Keywords.DeclareExtension.Length, parsedFragment.Header.Length - Keywords.DeclareExtension.Length ).Trim(); Typo3ExtensionGenerator.Model.Extension extension = new Typo3ExtensionGenerator.Model.Extension { Key = extensionKey, Author = Person.Someone, State = "alpha", Version = "0.0.1" }; foreach( Fragment extensionFragment in parsedFragment.Fragments ) { if( extensionFragment.Keyword == Keywords.ExtensionDirectives.DefineAuthor ) { extension.Author.Name = extensionFragment.Parameters; } else if( extensionFragment.Keyword == Keywords.ExtensionDirectives.DefineAuthorCompany ) { extension.Author.Company = extensionFragment.Parameters; } else if( extensionFragment.Keyword == Keywords.ExtensionDirectives.DefineAuthorEmail ) { extension.Author.Email = extensionFragment.Parameters; } else if( extensionFragment.Keyword == Keywords.Category ) { extension.Category = extensionFragment.Parameters; } else if( extensionFragment.Keyword == Keywords.Description ) { extension.Description = extensionFragment.Parameters; } else if( extensionFragment.Keyword == Keywords.Title ) { extension.Title = extensionFragment.Parameters; } else if( extensionFragment.Keyword == Keywords.ExtensionDirectives.State ) { extension.State = extensionFragment.Parameters; } else if( extensionFragment.Keyword == Keywords.ExtensionDirectives.Version ) { extension.Version = extensionFragment.Parameters; } else if( extensionFragment.Keyword == Keywords.ConfigurationDirectives.LabelHook ) { extension.LabelHookImplementation = extensionFragment.Parameters; } } extension.Configurations = ConfigurationResolver.Resolve( parsedFragment ); extension.Models = ModelResolver.Resolve( parsedFragment ); extension.Modules = ModuleResolver.Resolve( parsedFragment ); extension.Plugins = PluginResolver.Resolve( parsedFragment ); extension.Repositories = RepositoryResolver.Resolve( parsedFragment ); extension.Requirements = RequirementResolver.Resolve( parsedFragment ); extension.Services = ServiceResolver.Resolve( parsedFragment ); extension.Tasks = TaskResolver.Resolve( parsedFragment ); return extension; }
/// <summary> /// Resolves a type definition of data model configuration of an extension from a ParsedPartial. /// </summary> /// <param name="parsedFragment">The partially parsed extension.</param> /// <returns>The defined type.</returns> /// <exception cref="ParserException">Type does not define an interface.</exception> public static Typo3ExtensionGenerator.Model.Configuration.Type Resolve( Fragment parsedFragment ) { // Check if the type defines an interface Fragment interfacePartial = parsedFragment.Fragments.SingleOrDefault( p => p.Keyword == Keywords.ConfigurationDirectives.InterfaceType ); if( null == interfacePartial ) { string typeName = parsedFragment.Parameters; if( string.IsNullOrEmpty( typeName ) ) { typeName = "<unnamed>"; } throw new ParserException( string.Format( "Type '{0}' does not define an interface.", typeName ), parsedFragment.SourceDocument ); } Typo3ExtensionGenerator.Model.Configuration.Type parsedType = new Typo3ExtensionGenerator.Model.Configuration.Type {Interface = interfacePartial.Parameters, SourceFragment = interfacePartial}; return parsedType; }
public static Action ResolveAction( Fragment parsedFragment ) { Action resultingAction = new Action {Name = parsedFragment.Parameters}; foreach( Fragment actionDirective in parsedFragment.Fragments ) { if( actionDirective.Keyword == Keywords.Title ) { resultingAction.Title = actionDirective.Parameters; } else if( actionDirective.Keyword == Keywords.Requirement ) { resultingAction.Requirements.AddRange( actionDirective.Parameters.Split( new[] {','} ) ); } else if( actionDirective.Keyword == Keywords.PluginDirectives.ActionDirectives.Uncachable ) { resultingAction.Uncachable = true; } } return resultingAction; }
/// <summary> /// Resolves all tasks defined in a given parsed fragment. /// </summary> /// <param name="parsedFragment"></param> /// <returns></returns> /// <exception cref="ParserException">Task has no name!</exception> public static List<Task> Resolve( Fragment parsedFragment ) { IEnumerable<Fragment> taskFragments = parsedFragment.Fragments.Where( p => p.Keyword == Keywords.ExtensionDirectives.DeclareTask ); if( !taskFragments.Any() ) return null; List<Task> tasks = new List<Task>(); foreach( Fragment taskFragment in taskFragments ) { // Construct the plugin with the given name Task task = new Task {Name = taskFragment.Parameters, SourceFragment = taskFragment}; // Resolve task foreach( Fragment taskParameter in taskFragment.Fragments ) { if( taskParameter.Keyword == Keywords.Description ) { task.Description = taskParameter.Parameters; } else if( taskParameter.Keyword == Keywords.Title ) { task.Title = taskParameter.Parameters; } else if( taskParameter.Keyword == Keywords.Implementation ) { task.Implementation = taskParameter.Parameters; } else if( taskParameter.Keyword == Keywords.ServiceDirectives.AdditionalFields ) { task.AdditionalFieldsClass = taskParameter.Parameters; task.TaskFields = new TaskFields { Implementation = taskParameter.Parameters }; } } // If no name was defined, throw if( string.IsNullOrEmpty( task.Name ) ) { throw new ParserException( "Service has no name!", parsedFragment.SourceDocument ); } if( null != task.TaskFields ) { task.TaskFields.Name = task.Name; } tasks.Add( task ); } return tasks; }
/// <summary> /// Find an ExtBase SignalSlot listener in a parsed fragment and return it. /// </summary> /// <param name="parsedFragment"></param> /// <returns></returns> /// <exception cref="ParserException">Listener does not define a signal host or slot.</exception> public static Listener ResolveListener( Fragment parsedFragment ) { Listener resultingListener = new Listener(); resultingListener.TargetAction = ActionResolver.ResolveAction( parsedFragment ); foreach( Fragment actionDirective in parsedFragment.Fragments ) { if( actionDirective.Keyword == Keywords.PluginDirectives.ActionDirectives.Host ) { resultingListener.Host = actionDirective.Parameters; } else if( actionDirective.Keyword == Keywords.PluginDirectives.ActionDirectives.Slot ) { resultingListener.Signal = actionDirective.Parameters; } } if( string.IsNullOrEmpty( resultingListener.Host ) ) { throw new ParserException( string.Format( "Listener '{0}' does not define a signal host.", parsedFragment.Parameters ), parsedFragment.SourceDocument ); } if( string.IsNullOrEmpty( resultingListener.Signal ) ) { throw new ParserException( string.Format( "Listener '{0}' does not define a signal slot.", parsedFragment.Parameters ), parsedFragment.SourceDocument ); } return resultingListener; }
/// <summary> /// Resolves all services defined in a given parsed fragment. /// </summary> /// <param name="parsedFragment"></param> /// <returns></returns> /// <exception cref="NotImplementedException">Defining ExtBase SignalSlot listeners in service classes is unsupported at this time.</exception> /// <exception cref="ParserException">Service has no name!</exception> public static List<Service> Resolve( Fragment parsedFragment ) { IEnumerable<Fragment> serviceFragments = parsedFragment.Fragments.Where( p => p.Keyword == Keywords.ExtensionDirectives.DeclareService ); if( !serviceFragments.Any() ) return null; List<Service> services = new List<Service>(); foreach( Fragment serviceFragment in serviceFragments ) { // Construct the plugin with the given name Service service = new Service {Name = serviceFragment.Parameters, SourceFragment = serviceFragment}; // Resolve service foreach( Fragment serviceParameter in serviceFragment.Fragments ) { if( serviceParameter.Keyword == Keywords.PluginDirectives.Action ) { Typo3ExtensionGenerator.Model.Action action = ActionResolver.ResolveAction( serviceParameter ); service.Actions.Add( action ); } else if( serviceParameter.Keyword == Keywords.PluginDirectives.Listener ) { Listener listener = ListenerResolver.ResolveListener( serviceParameter ); service.Actions.Add( listener.TargetAction ); throw new NotImplementedException( "Defining ExtBase SignalSlot listeners in service classes is unsupported at this time." ); //service.Listeners.Add( listener ); } else if( serviceParameter.Keyword == Keywords.Implementation ) { service.Implementation = serviceParameter.Parameters; } } // If no name was defined, throw if( string.IsNullOrEmpty( service.Name ) ) { throw new ParserException( "Service has no name!", parsedFragment.SourceDocument ); } services.Add( service ); } return services; }
/// <summary> /// Resolves the modules of an extension from a ParsedPartial. /// </summary> /// <param name="parsedFragment">The partially parsed extension.</param> /// <returns>The plauings of the extension</returns> public static List<Typo3ExtensionGenerator.Model.Module> Resolve( Fragment parsedFragment ) { IEnumerable<Fragment> modulePartials = parsedFragment.Fragments.Where( p => p.Keyword == Keywords.ExtensionDirectives.DeclareModule ); if( !modulePartials.Any() ) return null; List<Typo3ExtensionGenerator.Model.Module> modules = new List<Typo3ExtensionGenerator.Model.Module>(); foreach( Fragment modulePartial in modulePartials ) { Typo3ExtensionGenerator.Model.Module module = new Typo3ExtensionGenerator.Model.Module {Name = modulePartial.Parameters, SourceFragment = parsedFragment}; foreach( Fragment subPartial in modulePartial.Fragments ) { if( subPartial.Keyword == Keywords.Category ) { module.MainModuleName = subPartial.Parameters; } else if( subPartial.Keyword == Keywords.Title ) { module.Title = subPartial.Parameters; } else if( subPartial.Keyword == Keywords.Implementation ) { module.Implementation = subPartial.Parameters; } else if( subPartial.Keyword == Keywords.PluginDirectives.Action ) { Action action = ActionResolver.ResolveAction( subPartial ); module.Actions.Add( action ); } } // If no name was defined, use the common placeholder names if( string.IsNullOrEmpty( module.Name ) ) { module.Name = string.Format( "M{0}", ( modules.Count + 1 ) ); } modules.Add( module ); } return modules; }
/// <summary> /// Parses a virtual document into a parsed fragment. /// </summary> /// <param name="document">The virtual document that should be parsed.</param> /// <returns></returns> public static Fragment ParseFragment( VirtualDocument document ) { DocumentWalker walker = new DocumentWalker( document ); // The currently collected scope body string body = String.Empty; // Sub-scopes which we'll find during parsing will be stored in this partial. Fragment result = new Fragment { Body = string.Empty, Header = string.Empty, SourceDocument = document }; // How deeply nested we are into scopes. int scopeLevel = 0; // Where the scope we're currently recording started. VirtualDocument.Character scopeStart = walker.CurrentCharacter; // Are we currently inside a string? bool inString = false; // Is the current character escaped? bool isEscaped = false; // Are we currently inside a comment? bool inComment = false; // The line where a comment was started int commentStart = 0; // Iterate over the whole input string // The whole point of this operation is to collect the full header of the partial, // as well as the full body of the partial. // If, while parsing the body of the partial, we find nested scopes, we'll store those to parse them later. while( walker.CanWalk ) { if( !inString ) { // Check for scope terminator if( walker.CurrentlyReads( Syntax.ScopeTerminate ) ) { // Did we find a scope terminator? Like: ; if( 1 == scopeLevel ) { // As long as we're on the first scope level, we can collect the body of scopes to parse them later. // If we're deeper nested, there's no point, we'll parse those when we recurse. // Construct a new document for the currently recorded scope. VirtualDocument documentFragment = VirtualDocument.FromDocument( document, scopeStart, walker.CurrentCharacter ); // ...and store it. result.Fragments.Add( new Fragment {Body = body.Trim(), SourceDocument = documentFragment} ); result.Body += walker.CurrentCharacter; // Clear buffer body = string.Empty; // We skip ahead until we see a character again. We need those as markers. try { walker.WalkToNext(); } catch( ArgumentOutOfRangeException ) { // Things can always go wrong when running! break; } // Set the current location as the new recording start point scopeStart = walker.CurrentCharacter; continue; } if( 0 == scopeLevel ) { // If we're on the root level, just increase the scope pointer and skip. walker.Walk(); continue; } } // Check for scopes if( walker.CurrentlyReads( Syntax.ScopeStart ) ) { // Did we find the start of a new scope? ++scopeLevel; if( 1 == scopeLevel ) { // If we're on the root level (we are, because we just increased the scopeLevel), we need to skip ahead. walker.Walk(); scopeStart = walker.CurrentCharacter; continue; } if( 2 == scopeLevel ) { //scopeStart = walker.CurrentCharacter; } } else if( walker.CurrentlyReads( Syntax.ScopeEnd ) ) { --scopeLevel; // Did we find the end of a scope? if( 1 == scopeLevel ) { // Great! Another temporary scope we can store for later body += walker.CurrentCharacter; result.Fragments.Add( new Fragment { Body = body.Trim(), SourceDocument = VirtualDocument.FromDocument( document, scopeStart, walker.CurrentCharacter ) } ); result.Body += walker.CurrentCharacter; // Clear buffer body = string.Empty; // We skip ahead until we see a character again. We need those as markers. try { walker.WalkToNext(); } catch( ArgumentOutOfRangeException ) { // Things can always go wrong when running! break; } // Set the current location as the new recording start point scopeStart = walker.CurrentCharacter; continue; } if( 0 == scopeLevel ) { // If we're on the root level, just increase the scope pointer and skip. try { walker.Walk(); } catch( ArgumentOutOfRangeException ){} continue; } } // Check for string delimiter if( walker.CurrentlyReads( Syntax.StringDelimiter ) ) { // Did we hit a string delimiter? Like: " inString = true; } // Check for comment try { //if( characterPointer + Syntax.CommentMultilineStart.Length <= element.Length && Syntax.CommentMultilineStart == element.Substring( characterPointer, Syntax.CommentMultilineStart.Length ) ) { if( walker.CurrentlyReads( Syntax.CommentMultilineStart ) ) { inComment = true; commentStart = walker.CurrentLine.PhysicalLineIndex; // Skip ahead until comment is terminated while( walker.CanWalk && inComment ) { walker.Walk(); if( walker.CurrentlyReads( Syntax.CommentMultilineEnd ) ) { walker.Walk( Syntax.CommentMultilineEnd.Length ); inComment = false; commentStart = 0; } } } else if( walker.CurrentlyReads( Syntax.CommentSinglelineStart ) ) { // Skip ahead until comment is terminated // Single line comments are terminated by newline. while( walker.CanWalkForward ) { walker.Walk(); } // We walked to the end of the line, no we skip to the next one walker.Walk(); commentStart = 0; } } catch( ArgumentOutOfRangeException ex ) { throw new ParserException( string.Format( "Hit end of input while looking for end of comment which started on line {0}.", commentStart ), walker.Document ); } } else { // This is when we're parsing within a string. if( walker.CurrentlyReads( Syntax.StringEscape ) ) { // Did we find an escape sequence? Like: \" isEscaped = true; walker.Walk(); } if( !isEscaped && walker.CurrentlyReads( Syntax.StringDelimiter ) ) { // Did the string end? inString = false; } } // Decide if we're currently parsing a header or a body and store accordingly. if( 0 == scopeLevel && walker.CanWalk ) { // Store in persitent result result.Header += walker.CurrentCharacter; } else { // Store in persistent result result.Body += walker.CurrentCharacter; // Also store in temporary buffer body += walker.CurrentCharacter; } isEscaped = false; Debug.Assert( walker.CanWalk, "Tried to walk when it's not possible" ); walker.Walk(); } result.Header = result.Header.Trim(); result.Body = result.Body.Trim(); if( inString ) { throw new ParserException( string.Format( "Unmatched \" in {0}", result.Body ), walker.Document ); } // Recurse to resolve all previously parsed fragments foreach( Fragment childFragment in result.Fragments ) { Fragment fragment = ParseFragment( childFragment.SourceDocument ); childFragment.Header = fragment.Header; childFragment.Body = fragment.Body; childFragment.Fragments = fragment.Fragments; // Pull keyword from header int delimiterPosition = childFragment.Header.IndexOf( ' ' ); if( 0 > delimiterPosition ) delimiterPosition = childFragment.Header.Length; childFragment.Keyword = childFragment.Header.Substring( 0, delimiterPosition ).Trim(); // The remaining part of the header would now be the parameters childFragment.Parameters = childFragment.Header.Substring( childFragment.Keyword.Length ).Trim(); // Is the parameter set in ""? if( !string.IsNullOrEmpty( childFragment.Parameters ) && "\"" == childFragment.Parameters.Substring( 0, 1 ) ) { if( "\"" != childFragment.Parameters.Substring( childFragment.Parameters.Length -1, 1 ) ) { throw new ParserException( string.Format( "Unmatched \" in {0}", childFragment.Header ), walker.Document ); } childFragment.Parameters = childFragment.Parameters.Substring( 1, childFragment.Parameters.Length - 2 ); } } return result; }
/// <summary> /// Resolves the models of an extension from a ParsedPartial. /// </summary> /// <param name="parsedFragment">The partially parsed extension.</param> /// <returns>The models of the extension</returns> /// <exception cref="GeneratorException">The given requirement root does not exist.</exception> public static List<Requirement> Resolve( Fragment parsedFragment ) { IEnumerable<Fragment> requirementFragments = parsedFragment.Fragments.Where( p => p.Keyword == Keywords.Requirement ); if( !requirementFragments.Any() ) return null; List<Requirement> requirements = new List<Requirement>(); foreach( Fragment requirementFragment in requirementFragments ) { Requirement requirement = new Requirement { SourceFolder = requirementFragment.Parameters, SourceFragment = requirementFragment }; requirements.Add( requirement ); if( requirementFragment.Fragments.Any() ) { foreach( Fragment fileFilter in requirementFragment.Fragments ) { requirement.SourceFilter.Add( ParseHelper.UnwrapString( fileFilter.Keyword ) ); } } } foreach( Requirement requirement in requirements ) { // If the requirement root does not exist, throw if( !Directory.Exists( requirement.SourceFolder ) ) { throw new GeneratorException( string.Format( "The given requirement root '{0}' does not exist.", requirement.SourceFolder ), requirement.SourceFragment.SourceDocument ); } // Find files in the requirement root DirectoryInfo sourceDirectory = new DirectoryInfo( requirement.SourceFolder ); string currentPath = string.Empty; // Iterate over all defined filters in the requirement foreach( string sourceFilter in requirement.SourceFilter ) { DirectoryInfo searchRoot = sourceDirectory; currentPath = string.Empty; // Extract folder from filter and adjust filter expression. string filter = sourceFilter; if( sourceFilter.Contains( "/" ) ) { currentPath = sourceFilter.Substring( 0, sourceFilter.LastIndexOf( '/' ) + 1 ); string activePath = Path.Combine( requirement.SourceFolder, currentPath ); searchRoot = new DirectoryInfo( activePath ); filter = sourceFilter.Substring( sourceFilter.LastIndexOf( '/' ) + 1 ); } // Add all matched try { FileInfo[] files = searchRoot.GetFiles( filter ); // Convert filenames to RequiredFile instances requirement.Files.AddRange( files.Select( s => new Requirement.RequiredFile {FullSourceName = s.FullName, RelativeTargetName = currentPath + s.Name} ) ); } catch( DirectoryNotFoundException e ) { throw new ParserException( e.Message, parsedFragment.SourceDocument ); } } } return requirements; }
public static void Resolve( Fragment parsedFragment, Typo3ExtensionGenerator.Model.Configuration.Interface.Interface @interface, string displayType ) { if( Keywords.ConfigurationDirectives.InterfaceDirectives.Representations.FileReference == displayType ) { SpecializedDisplayType specializedDisplayType = new SpecializedDisplayType { Name = Keywords.ConfigurationDirectives.InterfaceDirectives.Representations.RecordGroup, SourceFragment = parsedFragment }; specializedDisplayType.Set( "internal_type", "file_reference" ); specializedDisplayType.Set( "allowed", "*" ); specializedDisplayType.Set( "disallowed", "php" ); specializedDisplayType.Set( "size", 5 ); specializedDisplayType.Set( "maxitems", 99 ); // If this field requires anything, it should have at least 1 item. if( @interface.Settings.Any( s => s.Key == Keywords.Requirement ) ) { specializedDisplayType.Set( "minitems", 1 ); } else { specializedDisplayType.Set( "minitems", 0 ); } @interface.DisplayType = specializedDisplayType; } else if( Keywords.ConfigurationDirectives.InterfaceDirectives.Representations.RecordGroup == displayType ) { RecordGroupDisplayType recordGroupDisplayType = new RecordGroupDisplayType { Name = Keywords.ConfigurationDirectives.InterfaceDirectives.Representations.RecordGroup, SourceFragment = parsedFragment }; // Show records next to select box recordGroupDisplayType.ShowThumbnails = true; // Increase list length recordGroupDisplayType.Lines = 10; // Increase list width recordGroupDisplayType.SelectedListStyle = "width:400px"; // Don't allow duplicates recordGroupDisplayType.AllowDuplicates = false; // Set item limit recordGroupDisplayType.MaxItems = 99; // If this field requires anything, it should have at least 1 item. if( @interface.Settings.Any( s => s.Key == Keywords.Requirement ) ) { recordGroupDisplayType.MinItems = 1; } else { recordGroupDisplayType.MinItems = 0; } // The model type for the suggest wizard is resolved during generation later. recordGroupDisplayType.Set( "wizards.RTE.type", "suggest" ); @interface.DisplayType = recordGroupDisplayType; } else if( Keywords.ConfigurationDirectives.InterfaceDirectives.Representations.RichTextArea == displayType ) { SpecializedDisplayType specializedDisplayType = new SpecializedDisplayType() { Name = Keywords.ConfigurationDirectives.InterfaceDirectives.Representations.TextArea, SourceFragment = parsedFragment }; specializedDisplayType.Set( "wizards.RTE.icon", "wizard_rte2.gif" ); specializedDisplayType.Set( "wizards.RTE.notNewRecords", 1 ); specializedDisplayType.Set( "wizards.RTE.RTEonly", 1 ); specializedDisplayType.Set( "wizards.RTE.script", "wizard_rte.php" ); specializedDisplayType.Set( "wizards.RTE.title", "LLL:EXT:cms/locallang_ttc.xml:bodytext.W.RTE" ); specializedDisplayType.Set( "wizards.RTE.type", "script" ); @interface.DisplayType = specializedDisplayType; // Add a new property to the interface itself, to enable rich text editing. @interface.Set( "defaultExtras", "richtext[]" ); } else { // Could not determine proper display type, use user supplied intput @interface.DisplayType = new DisplayType {Name = @interface.DisplayTypeTarget}; } }