/** * Generates the output document. * * @staticvar standardOutput $lastOutput The last output used. */ public function generate() { static $lastOutput = NULL; $prog = tfProgram::get(); $reparse = false; if ($lastOutput != $this->output) { $lastOutput = $this->output; $reparse = true; } $this->fs->safeMkDir('output/' . $this->output, TF_READ | TF_WRITE | TF_EXEC); $this->fs->cleanUpDirectory('output/' . $this->output); $this->copyMedia(); $this->outputObj = $out = $this->prog->fs->loadObject('outputs/' . $this->output . '.php', $this->output); if ($reparse) { $parsers = tfParsers::get(); $refs = array(); $refTitles = array(); foreach ($this->pages as &$page) { $refs[$page['Id']] = $this->outputObj->toAddress($page['Id']); $refTitles[$page['Id']] = ($this->config['showNumbers'] ? $page['FullNumber'] . '. ' : '') . (!isset($page['Tags']['ShortTitle']) ? $page['Tags']['Title'] : $page['Tags']['ShortTitle']); } $parsers->getParser()->predef_urls = $refs; $parsers->getParser()->predef_titles = $refTitles; } foreach ($this->pages as &$page) { if (!tfTags::validateTags($page['Tags'])) { throw new Exception('Tag validation error in "' . $page['Id'] . '": ' . PHP_EOL . tfTags::getError()); } } $out->init($this, 'output/' . $this->output . '/'); foreach ($this->pages as &$page) { if (!$this->parsed) { $page['Markdown'] = $page['Content']; } $parsers->getParser()->fn_id_prefix = str_replace('.', '_', $page['Id']) . ':'; $parsers->getParser()->page_id = $page['Id']; $page['Content'] = $parsers->parse($page['Markdown']); $out->generate($page); $prog->console->stderr->write('.'); } $prog->console->stderr->write(PHP_EOL); $this->parsed = true; $out->close(); }
/** * Generates a single page and saves it on the disk. * * @param Array $page The page meta-info. */ public function generate($page) { tfTags::setTagList($page['Tags']); $nav = array(); $this->_currentPage = $page; $nav[$page['Id']] = $page['Tags']['ShortTitle']; $parent = $page['_Parent']; do { $parent = $this->project->getMetaInfo($parent, false); if (!is_null($parent)) { $nav[$parent['Id']] = $parent['Tags']['ShortTitle']; $parent = $parent['_Parent']; } } while (!is_null($parent)); $nav = array_reverse($nav, true); $code = $this->createTopNavigator($page); $subtitle = ''; if (isset($page['Tags']['Appendix']) && $page['Tags']['Appendix']) { $subtitle = $this->translate->_('tags', 'appendix') . ' '; if (!$this->project->config['showNumbers']) { $subtitle = trim($subtitle) . ': '; } } if ($this->project->config['showNumbers']) { $code .= '<h1>' . $subtitle . $page['FullNumber'] . '. ' . $page['Tags']['Title'] . '</h1>'; } else { $code .= '<h1>' . $subtitle . $page['Tags']['Title'] . '</h1>'; } $this->_tagVersion = array(); $reference = tfTags::orderProcessTag('General', 'Author', $this) . tfTags::orderProcessTag('Status', 'Status', $this) . tfTags::orderProcessTags('Programming', $this) . tfTags::orderProcessTags('Behaviour', $this) . tfTags::orderProcessTags('VersionControl', $this); if (sizeof($this->_tagVersion) > 0) { $reference .= '<tr><th>' . $this->translate->_('tags', 'versions') . '</th><td>'; if (isset($this->_tagVersion['since'])) { $reference .= $this->translate->_('general', 'period_since') . ' <code>' . $this->_tagVersion['since'] . '</code>'; } if (isset($this->_tagVersion['to'])) { $reference .= ' ' . $this->translate->_('general', 'period_to') . ' <code>' . $this->_tagVersion['to'] . '</code>'; } $reference .= '</td></tr>' . PHP_EOL; } if ($reference != '') { $code .= '<div class="tf_reference"><table>' . $reference . '</table><hr/></div>'; } $code .= tfTags::orderProcessTag('General', 'FeatureInformationFrame', $this); $code .= $page['Content']; $code .= tfTags::orderProcessTag('Navigation', 'SeeAlso', $this); $this->pageContent[$page['Id']] = $code; }
/** * Builds an output document * @param tfProgram $prg */ public function build(tfProgram $prg) { if (!isset($this->args['#path'])) { return $this->main($prg); } $prg->loadLibrary('parsers'); $prg->loadLibrary('output'); $prg->loadLibrary('project'); $prg->loadLibrary('i18n'); $prg->loadLibrary('tags'); $project = new tfProject($this->args['#path']); tfProject::set($project); // Choose the language if (isset($this->args['-l'])) { $project->setLanguage($this->args['-l']); } else { $project->setLanguage($project->config['baseLanguage']); } tfTags::setProject($project); try { if (isset($this->args['-o'])) { $prg->console->stdout->writeln('Processing the files.'); $project->loadItems(); $prg->console->stdout->writeln('Starting ' . $this->args['-o'] . '.'); $project->setOutput($this->args['-o']); $project->generate(); $prg->console->stdout->writeln('Generation completed.'); } else { $prg->console->stdout->writeln('Processing the files.'); $project->loadItems(); foreach ($project->config['outputs'] as $out) { $prg->console->stdout->writeln('Starting ' . $out . '.'); $project->setOutput($out); $project->generate(); } $prg->console->stdout->writeln('Generation completed.'); } } catch (Exception $e) { $prg->console->stderr->writeln($e->getMessage()); } }
/** * Validates the tag list and returns the result. * * @param Array &$tags The list of tags * @return Boolean */ public static function validateTags(array &$tags) { // Process the "FeatureInformation" tag. // This tag has to be reparsed every time the method is invoked (because of parsing markdown) if (isset($tags['FeatureInformation'])) { $parser = tfParsers::get(); try { $tags['FeatureInformationFrame'] = $parser->parse(self::$_project->getTemplate($tags['FeatureInformation'])); } catch (SystemException $exception) { self::$_error = 'The feature information identifier: "' . $tags['FeatureInformation'] . '" is not defined.'; return false; } } if (isset($tags['%%Validated'])) { return true; } self::_buildTagList(); if (!isset($tags['Title'])) { self::$_error = 'The required tag "Title" is not defined.'; return false; } if (!isset($tags['ShortTitle'])) { $tags['ShortTitle'] = $tags['Title']; } // Validate the tags. foreach ($tags as $tag => &$value) { if (!isset(self::$_tags[$tag])) { if (!self::$_allowUnknown) { self::$_error = 'The tag "' . $tag . '" cannot be recognized as a valid TypeFriendly tag.'; return false; } } if (!self::_validate($value, self::$_tags[$tag])) { self::$_error = '"' . $tag . '": invalid value.'; return false; } } if (isset($tags['Extends']) && isset($tags['EExtends'])) { self::$_error = 'Tags "Extends" and "EExtends" cannot be used together.'; return false; } if ((isset($tags['Extends']) || isset($tags['EExtends'])) && (isset($tags['MultiExtends']) || isset($tags['EMultiExtends']))) { self::$_error = 'Tags "Extends" and "MultiExtends" cannot be used together.'; return false; } // Process the "Construct" tag if (isset($tags['Construct'])) { $translate = tfTranslate::get(); $construct = strtolower(trim($tags['Construct'])); if (!in_array($construct, self::$_constructs)) { $tags['ConstructType'] = 'unknown'; } else { $tags['ConstructType'] = str_replace(' ', '_', $construct); $tags['Construct'] = $translate->_('constructs', $tags['ConstructType']); } // Using the information from "Construct", we can perform some extra checks. $extends = false; $reference = false; $throws = false; $implementedBy = false; $mixins = false; $traits = false; switch ($tags['ConstructType']) { case 'function': case 'method': case 'static_method': case 'abstract_method': case 'accessor_method': case 'final_method': case 'final_static method': case 'final_accessor_method': case 'optional_method': case 'magic_method': case 'constructor': case 'destructor': case 'macro': case 'operator': $reference = true; $throws = true; break; case 'mixin': case 'trait': $implementedBy = true; break; case 'class': case 'abstract_class': case 'exception_class': case 'internal_class': case 'structure': $extends = true; case 'final_class': $mixins = true; $traits = true; break; case 'interface': $extends = true; $implementedBy = true; break; } if (!$reference && isset($tags['Reference'])) { self::$_error = 'Tag "Reference" is not allowed with the specified construct.'; return false; } if (!$throws && (isset($tags['Throws']) || isset($tags['EThrows']))) { self::$_error = 'Tags "Throws" and "EThrows" are not allowed with the specified construct.'; return false; } if (!$implementedBy && (isset($tags['ImplementedBy']) || isset($tags['EImplementedBy']))) { self::$_error = 'Tags "ImplementedBy" and "EImplementedBy" are not allowed with the specified construct.'; return false; } if (!$mixins && (isset($tags['Mixins']) || isset($tags['EMixins']))) { self::$_error = 'Tags "Mixins" and "EMixins" are not allowed with the specified construct.'; return false; } if (!$traits && (isset($tags['Traits']) || isset($tags['ETraits']))) { self::$_error = 'Tags "Traits" and "ETraits" are not allowed with the specified construct.'; return false; } if ($tags['ConstructType'] != 'internal_class' && (isset($tags['PartOf']) || isset($tags['EPartOf']))) { self::$_error = 'Tags "PartOf" and "EPartOf" are not allowed with the specified construct.'; return false; } if (!$extends && (isset($tags['Extends']) || isset($tags['EExtends']) || isset($tags['Implements']) || isset($tags['Implements']) || isset($tags['ExtendedBy']) || isset($tags['EExtendedBy']) || isset($tags['MultiExtends']) || isset($tags['EMultiExtends']))) { self::$_error = 'The tags that describe the OOP inheritance are not allowed with the specified construct.'; return false; } } $tags['%%Validated'] = true; return true; }