├── .editorconfig
├── LICENSE
├── README.md
├── composer.json
├── config
└── config.yml.default
└── src
└── PatternLab
├── Annotations.php
├── Builder.php
├── Config.php
├── Console.php
├── Console
├── Command.php
├── Commands
│ ├── ConfigCommand.php
│ ├── ExportCommand.php
│ ├── GenerateCommand.php
│ ├── HelpCommand.php
│ ├── ServerCommand.php
│ ├── StarterKitCommand.php
│ ├── VersionCommand.php
│ └── WatchCommand.php
├── Event.php
├── ProcessSpawner.php
└── ProcessSpawnerEvent.php
├── Data.php
├── Dispatcher.php
├── Fetch.php
├── FileUtil.php
├── Generator.php
├── InstallerUtil.php
├── JSON.php
├── Listener.php
├── Migrator.php
├── Parsers
└── Documentation.php
├── PatternData.php
├── PatternData
├── Event.php
├── Exporter.php
├── Exporters
│ ├── DataLinkExporter.php
│ ├── DataMergeExporter.php
│ ├── NavItemsExporter.php
│ ├── PatternPartialsExporter.php
│ ├── PatternPathDestsExporter.php
│ ├── PatternPathSrcExporter.php
│ └── ViewAllPathsExporter.php
├── Helper.php
├── Helpers
│ ├── LineageHelper.php
│ ├── PatternCodeHelper.php
│ ├── PatternStateHelper.php
│ ├── Plugins
│ │ └── CSSRuleSaverHelperPlugin.php
│ └── RawPatternHelper.php
├── Rule.php
└── Rules
│ ├── DocumentationRule.php
│ ├── PatternInfoListItemsRule.php
│ ├── PatternInfoRule.php
│ ├── PatternRule.php
│ ├── PatternSubtypeRule.php
│ ├── PatternTypeRule.php
│ └── PseudoPatternRule.php
├── PatternEngine.php
├── PatternEngine
├── Loader.php
├── Rule.php
└── Util.php
├── Saying.php
├── Template.php
├── Timer.php
├── Util.php
├── Watcher.php
└── Zippy
├── UnpackAdapter.php
└── UnpackFileStrategy.php
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = tab
6 | trim_trailing_whitespace = false
7 | end_of_line = lf
8 | insert_final_newline = true
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Brad Frost, http://bradfrostweb.com & Dave Olsen, http://dmolsen.com
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 | [](https://gitter.im/pattern-lab/php)
3 |
4 | # Pattern Lab Core
5 |
6 | This repository contains the core functionality for Pattern Lab. Pattern Lab Core is designed to be included as a dependency within Editions. Turn it up.
7 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pattern-lab/core",
3 | "description": "The core functionality for Pattern Lab.",
4 | "keywords": ["pattern lab", "styleguide", "style guide", "atomic", "atomic design"],
5 | "homepage": "http://patternlab.io",
6 | "license": "MIT",
7 | "authors": [
8 | {
9 | "name": "Evan Lovely",
10 | "homepage": "http://evanlovely.com",
11 | "role": "Lead Developer"
12 | },
13 | {
14 | "name": "Salem Ghoweri",
15 | "homepage": "https://github.com/sghoweri",
16 | "role": "Developer"
17 | },
18 | {
19 | "name": "Dave Olsen",
20 | "email": "dmolsen@gmail.com",
21 | "homepage": "http://dmolsen.com",
22 | "role": "Former Lead Developer"
23 | },
24 | {
25 | "name": "Brad Frost",
26 | "homepage": "http://bradfrostweb.com",
27 | "role": "Creator"
28 | }
29 | ],
30 | "support": {
31 | "issues": "https://github.com/pattern-lab/patternlab-php-core/issues",
32 | "wiki": "http://patternlab.io/docs/",
33 | "source": "https://github.com/pattern-lab/patternlab-php-core/releases"
34 | },
35 | "autoload": {
36 | "psr-0": {
37 | "PatternLab": "src/"
38 | }
39 | },
40 | "require": {
41 | "php": ">=5.4",
42 | "alchemy/zippy": "^0.3",
43 | "doctrine/collections": "1.4.0",
44 | "kevinlebrun/colors.php": "^1.0",
45 | "michelf/php-markdown": "^1.6",
46 | "seld/jsonlint": "^1.0",
47 | "shudrum/array-finder": "^1.0",
48 | "symfony/event-dispatcher": "^3.0",
49 | "symfony/filesystem": "^3.0",
50 | "symfony/finder": "^3.0",
51 | "symfony/process": "^3.1",
52 | "symfony/yaml": "^3.0"
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/config/config.yml.default:
--------------------------------------------------------------------------------
1 | ## Configuration Options for Pattern Lab
2 |
3 | # pattern lab version
4 | v: "2.6.0"
5 |
6 | # what to do when included config var conflicts, q for question, a for always override, n for never override
7 | overrideConfig: "q"
8 |
9 | # file extensions to ignore when building or watching the source dir, separate with a comma
10 | ie:
11 | - "DS_Store"
12 | - "less"
13 | - "scss"
14 |
15 | # directories and files to ignore when building or watching the source dir, separate with a comma
16 | id:
17 | - "scss"
18 | - ".svn"
19 | - ".sass-cache"
20 |
21 | # whether the public directory should be cleaned when generating your site
22 | cleanPublic: "true"
23 |
24 | # the order of pattern states, css class names
25 | patternStates:
26 | - "inprogress"
27 | - "inreview"
28 | - "complete"
29 |
30 | # the pattern types that shouldn't be included in the style guide, useful if you nest pages/templates
31 | styleGuideExcludes: ""
32 |
33 | # should the cache buster be on, set to false to set the cacheBuster value to 0
34 | cacheBusterOn: "true"
35 |
36 | # project directories
37 | exportDir: "export"
38 | publicDir: "public"
39 | sourceDir: "source"
40 |
41 | # defaultPattern to show on load
42 | defaultPattern: "all"
43 |
44 | # show pattern info by default on the "view all" views
45 | defaultShowPatternInfo: false
46 |
--------------------------------------------------------------------------------
/src/PatternLab/Annotations.php:
--------------------------------------------------------------------------------
1 | dispatch("annotations.gatherStart");
50 |
51 | // set-up the comments store
52 | self::$store["comments"] = array();
53 |
54 | // create the annotations dir if it doesn't exist
55 | if (!is_dir($annotationsDir)) {
56 | mkdir($annotationsDir);
57 | }
58 |
59 | // find the markdown-based annotations
60 | $finder = new Finder();
61 | $finder->files()->name("*.md")->in($annotationsDir);
62 | $finder->sortByName();
63 |
64 | foreach ($finder as $name => $file) {
65 |
66 | $data = array();
67 | $data[0] = array();
68 |
69 | $text = file_get_contents($file->getPathname());
70 |
71 | $matches = (strpos($text,PHP_EOL."~*~".PHP_EOL) !== false) ? explode(PHP_EOL."~*~".PHP_EOL,$text) : array($text);
72 |
73 | foreach ($matches as $match) {
74 |
75 | list($yaml,$markdown) = Documentation::parse($match);
76 |
77 | if (isset($yaml["el"]) || isset($yaml["selector"])) {
78 | $data[0]["el"] = (isset($yaml["el"])) ? $yaml["el"] : $yaml["selector"];
79 | } else {
80 | $data[0]["el"] = "#someimpossibleselector";
81 | }
82 | $data[0]["title"] = isset($yaml["title"]) ? $yaml["title"] : "";
83 | $data[0]["comment"] = $markdown;
84 |
85 | self::$store["comments"] = array_merge(self::$store["comments"],$data);
86 |
87 | }
88 |
89 | }
90 |
91 | // read in the old style annotations.js, modify the data and generate JSON array to merge
92 | $data = array();
93 | $oldStyleAnnotationsPath = $annotationsDir.DIRECTORY_SEPARATOR."annotations.js";
94 | if (file_exists($oldStyleAnnotationsPath)) {
95 | $text = trim(file_get_contents($oldStyleAnnotationsPath));
96 | $text = str_replace("var comments = ","",$text);
97 | if ($text[strlen($text)-1] == ";") {
98 | $text = rtrim($text,";");
99 | }
100 | $data = json_decode($text,true);
101 | if ($jsonErrorMessage = JSON::hasError()) {
102 | JSON::lastErrorMsg(Console::getHumanReadablePath($oldStyleAnnotationsPath),$jsonErrorMessage,$data);
103 | }
104 | }
105 |
106 | // merge in any data from the old file if the json decode was successful
107 | if (is_array($data) && isset($data["comments"])) {
108 | self::$store["comments"] = array_merge(self::$store["comments"],$data["comments"]);
109 | }
110 |
111 | $dispatcherInstance->dispatch("annotations.gatherEnd");
112 |
113 | }
114 |
115 | /**
116 | * Get the data in the store
117 | */
118 | public static function get() {
119 | return self::$store;
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/src/PatternLab/Console/Command.php:
--------------------------------------------------------------------------------
1 | pathPHP = Console::getPathPHP();
28 | $this->pathConsole = Console::getPathConsole();
29 |
30 | }
31 |
32 | /**
33 | * See if a particular command matches the one passed via the command line
34 | * @param {String} the command to check
35 | *
36 | * @return {Boolean} the result of the test
37 | */
38 | public function test($command) {
39 | return ($command == str_replace(":","",$this->command));
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/PatternLab/Console/Commands/ConfigCommand.php:
--------------------------------------------------------------------------------
1 | command = "config";
29 |
30 | Console::setCommand($this->command,"Configure Pattern Lab","The --config command allows for the review and update of existing Pattern Lab config options.","c");
31 | Console::setCommandOption($this->command,"get:","Get the value for a specific config option.","To get a configuration option:","","configOption");
32 | Console::setCommandOption($this->command,"list","List the current config options.","To list the current configuration:");
33 | Console::setCommandOption($this->command,"set:","Set the value for a specific config option.","To set a configuration option:","","configOption=\"configValue\"");
34 |
35 | }
36 |
37 | public function run() {
38 |
39 | if (Console::findCommandOption("list")) {
40 |
41 | $this->listOptions();
42 |
43 | } else if (Console::findCommandOption("get")) {
44 |
45 | $this->getOption();
46 |
47 | } else if (Console::findCommandOption("set")) {
48 |
49 | $this->setOption();
50 |
51 | } else {
52 |
53 | Console::writeHelpCommand($this->command);
54 |
55 | }
56 |
57 | }
58 |
59 | /**
60 | * Get the given option and return its value
61 | */
62 | private function getOption() {
63 |
64 | // figure out which option was passed
65 | $searchOption = Console::findCommandOptionValue("get");
66 | $optionValue = Config::getOption($searchOption);
67 |
68 | // write it out
69 | if (!$optionValue) {
70 | Console::writeError("the --get value you provided, ".$searchOption.", does not exists in the config...");
71 | } else {
72 | $optionValue = (is_array($optionValue)) ? implode(", ",$optionValue) : $optionValue;
73 | $optionValue = (!$optionValue) ? "false" : $optionValue;
74 | Console::writeInfo($searchOption.": ".$optionValue."");
75 | }
76 |
77 | }
78 |
79 | /**
80 | * List out of the options available in the config
81 | */
82 | private function listOptions() {
83 |
84 | // get all of the options
85 | $options = Config::getOptions();
86 |
87 | // sort 'em alphabetically
88 | ksort($options);
89 |
90 | // find length of longest option
91 | $this->lengthLong = 0;
92 | foreach ($options as $optionName => $optionValue) {
93 | $this->lengthLong = (strlen($optionName) > $this->lengthLong) ? strlen($optionName) : $this->lengthLong;
94 | }
95 |
96 | $this->writeOutOptions($options);
97 |
98 | }
99 |
100 | /**
101 | * Set the given option to the given value
102 | */
103 | protected function setOption() {
104 |
105 | // find the value that was passed
106 | $updateOption = Console::findCommandOptionValue("set");
107 | $updateOptionBits = explode("=",$updateOption);
108 | if (count($updateOptionBits) == 1) {
109 | Console::writeError("the --set value should look like optionName=\"optionValue\". nothing was updated...");
110 | }
111 |
112 | // set the name and value that were passed
113 | $updateName = $updateOptionBits[0];
114 | $updateValue = (($updateOptionBits[1][0] == "\"") || ($updateOptionBits[1][0] == "'")) ? substr($updateOptionBits[1],1,strlen($updateOptionBits[1])-1) : $updateOptionBits[1];
115 |
116 | // make sure the option being updated already exists
117 | $currentValue = Config::getOption($updateName);
118 |
119 | if (!$currentValue) {
120 | Console::writeError("the --set option you provided, ".$updateName.", does not exists in the config. nothing will be updated...");
121 | } else {
122 | Config::updateConfigOption($updateName,$updateValue);
123 | Console::writeInfo("config option updated...");
124 | }
125 |
126 | }
127 |
128 | /**
129 | * Write out the given options. Check to see if it's a nested sequential or associative array
130 | * @param {Mixed} the options to check and write out
131 | * @param {String} copy to be added to the beginning of the option if nested
132 | */
133 | private function writeOutOptions($options, $pre = "") {
134 |
135 | foreach ($options as $optionName => $optionValue) {
136 |
137 | if (is_array($optionValue) && (count($optionValue) > 0) && !isset($optionValue[0])) {
138 |
139 | $this->writeOutOptions($optionValue, $optionName.".");
140 |
141 | } else {
142 |
143 | $optionValue = (is_array($optionValue) && isset($optionValue[0])) ? implode(", ",$optionValue) : $optionValue;
144 | $optionValue = (!$optionValue) ? "false" : $optionValue;
145 | $spacer = Console::getSpacer($this->lengthLong,strlen($pre.$optionName));
146 | Console::writeLine("".$pre.$optionName.":".$spacer.$optionValue);
147 |
148 | }
149 |
150 | }
151 |
152 | }
153 |
154 | }
155 |
--------------------------------------------------------------------------------
/src/PatternLab/Console/Commands/ExportCommand.php:
--------------------------------------------------------------------------------
1 | command = "export";
30 |
31 | Console::setCommand($this->command,"Export Pattern Lab patterns & assets","The export command generates your patterns without Pattern Lab's CSS & JS, copies static assets from public/, and puts all of it in export/.","e");
32 | Console::setCommandOption($this->command,"clean","Don't add any header or footer mark-up to the exported patterns.","To generate clean versions of your patterns:");
33 |
34 | }
35 |
36 | public function run() {
37 |
38 | // set-up required vars
39 | $options = array();
40 | $options["exportFiles"] = true;
41 | $options["exportClean"] = Console::findCommandOption("clean");
42 | $options["moveStatic"] = false;
43 |
44 | FileUtil::cleanExport();
45 |
46 | $g = new Generator();
47 | $g->generate($options);
48 |
49 | FileUtil::exportStatic();
50 |
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/PatternLab/Console/Commands/GenerateCommand.php:
--------------------------------------------------------------------------------
1 | command = "generate";
27 |
28 | Console::setCommand($this->command,"Generate Pattern Lab","The generate command generates an entire site a single time. By default it removes old content in public/, compiles the patterns and moves content from source/ into public/","g");
29 | Console::setCommandOption($this->command,"patternsonly","Generate only the patterns. Does NOT clean public/.","To generate only the patterns:","p");
30 | Console::setCommandOption($this->command,"nocache","Set the cacheBuster value to 0.","To turn off the cacheBuster:","n");
31 |
32 | }
33 |
34 | public function run() {
35 |
36 | // set-up required vars
37 | $options = array();
38 | $options["moveStatic"] = (Console::findCommandOption("p|patternsonly")) ? false : true;
39 | $options["noCacheBuster"] = Console::findCommandOption("n|nocache");
40 |
41 | $g = new Generator();
42 | $g->generate($options);
43 |
44 | $s = new Saying();
45 | $s->say();
46 |
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/PatternLab/Console/Commands/HelpCommand.php:
--------------------------------------------------------------------------------
1 | command = "help:";
24 |
25 | Console::setCommand($this->command,"Print the help for a given command","The help command prints out the help for a given flag. Just use -h with another command and it will tell you all of the options.","h:");
26 | Console::setCommandSample($this->command,"To get help for a particular command:","");
27 |
28 | }
29 |
30 | public function run() {
31 |
32 | if ($helpCommand = Console::findCommandValue("h|help")) {
33 | $helpCommand = str_replace("-","",$helpCommand);
34 | if ($commandFound = Console::findCommandLong($helpCommand)) {
35 | Console::writeHelpCommand($commandFound);
36 | } else {
37 | Console::writeHelp();
38 | }
39 | } else {
40 | Console::writeHelp();
41 | }
42 |
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/PatternLab/Console/Commands/ServerCommand.php:
--------------------------------------------------------------------------------
1 | command = "server";
28 |
29 | Console::setCommand($this->command,"Start the PHP-based server","The server command will start PHP's web server for you.","s");
30 | Console::setCommandOption($this->command,"host:","Provide a custom hostname. Default value is localhost.","To use a custom hostname and the default port:","","");
31 | Console::setCommandOption($this->command,"port:","Provide a custom port. Default value is 8080.","To use a custom port and the default hostname:","","");
32 | Console::setCommandOption($this->command,"quiet","Turn on quiet mode for the server.","To turn on quiet mode:");
33 | Console::setCommandOption($this->command,"with-watch","Start watching ./source when starting the server. Takes the same arguments as --watch.","To turn on with-watch mode:");
34 | Console::setCommandSample($this->command,"To provide both a custom hostname and port:","--host --port ");
35 |
36 | }
37 |
38 | public function run() {
39 |
40 | if (version_compare(phpversion(), '5.4.0', '<')) {
41 |
42 | Console::writeWarning("you must have PHP 5.4.0 or greater to use this feature. you are using PHP ".phpversion()."...");
43 |
44 | } else {
45 |
46 | // set-up defaults
47 | $publicDir = Config::getOption("publicDir");
48 | $coreDir = Config::getOption("coreDir");
49 |
50 | $host = Console::findCommandOptionValue("host");
51 | $host = $host ? $host : "localhost";
52 |
53 | $port = Console::findCommandOptionValue("port");
54 | $host = $port ? $host.":".$port : $host.":8080";
55 |
56 | $quiet = Console::findCommandOption("quiet");
57 |
58 | // set-up the base command
59 | $command = $this->pathPHP." -S ".$host." ".$coreDir."/server/router.php";
60 | $commands = array();
61 | $commands[] = array("command" => $command, "cwd" => $publicDir, "timeout" => null, "idle" => 1800);
62 |
63 | // get the watch command info
64 | if (Console::findCommandOption("with-watch")) {
65 | $watchCommand = new WatchCommand;
66 | $commands[] = array("command" => $watchCommand->build()." --no-procs", "timeout" => null, "idle" => 1800);
67 | }
68 |
69 | Console::writeInfo("server started on http://".$host." - use ctrl+c to exit...");
70 |
71 | $processSpawner = new ProcessSpawner;
72 | $processSpawner->spawn($commands, $quiet);
73 |
74 | }
75 |
76 | }
77 |
78 | public function build() {
79 |
80 | $command = $this->pathPHP." ".$this->pathConsole." --".$this->command;
81 |
82 | $host = Console::findCommandOptionValue("host");
83 | $port = Console::findCommandOptionValue("port");
84 |
85 | if ($host) {
86 | $command .= " --host ".$host;
87 | }
88 | if ($port) {
89 | $command .= " --port ".$port;
90 | }
91 |
92 | return $command;
93 |
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/src/PatternLab/Console/Commands/StarterKitCommand.php:
--------------------------------------------------------------------------------
1 | command = "starterkit";
28 |
29 | Console::setCommand($this->command,"Initialize or fetch a specific StarterKit","The StarterKit command downloads StarterKits.","k");
30 | Console::setCommandOption($this->command,"init","Initialize with a blank StarterKit based on the active PatternEngine.","To initialize your project with a base StarterKit:","i");
31 | Console::setCommandOption($this->command,"install:","Fetch a specific StarterKit from GitHub.","To fetch a StarterKit from GitHub:","j:","");
32 | Console::setCommandOption($this->command,"suggestions","Show suggested StarterKits for this Edition. Offer install prompt.","To show suggested StarterKits for this Edition:");
33 |
34 | }
35 |
36 | public function run() {
37 |
38 | // find the value given to the command
39 | $init = Console::findCommandOption("i|init");
40 | $starterkit = Console::findCommandOptionValue("f|install");
41 | $suggestions = Console::findCommandOption("suggestions");
42 |
43 | if ($suggestions) {
44 |
45 | $this->starterKitSuggestions();
46 |
47 | } else if ($init || $starterkit) {
48 |
49 | $this->starterKitInstall($starterkit, $init);
50 |
51 | } else {
52 |
53 | Console::writeHelpCommand($this->command);
54 |
55 | }
56 |
57 | }
58 |
59 | protected function starterKitInstall($starterkit, $init) {
60 |
61 | // set-up the base starterkit
62 | if ($init) {
63 | $patternEngine = Config::getOption("patternExtension");
64 | $starterkit = "pattern-lab/starterkit-".$patternEngine."-base";
65 | }
66 |
67 | // download the starterkit
68 | $f = new Fetch();
69 | $f->fetchStarterKit($starterkit);
70 |
71 | }
72 |
73 | protected function starterKitSuggestions() {
74 |
75 | Console::writeLine("");
76 |
77 | $composerPath = Config::getOption("baseDir")."/composer.json";
78 | if (file_exists($composerPath)) {
79 |
80 | $json = file_get_contents($composerPath);
81 | $data = json_decode($json,true);
82 | if ($jsonErrorMessage = JSON::hasError()) {
83 | JSON::lastErrorMsg(Console::getHumanReadablePath($oldStyleAnnotationsPath),$jsonErrorMessage,$data);
84 | }
85 |
86 | if (isset($data["extra"]) && isset($data["extra"]["patternlab"]) && isset($data["extra"]["patternlab"]["starterKitSuggestions"])) {
87 |
88 | $starterKitSuggestions = $data["extra"]["patternlab"]["starterKitSuggestions"];
89 |
90 | Console::writeInfo("suggested starterkits that work with this edition:", false, true);
91 | foreach ($starterKitSuggestions as $i => $suggestion) {
92 | $num = $i + 1;
93 | Console::writeLine($num.": ".$suggestion, true);
94 | }
95 |
96 | // hack around installer util feature in Console::promptInput
97 | InstallerUtil::$isInteractive = true;
98 |
99 | // prompt for input on the suggestions
100 | Console::writeLine("");
101 |
102 | $prompt = "choose an option or hit return to cancel:";
103 | $options = "(ex. 1)";
104 | $input = Console::promptInput($prompt,$options,"1");
105 | $result = (int)$input - 1;
106 |
107 | if (isset($starterKitSuggestions[$result])) {
108 |
109 | Console::writeLine("");
110 | $f = new Fetch();
111 | $result = $f->fetchStarterKit($starterKitSuggestions[$result]);
112 |
113 | }
114 |
115 | } else {
116 |
117 | Console::writeWarning("this edition has no starterkits to suggested...", false, true);
118 |
119 | }
120 |
121 | } else {
122 |
123 | Console::writeError("can't find composer.json to get suggestions...", false, true);
124 |
125 | }
126 |
127 |
128 |
129 | }
130 |
131 | }
132 |
--------------------------------------------------------------------------------
/src/PatternLab/Console/Commands/VersionCommand.php:
--------------------------------------------------------------------------------
1 | command = "version";
25 |
26 | Console::setCommand($this->command,"Print the version number","The version command prints out the current version of Pattern Lab.","v");
27 |
28 | }
29 |
30 | public function run() {
31 |
32 | Console::writeInfo("you're running v".Config::getOption("v")." of the PHP version of Pattern Lab...");
33 |
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/PatternLab/Console/Commands/WatchCommand.php:
--------------------------------------------------------------------------------
1 | command = "watch";
28 |
29 | Console::setCommand($this->command,"Watch for changes and regenerate","The watch command builds Pattern Lab, watches for changes in source/ and regenerates Pattern Lab when there are any.","w");
30 | Console::setCommandOption($this->command,"patternsonly","Watches only the patterns. Does NOT clean public/.","To watch and generate only the patterns:","p");
31 | Console::setCommandOption($this->command,"nocache","Set the cacheBuster value to 0.","To watch and turn off the cache buster:","n");
32 | Console::setCommandOption($this->command,"sk","Watch for changes to the StarterKit and copy to source/. The --sk flag should only be used if one is actively developing a StarterKit.","To watch for changes to the StarterKit:");
33 | Console::setCommandOption($this->command,"no-procs","Disable plug-in related processes. For use with --server --with-watch.","To disable plug-in related processes:");
34 | Console::setCommandSample($this->command,"To watch only patterns and turn off the cache buster:","--patternsonly --nocache");
35 |
36 | }
37 |
38 | public function run() {
39 |
40 | // set-up required vars
41 | $options = array();
42 | $options["moveStatic"] = (Console::findCommandOption("p|patternsonly")) ? false : true;
43 | $options["noCacheBuster"] = Console::findCommandOption("n|nocache");
44 |
45 | // see if the starterKit flag was passed so you know what dir to watch
46 | if (Console::findCommandOption("sk")) {
47 |
48 | // load the starterkit watcher
49 | $w = new Watcher();
50 | $w->watchStarterKit();
51 |
52 | } else {
53 |
54 | if (Console::findCommandOption("no-procs")) {
55 |
56 | // don't have to worry about loading processes so launch watcher
57 |
58 | // load the generator
59 | $g = new Generator();
60 | $g->generate($options);
61 |
62 | // load the watcher
63 | $w = new Watcher();
64 | $w->watch($options);
65 |
66 | } else {
67 |
68 | // a vanilla --watch command needs to have a --no-procs version built
69 | // so we don't get caught in while() loops. re-request the console command
70 | $commands = array();
71 | $commands[] = array("command" => $this->build()." --no-procs", "timeout" => null, "idle" => 600);
72 |
73 | Console::writeInfo("spawning the watch process...");
74 |
75 | $process = new ProcessSpawner;
76 | $process->spawn($commands);
77 |
78 | }
79 |
80 | }
81 |
82 | }
83 |
84 | public function build() {
85 |
86 | $command = $this->pathPHP." ".$this->pathConsole." --".$this->command;
87 |
88 | if (Console::findCommandOption("p|patternsonly")) {
89 | $command .= " --patternsonly";
90 | }
91 | if (Console::findCommandOption("n|nocache")) {
92 | $command .= " --nocache";
93 | }
94 |
95 | return $command;
96 |
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/src/PatternLab/Console/Event.php:
--------------------------------------------------------------------------------
1 | options = $options;
23 | }
24 |
25 | public function getOptions() {
26 | return $this->options;
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/PatternLab/Console/ProcessSpawner.php:
--------------------------------------------------------------------------------
1 | dispatch('processSpawner.getPluginProcesses',$event);
39 | $this->pluginProcesses = $event->getPluginProcesses();
40 |
41 | }
42 |
43 | /**
44 | * Spawn the passed commands and those collected from plugins
45 | * @param {Array} a list of commands to spawn
46 | * @param {Boolean} if this should be run in quiet mode
47 | */
48 | public function spawn($commands = array(), $quiet = false) {
49 |
50 | // set-up a default
51 | $processes = array();
52 |
53 | // add the default processes sent to the spawner
54 | if (!empty($commands)) {
55 | foreach ($commands as $command) {
56 | $processes[] = $this->buildProcess($command);
57 | }
58 | }
59 |
60 | // add the processes sent to the spawner from plugins
61 | foreach ($this->pluginProcesses as $pluginProcess) {
62 | $processes[] = $this->buildProcess($pluginProcess);
63 | }
64 |
65 | // if there are processes to spawn do so
66 | if (!empty($processes)) {
67 |
68 | // start the processes
69 | foreach ($processes as $process) {
70 | $process["process"]->start();
71 | }
72 |
73 | // check on them and produce output
74 | while (true) {
75 | foreach ($processes as $process) {
76 | try {
77 | if ($process["process"]->isRunning()) {
78 | $process["process"]->checkTimeout();
79 | if (!$quiet && $process["output"]) {
80 | print $process["process"]->getIncrementalOutput();
81 | $cmd = $process["process"]->getCommandLine();
82 | if (strpos($cmd,"router.php") != (strlen($cmd) - 10)) {
83 | print $process["process"]->getIncrementalErrorOutput();
84 | }
85 | }
86 | }
87 | } catch (ProcessTimedOutException $e) {
88 | if ($e->isGeneralTimeout()) {
89 | Console::writeError("pattern lab processes should never time out. yours did...");
90 | } else if ($e->isIdleTimeout()) {
91 | Console::writeError("pattern lab processes automatically time out if their is no command line output in 30 minutes...");
92 | }
93 | }
94 | }
95 | usleep(100000);
96 | }
97 | }
98 |
99 | }
100 |
101 | /**
102 | * Build the process from the given commandOptions
103 | * @param {Array} the options from which to build the process
104 | */
105 | protected function buildProcess($commandOptions) {
106 |
107 | if (is_string($commandOptions)) {
108 |
109 | $process = new Process(escapeshellcmd((string) $commandOptions));
110 | return array("process" => $process, "output" => true);
111 |
112 | } else if (is_array($commandOptions)) {
113 |
114 | $commandline = escapeshellcmd((string) $commandOptions["command"]);
115 | $cwd = isset($commandOptions["cwd"]) ? $commandOptions["cwd"] : null;
116 | $env = isset($commandOptions["env"]) ? $commandOptions["env"] : null;
117 | $input = isset($commandOptions["input"]) ? $commandOptions["input"] : null;
118 | $timeout = isset($commandOptions["timeout"]) ? $commandOptions["timeout"] : null;
119 | $options = isset($commandOptions["options"]) ? $commandOptions["options"] : array();
120 | $idle = isset($commandOptions["idle"]) ? $commandOptions["idle"] : null;
121 | $output = isset($commandOptions["output"]) ? $commandOptions["output"] : true;
122 |
123 | $process = new Process($commandline, $cwd, $env, $input, $timeout, $options);
124 |
125 | // double-check idle
126 | if (!empty($idle)) {
127 | $process->setIdleTimeout($idle);
128 | }
129 |
130 | return array("process" => $process, "output" => $output);
131 |
132 | }
133 |
134 | }
135 |
136 | }
137 |
--------------------------------------------------------------------------------
/src/PatternLab/Console/ProcessSpawnerEvent.php:
--------------------------------------------------------------------------------
1 | pluginProcesses = array();
23 | }
24 |
25 | public function addPluginProcesses($processes = array()) {
26 | if (!empty($processes)) {
27 | $this->pluginProcesses = array_merge($this->pluginProcesses, $processes);
28 | }
29 | }
30 |
31 | public function getPluginProcesses() {
32 | return $this->pluginProcesses;
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/PatternLab/Data.php:
--------------------------------------------------------------------------------
1 | $v) {
62 | if (is_array($v)) {
63 | $array[$k] = self::recursiveWalk($v);
64 | } else {
65 | $array[$k] = self::compareReplaceListVars($v);
66 | }
67 | }
68 | return $array;
69 | }
70 |
71 | /**
72 | * Set-up the recursive walk so that the data can be properly saved
73 | */
74 | public static function compareReplaceListVarsInit() {
75 |
76 | self::$store = self::recursiveWalk(self::$store);
77 |
78 | }
79 |
80 | /**
81 | * Gather data from any JSON and YAML files in source/_data
82 | *
83 | * Reserved attributes:
84 | * - Data::$store["listItems"] : listItems from listitems.json, duplicated into separate arrays for Data::$store["listItems"]["one"], Data::$store["listItems"]["two"]... etc.
85 | * - Data::$store["link"] : the links to each pattern
86 | * - Data::$store["cacheBuster"] : the cache buster value to be appended to URLs
87 | * - Data::$store["patternSpecific"] : holds attributes from the pattern-specific data files
88 | *
89 | * @return {Array} populates Data::$store
90 | */
91 | public static function gather($options = array()) {
92 |
93 | // set-up the dispatcher
94 | $dispatcherInstance = Dispatcher::getInstance();
95 |
96 | // dispatch that the data gather has started
97 | $dispatcherInstance->dispatch("data.gatherStart");
98 |
99 | // default vars
100 | $found = false;
101 | $dataJSON = array();
102 | $dataYAML = array();
103 | $listItemsJSON = array();
104 | $listItemsYAML = array();
105 | $sourceDir = Config::getOption("sourceDir");
106 |
107 | // iterate over all of the other files in the source directory
108 | if (!is_dir($sourceDir."/_data/")) {
109 | Console::writeWarning("_data/ doesn't exist so you won't have dynamic data...");
110 | mkdir($sourceDir."/_data/");
111 | }
112 |
113 | // find the markdown-based annotations
114 | $finder = new Finder();
115 | $finder->files()->in($sourceDir."/_data/");
116 | $finder->sortByName();
117 |
118 | foreach ($finder as $name => $file) {
119 |
120 | $ext = $file->getExtension();
121 | $data = array();
122 | $fileName = $file->getFilename();
123 | $hidden = ($fileName[0] == "_");
124 | $isListItems = strpos($fileName,"listitems");
125 | $pathName = $file->getPathname();
126 | $pathNameClean = str_replace($sourceDir."/","",$pathName);
127 |
128 | if (!$hidden && (($ext == "json") || ($ext == "yaml") || ($ext == "yml"))) {
129 |
130 | if ($isListItems === false) {
131 |
132 | if ($ext == "json") {
133 |
134 | $file = file_get_contents($pathName);
135 | $data = json_decode($file,true);
136 | if ($jsonErrorMessage = JSON::hasError()) {
137 | JSON::lastErrorMsg($pathNameClean,$jsonErrorMessage,$data);
138 | }
139 |
140 | } else if (($ext == "yaml") || ($ext == "yml")) {
141 |
142 | $file = file_get_contents($pathName);
143 |
144 | try {
145 | $data = YAML::parse($file);
146 | } catch (ParseException $e) {
147 | printf("unable to parse ".$pathNameClean.": %s..\n", $e->getMessage());
148 | }
149 |
150 | // single line of text won't throw a YAML error. returns as string
151 | if (gettype($data) == "string") {
152 | $data = array();
153 | }
154 |
155 | }
156 |
157 | if (is_array($data)) {
158 | self::$store = array_replace_recursive(self::$store,$data);
159 | }
160 |
161 | } else if ($isListItems !== false) {
162 |
163 | $data = ($ext == "json") ? self::getListItems("_data/".$fileName) : self::getListItems("_data/".$fileName,"yaml");
164 |
165 | if (!isset(self::$store["listItems"])) {
166 | self::$store["listItems"] = array();
167 | }
168 |
169 | self::$store["listItems"] = array_replace_recursive(self::$store["listItems"],$data);
170 |
171 | }
172 |
173 | }
174 |
175 | }
176 |
177 | if (is_array(self::$store)) {
178 | foreach (self::$reservedKeys as $reservedKey) {
179 | if (array_key_exists($reservedKey,self::$store)) {
180 | Console::writeWarning("\"".$reservedKey."\" is a reserved key in Pattern Lab. the data using that key will be overwritten. please choose a new key...");
181 | }
182 | }
183 | }
184 |
185 | self::$store["cacheBuster"] = Config::getOption("cacheBuster");
186 | self::$store["link"] = array();
187 | self::$store["patternSpecific"] = array();
188 |
189 | $dispatcherInstance->dispatch("data.gatherEnd");
190 |
191 | }
192 |
193 | /**
194 | * Grab a copy of the $store
195 | *
196 | * @return {Array} the store
197 | */
198 | public static function get() {
199 | return self::$store;
200 | }
201 |
202 |
203 |
204 | /**
205 | * Generate the listItems array
206 | * @param {String} the filename for the pattern to be parsed
207 | * @param {String} the extension so that a flag switch can be used to parse data
208 | *
209 | * @return {Array} the final set of list items
210 | */
211 | public static function getListItems($filepath,$ext = "json") {
212 |
213 | // set-up the dispatcher
214 | $dispatcherInstance = Dispatcher::getInstance();
215 |
216 | // dispatch that the data gather has started
217 | $dispatcherInstance->dispatch("data.getListItemsStart");
218 |
219 | // default vars
220 | $sourceDir = Config::getOption("sourceDir");
221 | $listItems = array();
222 | $listItemsData = array();
223 |
224 | // add list item data, makes 'listItems' a reserved word
225 | if (file_exists($sourceDir."/".$filepath)) {
226 |
227 | $file = file_get_contents($sourceDir."/".$filepath);
228 |
229 | if ($ext == "json") {
230 | $listItemsData = json_decode($file, true);
231 | if ($jsonErrorMessage = JSON::hasError()) {
232 | JSON::lastErrorMsg($filepath,$jsonErrorMessage,$listItems);
233 | }
234 | } else {
235 |
236 | try {
237 | $listItemsData = YAML::parse($file);
238 | } catch (ParseException $e) {
239 | printf("unable to parse ".$pathNameClean.": %s..\n", $e->getMessage());
240 | }
241 |
242 | // single line of text won't throw a YAML error. returns as string
243 | if (gettype($listItemsData) == "string") {
244 | $listItemsData = array();
245 | }
246 |
247 | }
248 |
249 |
250 | $numbers = array("one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve");
251 |
252 | $i = 0;
253 | $k = 1;
254 | $c = count($listItemsData)+1;
255 |
256 | while ($k < $c) {
257 |
258 | shuffle($listItemsData);
259 | $itemsArray = array();
260 |
261 | while ($i < $k) {
262 | $itemsArray[] = $listItemsData[$i];
263 | $i++;
264 | }
265 |
266 | $listItems[$numbers[$k-1]] = $itemsArray;
267 |
268 | $i = 0;
269 | $k++;
270 |
271 | }
272 |
273 | }
274 |
275 | $dispatcherInstance->dispatch("data.getListItemsEnd");
276 |
277 | return $listItems;
278 |
279 | }
280 |
281 | /**
282 | * Get an option for the data store
283 | * @param {String} a string in dot notation dictating where the option is in the data structure
284 | *
285 | * @return {Array} the store
286 | */
287 | public static function getOption($key = "") {
288 | if (!empty($key)) {
289 | $arrayFinder = new ArrayFinder(self::$store);
290 | return $arrayFinder->get($key);
291 | }
292 | return false;
293 | }
294 |
295 | /**
296 | * Get the final data array specifically for a pattern
297 | * @param {String} the filename for the pattern to be parsed
298 | * @param {Array} any extra data that should be added to the pattern specific data that's being returned
299 | *
300 | * @return {Array} the final set of list items
301 | */
302 | public static function getPatternSpecificData($patternPartial,$extraData = array()) {
303 |
304 | // if there is pattern-specific data make sure to override the default in $this->d
305 | $d = self::get();
306 |
307 | if (isset($d["patternSpecific"]) && array_key_exists($patternPartial,$d["patternSpecific"])) {
308 |
309 | if (!empty($d["patternSpecific"][$patternPartial]["data"])) {
310 | $d = array_replace_recursive($d, $d["patternSpecific"][$patternPartial]["data"]);
311 | }
312 |
313 | if (!empty($d["patternSpecific"][$patternPartial]["listItems"])) {
314 |
315 | $numbers = array("one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve");
316 |
317 | $k = 0;
318 | $c = count($d["patternSpecific"][$patternPartial]["listItems"]);
319 |
320 | while ($k < $c) {
321 | $section = $numbers[$k];
322 | $d["listItems"][$section] = array_replace_recursive( $d["listItems"][$section], $d["patternSpecific"][$patternPartial]["listItems"][$section]);
323 | $k++;
324 | }
325 |
326 | }
327 |
328 | }
329 |
330 | if (!empty($extraData)) {
331 | $d = array_replace_recursive($d, $extraData);
332 | }
333 |
334 | unset($d["patternSpecific"]);
335 |
336 | return $d;
337 |
338 | }
339 |
340 | /**
341 | * Initialize a pattern specific data store under the patternSpecific option
342 | * @param {String} the pattern to create an array for
343 | */
344 | public static function initPattern($optionName) {
345 |
346 | if (!isset(self::$store["patternSpecific"])) {
347 | self::$store["patternSpecific"] = array();
348 | }
349 |
350 | if ((!isset(self::$store["patternSpecific"][$optionName])) || (!is_array(self::$store["patternSpecific"][$optionName]))) {
351 | self::$store["patternSpecific"][$optionName] = array();
352 | }
353 |
354 | }
355 |
356 | /**
357 | * Print out the data var. For debugging purposes
358 | *
359 | * @return {String} the formatted version of the d object
360 | */
361 | public static function printData() {
362 | print_r(self::$store);
363 | }
364 |
365 | /**
366 | * Replace the data store
367 | * @param {Array} the new store
368 | */
369 | public static function replaceStore($store) {
370 | self::$store = $store;
371 | }
372 |
373 | /**
374 | * Set an option for the data store
375 | * @param {String} a string in dot notation dictating where the option is in the data structure
376 | * @param {Mixed} the value for the key
377 | *
378 | * @return {Array} the store
379 | */
380 | public static function setOption($key = "", $value = "") {
381 |
382 | if (empty($key)) {
383 | return false;
384 | }
385 |
386 | $arrayFinder = new ArrayFinder(self::$store);
387 | $arrayFinder->set($key, $value);
388 | self::$store = $arrayFinder->get();
389 |
390 | }
391 |
392 | /**
393 | * Set an option on a sub element of the data array
394 | * @param {String} name of the option
395 | * @param {String} value for the option
396 | */
397 | public static function setOptionLink($optionName,$optionValue) {
398 |
399 | if (!isset(self::$store["link"])) {
400 | self::$store["link"] = array();
401 | }
402 |
403 | self::$store["link"][$optionName] = $optionValue;
404 |
405 | }
406 |
407 | /**
408 | * Set the pattern data option
409 | * @param {String} name of the pattern
410 | * @param {String} value for the pattern's data attribute
411 | */
412 | public static function setPatternData($optionName,$optionValue) {
413 |
414 | if (isset(self::$store["patternSpecific"][$optionName])) {
415 | self::$store["patternSpecific"][$optionName]["data"] = $optionValue;
416 | return true;
417 | }
418 |
419 | return false;
420 |
421 | }
422 |
423 | /**
424 | * Set the pattern listitems option
425 | * @param {String} name of the pattern
426 | * @param {String} value for the pattern's listItem attribute
427 | */
428 | public static function setPatternListItems($optionName,$optionValue) {
429 |
430 | if (isset(self::$store["patternSpecific"][$optionName])) {
431 | self::$store["patternSpecific"][$optionName]["listItems"] = $optionValue;
432 | return true;
433 | }
434 |
435 | return false;
436 |
437 | }
438 |
439 | }
440 |
--------------------------------------------------------------------------------
/src/PatternLab/Dispatcher.php:
--------------------------------------------------------------------------------
1 | getListeners();
63 | foreach ($listeners as $event => $eventProps) {
64 | $eventPriority = (isset($eventProps["priority"])) ? $eventProps["priority"] : 0;
65 | self::$instance->addListener($event, array($listener, $eventProps["callable"]), $eventPriority);
66 | }
67 | }
68 |
69 | }
70 |
71 | }
72 |
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/PatternLab/Fetch.php:
--------------------------------------------------------------------------------
1 | getPackageInfo($starterkit);
42 |
43 | // set default attributes
44 | $sourceDir = Config::getOption("sourceDir");
45 | $tempDir = sys_get_temp_dir().DIRECTORY_SEPARATOR."pl-sk";
46 | $tempDirSK = $tempDir.DIRECTORY_SEPARATOR."pl-sk-archive";
47 | $tempDirDist = $tempDirSK.DIRECTORY_SEPARATOR.$repo."-".$tag.DIRECTORY_SEPARATOR."dist";
48 | $tempComposerFile = $tempDirSK.DIRECTORY_SEPARATOR.$repo."-".$tag.DIRECTORY_SEPARATOR."composer.json";
49 |
50 | //get the path to the GH repo and validate it
51 | $tarballUrl = "https://github.com/".$org."/".$repo."/archive/".$tag.".tar.gz";
52 |
53 | Console::writeInfo("downloading the starterkit. this may take a few minutes...");
54 |
55 | // try to download the given package
56 | if (!$package = @file_get_contents($tarballUrl)) {
57 | $error = error_get_last();
58 | Console::writeError("the starterkit wasn't downloaded because:\n\n ".$error["message"]);
59 | }
60 |
61 | // Create temp directory if doesn't exist
62 | $fs = new Filesystem();
63 | try {
64 | $fs->mkdir($tempDir, 0775);
65 | } catch (IOExceptionInterface $e) {
66 | Console::writeError("Error creating temporary directory at " . $e->getPath());
67 | }
68 |
69 | // write the package to the temp directory
70 | $tempFile = tempnam($tempDir, "pl-sk-archive.tar.gz");
71 | file_put_contents($tempFile, $package);
72 |
73 | Console::writeInfo("finished downloading the starterkit...");
74 |
75 | // make sure the temp dir exists before copying into it
76 | if (!is_dir($tempDirSK)) {
77 | mkdir($tempDirSK);
78 | }
79 |
80 | // extract, if the zip is supposed to be unpacked do that (e.g. stripdir)
81 | try {
82 | $zippy = Zippy::load();
83 | $zippy->addStrategy(new UnpackFileStrategy());
84 | $zippy->getAdapterFor('tar.gz')->open($tempFile)->extract($tempDirSK);
85 | } catch(\RuntimeException $e) {
86 | Console::writeError("failed to extract the starterkit. easiest solution is to manually download it and copy ./dist./source/...");
87 | }
88 |
89 | if (!is_dir($tempDirDist)) {
90 | // try without repo dir
91 | $tempDirDist = $tempDirSK.DIRECTORY_SEPARATOR."dist";
92 | }
93 | // thrown an error if temp/dist/ doesn't exist
94 | if (!is_dir($tempDirDist)) {
95 | Console::writeError("the starterkit needs to contain a dist/ directory before it can be installed...");
96 | }
97 |
98 | // check for composer.json. if it exists use it for determining things. otherwise just mirror dist/ to source/
99 | if (file_exists($tempComposerFile)) {
100 |
101 | $tempComposerJSON = json_decode(file_get_contents($tempComposerFile), true);
102 |
103 | // see if it has a patternlab section that might define the files to move
104 | if (isset($tempComposerJSON["extra"]) && isset($tempComposerJSON["extra"]["patternlab"])) {
105 | Console::writeInfo("installing the starterkit...");
106 | InstallerUtil::parseComposerExtraList($tempComposerJSON["extra"]["patternlab"], $starterkit, $tempDirDist);
107 | Console::writeInfo("installed the starterkit...");
108 | } else {
109 | $this->mirrorDist($sourceDir, $tempDirDist);
110 | }
111 |
112 | } else {
113 |
114 | $this->mirrorDist($sourceDir, $tempDirDist);
115 |
116 | }
117 |
118 | // remove the temp files
119 | Console::writeInfo("cleaning up the temp files...");
120 | $fs = new Filesystem();
121 | $fs->remove($tempFile);
122 | $fs->remove($tempDirSK);
123 |
124 | Console::writeInfo("the starterkit installation is complete...");
125 |
126 | return true;
127 |
128 | }
129 |
130 | /**
131 | * Break up the package path
132 | * @param {String} path of the GitHub repo
133 | *
134 | * @return {Array} the parts of the package path
135 | */
136 | protected function getPackageInfo($package) {
137 |
138 | $org = "";
139 | $repo = "";
140 | $tag = "master";
141 |
142 | if (strpos($package, "#") !== false) {
143 | list($package,$tag) = explode("#",$package);
144 | }
145 |
146 | if (strpos($package, "/") !== false) {
147 | list($org,$repo) = explode("/",$package);
148 | } else {
149 | Console::writeError("please provide a real path to a package...");
150 | }
151 |
152 | return array($org,$repo,$tag);
153 |
154 | }
155 |
156 | /**
157 | * Force mirror the dist/ folder to source/
158 | * @param {String} path to the source directory
159 | * @param {String} path to the temp dist directory
160 | */
161 | protected function mirrorDist($sourceDir, $tempDirDist) {
162 |
163 | // set default vars
164 | $fsOptions = array();
165 | $emptyDir = true;
166 | $validFiles = array("README",".gitkeep",".DS_Store","styleguide","patternlab-components");
167 |
168 | // see if the source directory is empty
169 | if (is_dir($sourceDir)) {
170 | $objects = new \DirectoryIterator($sourceDir);
171 | foreach ($objects as $object) {
172 | if (!$object->isDot() && !in_array($object->getFilename(),$validFiles)) {
173 | $emptyDir = false;
174 | break;
175 | }
176 | }
177 | }
178 |
179 | // if source directory isn't empty ask if it's ok to nuke what's there
180 | if (!$emptyDir) {
181 |
182 | $prompt = "a starterkit is already installed. merge the new files with it or replace it?";
183 | $options = "M/r";
184 | $input = Console::promptInput($prompt,$options,"M");
185 | $fsOptions = ($input == "r") ? array("delete" => true, "override" => true) : array("delete" => false, "override" => false);
186 |
187 | }
188 |
189 | // mirror dist to source
190 | Console::writeInfo("installing the starterkit files...");
191 | $fs = new Filesystem();
192 | $fs->mirror($tempDirDist, $sourceDir, null, $fsOptions);
193 | Console::writeInfo("starterkit files have been installed...");
194 |
195 | }
196 |
197 | }
198 |
--------------------------------------------------------------------------------
/src/PatternLab/FileUtil.php:
--------------------------------------------------------------------------------
1 | ".Console::getHumanReadablePath($configPath)." by adding '".$configOption."=some/path'. sorry, stopping pattern lab... :(");
34 | } else if (!is_dir($path)) {
35 | Console::writeWarning("i can't seem to find the directory ".Console::getHumanReadablePath($path)."...");
36 | self::makeDir($path);
37 | Console::writeWarning("i created ".Console::getHumanReadablePath($path)." just in case. you can edit this in ".Console::getHumanReadablePath($configPath)." by editing ".$configOption."...");
38 | }
39 |
40 | }
41 |
42 | /**
43 | * Make a directory
44 | * @param {String} directory to be made
45 | */
46 | public static function makeDir($dir) {
47 | $fs = new Filesystem();
48 | try {
49 | $fs->mkdir($dir);
50 | } catch (IOExceptionInterface $e) {
51 | Console::writeError("an error occurred while creating your directory at ".$e->getPath()."...");
52 | }
53 | unset($fs);
54 | }
55 |
56 | /**
57 | * Copies a file from the given source path to the given public path.
58 | * THIS IS NOT FOR PATTERNS
59 | * @param {String} the source file
60 | * @param {String} the public file
61 | */
62 | protected static function moveFile($s,$p) {
63 |
64 | // default vars
65 | $sourceDir = Config::getOption("sourceDir");
66 | $publicDir = Config::getOption("publicDir");
67 |
68 | $fs = new Filesystem();
69 | $fs->copy($sourceDir.DIRECTORY_SEPARATOR.$s,$publicDir.DIRECTORY_SEPARATOR.$p);
70 |
71 | }
72 |
73 | /**
74 | * Moves static files that aren't directly related to Pattern Lab
75 | * @param {String} file name to be moved
76 | * @param {String} copy for the message to be printed out
77 | * @param {String} part of the file name to be found for replacement
78 | * @param {String} the replacement
79 | */
80 | public static function moveStaticFile($fileName,$copy = "", $find = "", $replace = "") {
81 | self::moveFile($fileName,str_replace($find, $replace, $fileName));
82 | Util::updateChangeTime();
83 | if ($copy != "") {
84 | Console::writeInfo($fileName." ".$copy."...");
85 | }
86 | }
87 |
88 | /**
89 | * Check to see if a given filename is in a directory that should be ignored
90 | * @param {String} file name to be checked
91 | *
92 | * @return {Boolean} whether the directory should be ignored
93 | */
94 | public static function ignoreDir($fileName) {
95 | $id = Config::getOption("id");
96 | foreach ($id as $dir) {
97 | $pos = strpos(DIRECTORY_SEPARATOR.$fileName,DIRECTORY_SEPARATOR.$dir.DIRECTORY_SEPARATOR);
98 | if ($pos !== false) {
99 | return true;
100 | }
101 | }
102 | return false;
103 | }
104 |
105 | /**
106 | * Taken from Composer: https://github.com/composer/composer/blob/master/src/Composer/Util/Filesystem.php
107 | *
108 | * Normalize a path. This replaces backslashes with slashes, removes ending
109 | * slash and collapses redundant separators and up-level references.
110 | *
111 | * @param string $path Path to the file or directory
112 | * @return string
113 | */
114 | public static function normalizePath($path) {
115 | $parts = array();
116 | $path = strtr($path, '\\', '/');
117 | $prefix = '';
118 | $absolute = false;
119 |
120 | if (preg_match('{^([0-9a-z]+:(?://(?:[a-z]:)?)?)}i', $path, $match)) {
121 | $prefix = $match[1];
122 | $path = substr($path, strlen($prefix));
123 | }
124 |
125 | if (substr($path, 0, 1) === '/') {
126 | $absolute = true;
127 | $path = substr($path, 1);
128 | }
129 |
130 | $up = false;
131 | foreach (explode('/', $path) as $chunk) {
132 | if ('..' === $chunk && ($absolute || $up)) {
133 | array_pop($parts);
134 | $up = !(empty($parts) || '..' === end($parts));
135 | } elseif ('.' !== $chunk && '' !== $chunk) {
136 | $parts[] = $chunk;
137 | $up = '..' !== $chunk;
138 | }
139 | }
140 |
141 | return $prefix.($absolute ? '/' : '').implode('/', $parts);
142 |
143 | }
144 |
145 | /**
146 | * Delete everything in export/
147 | */
148 | public static function cleanExport() {
149 |
150 | // default var
151 | $exportDir = Config::getOption("exportDir");
152 |
153 | if (is_dir($exportDir)) {
154 |
155 | $files = scandir($exportDir);
156 | foreach ($files as $file) {
157 | if (($file == "..") || ($file == ".")) {
158 | array_shift($files);
159 | } else {
160 | $key = array_keys($files,$file);
161 | $files[$key[0]] = $exportDir.DIRECTORY_SEPARATOR.$file;
162 | }
163 | }
164 |
165 | $fs = new Filesystem();
166 | $fs->remove($files);
167 |
168 | }
169 |
170 | }
171 |
172 | /**
173 | * Delete patterns and user-created directories and files in public/
174 | */
175 | public static function cleanPublic() {
176 |
177 | // set-up the dispatcher
178 | $dispatcherInstance = Dispatcher::getInstance();
179 |
180 | // dispatch that the data gather has started
181 | $dispatcherInstance->dispatch("fileUtil.cleanPublicStart");
182 |
183 | // default var
184 | $patternPublicDir = Config::getOption("patternPublicDir");
185 |
186 | // make sure patterns exists before trying to clean it
187 | if (is_dir($patternPublicDir)) {
188 |
189 | // symfony finder doesn't support child first and I don't want to do array crap
190 | $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($patternPublicDir), \RecursiveIteratorIterator::CHILD_FIRST);
191 |
192 | // make sure dots are skipped
193 | $objects->setFlags(\FilesystemIterator::SKIP_DOTS);
194 |
195 | // for each file figure out what to do with it
196 | foreach ($objects as $name => $object) {
197 |
198 | if ($object->isDir()) {
199 | // if this is a directory remove it
200 | rmdir($name);
201 | } else if ($object->isFile() && ($object->getFilename() != "README")) {
202 | // if this is a file remove it
203 | unlink($name);
204 | }
205 |
206 | }
207 |
208 | }
209 |
210 | // scan source/ & public/ to figure out what directories might need to be cleaned up
211 | $publicDir = Config::getOption("publicDir");
212 | $sourceDir = Config::getOption("sourceDir");
213 | $publicDirs = glob($publicDir.DIRECTORY_SEPARATOR."*",GLOB_ONLYDIR);
214 | $sourceDirs = glob($sourceDir.DIRECTORY_SEPARATOR."*",GLOB_ONLYDIR);
215 |
216 | // make sure some directories aren't deleted
217 | $ignoreDirs = array("styleguide","patternlab-components");
218 | foreach ($ignoreDirs as $ignoreDir) {
219 | $key = array_search($publicDir.DIRECTORY_SEPARATOR.$ignoreDir,$publicDirs);
220 | if ($key !== false){
221 | unset($publicDirs[$key]);
222 | }
223 | }
224 |
225 | // compare source dirs against public. remove those dirs w/ an underscore in source/ from the public/ list
226 | foreach ($sourceDirs as $dir) {
227 | $cleanDir = str_replace($sourceDir.DIRECTORY_SEPARATOR,"",$dir);
228 | if ($cleanDir[0] == "_") {
229 | $key = array_search($publicDir.DIRECTORY_SEPARATOR.str_replace("_","",$cleanDir),$publicDirs);
230 | if ($key !== false){
231 | unset($publicDirs[$key]);
232 | }
233 | }
234 | }
235 |
236 | // for the remaining dirs in public delete them and their files
237 | foreach ($publicDirs as $dir) {
238 |
239 | // symfony finder doesn't support child first and I don't want to do array crap
240 | $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir), \RecursiveIteratorIterator::CHILD_FIRST);
241 |
242 | // make sure dots are skipped
243 | $objects->setFlags(\FilesystemIterator::SKIP_DOTS);
244 |
245 | foreach($objects as $name => $object) {
246 |
247 | if ($object->isDir()) {
248 | rmdir($name);
249 | } else if ($object->isFile()) {
250 | unlink($name);
251 | }
252 |
253 | }
254 |
255 | rmdir($dir);
256 |
257 | }
258 |
259 | $dispatcherInstance->dispatch("fileUtil.cleanPublicEnd");
260 |
261 | }
262 |
263 | /**
264 | * moves user-generated static files from public/ to export/
265 | */
266 | public static function exportStatic() {
267 |
268 | // default vars
269 | $exportDir = Config::getOption("exportDir");
270 | $publicDir = Config::getOption("publicDir");
271 | $sourceDir = Config::getOption("sourceDir");
272 |
273 | if (!is_dir($exportDir)) {
274 | mkdir($exportDir);
275 | }
276 |
277 | if (is_dir($publicDir)) {
278 |
279 | // decide which files in public should def. be ignored
280 | $ignore = array("annotations","data","patterns","styleguide","index.html","latest-change.txt",".DS_Store",".svn","README");
281 |
282 | $files = scandir($publicDir);
283 | foreach ($files as $key => $file) {
284 | if (($file == "..") || ($file == ".")) {
285 | unset($files[$key]);
286 | } else if (in_array($file,$ignore)) {
287 | unset($files[$key]);
288 | } else if (is_dir($publicDir.DIRECTORY_SEPARATOR.$file) && !is_dir($sourceDir.DIRECTORY_SEPARATOR.$file)) {
289 | unset($files[$key]);
290 | } else if (is_file($publicDir.DIRECTORY_SEPARATOR.$file) && !is_file($sourceDir.DIRECTORY_SEPARATOR.$file)) {
291 | unset($files[$key]);
292 | }
293 | }
294 |
295 | $fs = new Filesystem();
296 | foreach ($files as $file) {
297 | if (is_dir($publicDir.DIRECTORY_SEPARATOR.$file)) {
298 | $fs->mirror($publicDir.DIRECTORY_SEPARATOR.$file,$exportDir.DIRECTORY_SEPARATOR.$file);
299 | } else if (is_file($publicDir.DIRECTORY_SEPARATOR.$file)) {
300 | $fs->copy($publicDir.DIRECTORY_SEPARATOR.$file,$exportDir.DIRECTORY_SEPARATOR.$file);
301 | }
302 | }
303 |
304 | }
305 |
306 | }
307 |
308 | }
309 |
--------------------------------------------------------------------------------
/src/PatternLab/Generator.php:
--------------------------------------------------------------------------------
1 | generateIndex();
81 | $this->generateStyleguide();
82 | $this->generateViewAllPages();
83 |
84 | // render out the patterns and move them to public/patterns
85 | $options = array();
86 | $options["exportFiles"] = $exportFiles;
87 | $this->generatePatterns($options);
88 |
89 | // render the annotations as a js file
90 | $this->generateAnnotations();
91 |
92 | // move all of the files unless pattern only is set
93 | if ($moveStatic) {
94 | $this->moveStatic();
95 | }
96 |
97 | // update the change time so the auto-reload will fire (doesn't work for the index and style guide)
98 | Util::updateChangeTime();
99 |
100 | if ($watchVerbose && $watchMessage) {
101 | Console::writeLine($watchMessage);
102 | } else {
103 | Console::writeLine("your site has been generated...");
104 | Timer::stop();
105 | }
106 |
107 | }
108 |
109 | /**
110 | * Move static files from source/ to public/
111 | */
112 | protected function moveStatic() {
113 |
114 | // set-up the dispatcher
115 | $dispatcherInstance = Dispatcher::getInstance();
116 |
117 | // note the start of the operation
118 | $dispatcherInstance->dispatch("generator.moveStaticStart");
119 |
120 | // common values
121 | $publicDir = Config::getOption("publicDir");
122 | $sourceDir = Config::getOption("sourceDir");
123 | $ignoreExt = Config::getOption("ie");
124 | $ignoreDir = Config::getOption("id");
125 |
126 | // iterate over all of the other files in the source directory
127 | $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($sourceDir), \RecursiveIteratorIterator::SELF_FIRST);
128 |
129 | // make sure dots are skipped
130 | $objects->setFlags(\FilesystemIterator::SKIP_DOTS);
131 |
132 | foreach($objects as $name => $object) {
133 |
134 | // clean-up the file name and make sure it's not one of the pattern lab files or to be ignored
135 | $fileName = str_replace($sourceDir.DIRECTORY_SEPARATOR,"",$name);
136 |
137 | if (($fileName[0] != "_") && (!in_array($object->getExtension(),$ignoreExt)) && (!in_array($object->getFilename(),$ignoreDir))) {
138 |
139 | // catch directories that have the ignored dir in their path
140 | $ignored = FileUtil::ignoreDir($fileName);
141 |
142 | // check to see if it's a new directory
143 | if (!$ignored && $object->isDir() && !is_dir($publicDir."/".$fileName)) {
144 | mkdir($publicDir."/".$fileName);
145 | }
146 |
147 | // check to see if it's a new file or a file that has changed
148 | if (!$ignored && $object->isFile() && (!file_exists($publicDir."/".$fileName))) {
149 | FileUtil::moveStaticFile($fileName);
150 | }
151 |
152 | }
153 |
154 | }
155 |
156 | // note the end of the operation
157 | $dispatcherInstance->dispatch("generator.moveStaticEnd");
158 |
159 | }
160 |
161 | }
162 |
--------------------------------------------------------------------------------
/src/PatternLab/JSON.php:
--------------------------------------------------------------------------------
1 | false,
23 | JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
24 | JSON_ERROR_STATE_MISMATCH => 'Underflow or the modes mismatch',
25 | JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
26 | JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON',
27 | JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded'
28 | );
29 |
30 | /**
31 | * Returns the last error message when building a JSON file. Mimics json_last_error_msg() from PHP 5.5
32 | * @param {String} the file that generated the error
33 | */
34 | public static function hasError() {
35 | $error = json_last_error();
36 | $errorMessage = array_key_exists($error, self::$errors) ? self::$errors[$error] : "Unknown error ({$error})";
37 | return $errorMessage;
38 | }
39 |
40 | /**
41 | * Returns the last error message when building a JSON file. Mimics json_last_error_msg() from PHP 5.5
42 | * @param {String} the file that generated the error
43 | */
44 | public static function lastErrorMsg($file,$message,$data) {
45 | Console::writeLine(PHP_EOL."The JSON file, ".$file.", wasn't loaded. The error: ".$message."");
46 | if ($message == "Syntax error, malformed JSON") {
47 | Console::writeLine("");
48 | $parser = new JsonLint\JsonParser();
49 | $error = $parser->lint($data);
50 | Console::writeError($error->getMessage(), false, true);
51 | }
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/src/PatternLab/Listener.php:
--------------------------------------------------------------------------------
1 | listeners[$eventName] = array("callable" => $callable, "priority" => $priority);
31 |
32 | }
33 |
34 | /**
35 | * Get the list of listeners
36 | */
37 | public function getListeners() {
38 | return $this->listeners;
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/PatternLab/Migrator.php:
--------------------------------------------------------------------------------
1 | getFilename();
46 | if (!$migration->isDot() && $migration->isFile() && ($filename[0] != "_")) {
47 | $migrationsValid[] = $filename;
48 | }
49 | }
50 |
51 | asort($migrationsValid);
52 |
53 | foreach ($migrationsValid as $filename) {
54 |
55 | $basePath = __DIR__."/../../../";
56 | $migrationData = json_decode(file_get_contents(__DIR__."/../../migrations/".$filename));
57 | $checkType = $migrationData->checkType;
58 | $sourcePath = ($checkType == "fileExists") ? $basePath.$migrationData->sourcePath : $basePath.$migrationData->sourcePath.DIRECTORY_SEPARATOR;
59 | $destinationPath = ($checkType == "fileExists") ? $basePath.$migrationData->destinationPath : $basePath.$migrationData->destinationPath.DIRECTORY_SEPARATOR;
60 |
61 | if ($checkType == "dirEmpty") {
62 |
63 | $emptyDir = true;
64 | $objects = new \DirectoryIterator($destinationPath);
65 | foreach ($objects as $object) {
66 | if (!$object->isDot() && ($object->getFilename() != "README") && ($object->getFilename() != ".DS_Store")) {
67 | $emptyDir = false;
68 | }
69 | }
70 |
71 | if ($emptyDir) {
72 | $this->runMigration($filename, $sourcePath, $destinationPath, false);
73 | }
74 |
75 | } else if ($checkType == "dirExists") {
76 |
77 | if (!is_dir($destinationPath)) {
78 | mkdir($destinationPath);
79 | }
80 |
81 | } else if ($checkType == "fileExists") {
82 |
83 | if (!file_exists($destinationPath)) {
84 | $this->runMigration($filename, $sourcePath, $destinationPath, true);
85 | }
86 |
87 | } else if (($checkType == "versionDiffDir") && $diffVersion) {
88 |
89 | // make sure the destination path exists
90 | if (!is_dir($destinationPath)) {
91 | mkdir($destinationPath);
92 | }
93 |
94 | $this->runMigration($filename, $sourcePath, $destinationPath, false);
95 |
96 | } else if (($checkType == "versionDiffFile") && $diffVersion) {
97 |
98 | $this->runMigration($filename, $sourcePath, $destinationPath, true);
99 |
100 | } else {
101 |
102 | print "pattern Lab doesn't recognize a checkType of ".$checkType.". The migrator class is pretty thin at the moment.\n";
103 | exit;
104 |
105 | }
106 |
107 | }
108 |
109 | }
110 |
111 | /**
112 | * Run any migrations found in core/migrations that match the approved types
113 | * @param {String} the filename of the migration
114 | * @param {String} the path of the source directory
115 | * @param {String} the path to the destination
116 | * @param {Boolean} moving a single file or a directory
117 | */
118 | protected function runMigration($filename, $sourcePath, $destinationPath, $singleFile) {
119 |
120 | $filename = str_replace(".json","",$filename);
121 | print "starting the ".$filename." migration...\n";
122 |
123 | if ($singleFile) {
124 |
125 | copy($sourcePath.$fileName,$destinationPath.$fileName);
126 |
127 | } else {
128 |
129 | if (strpos($sourcePath,"pattern-lab/") !== false) {
130 |
131 | $sourcePath = str_replace(__DIR__."/../../../","",rtrim($sourcePath,"/"));
132 | $f = new Fetch();
133 | $f->fetch("starterkit",$sourcePath);
134 |
135 | } else {
136 |
137 | $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($sourcePath), \RecursiveIteratorIterator::SELF_FIRST);
138 | $objects->setFlags(\FilesystemIterator::SKIP_DOTS);
139 |
140 | foreach ($objects as $object) {
141 |
142 | // clean-up the file name and make sure it's not one of the pattern lab files or to be ignored
143 | $fileName = str_replace($sourcePath,"",$object->getPathname());
144 |
145 | // check to see if it's a new directory
146 | if ($object->isDir() && !is_dir($destinationPath.$fileName)) {
147 | mkdir($destinationPath.$fileName);
148 | } else if ($object->isFile()) {
149 | copy($sourcePath.$fileName,$destinationPath.$fileName);
150 | }
151 |
152 | }
153 | }
154 |
155 | }
156 |
157 | print "completed the ".$filename." migration...\n";
158 |
159 | }
160 |
161 | }
162 |
--------------------------------------------------------------------------------
/src/PatternLab/Parsers/Documentation.php:
--------------------------------------------------------------------------------
1 | getMessage());
47 | }
48 |
49 | // single line of text won't throw a YAML error. returns as string
50 | if (gettype($yaml) == "string") {
51 | $yaml = array();
52 | }
53 |
54 | return $yaml;
55 |
56 | }
57 |
58 | /**
59 | * Return only the relevant YAML from the given text
60 | * @param {String} the text to be parsed
61 | *
62 | * @return {Array} the parsed content
63 | */
64 | public static function getYAML($text) {
65 | list($yaml,$markdown) = self::parse($text);
66 | return $yaml;
67 | }
68 |
69 | /**
70 | * Return only the relevant converted markdown from the given text
71 | * @param {String} the text to be parsed
72 | *
73 | * @return {Array} the parsed content
74 | */
75 | public static function getMarkdown($text) {
76 | list($yaml,$markdown) = self::parse($text);
77 | return $markdown;
78 | }
79 |
80 | /**
81 | * Find and convert YAML and markdown in Pattern Lab documention files
82 | * @param {String} the text to be chunked for YAML and markdown
83 | *
84 | * @return {Array} array containing both the YAML and converted markdown
85 | */
86 | public static function parse($text) {
87 |
88 | self::setLineEndings();
89 |
90 | // set-up defaults
91 | $yaml = array();
92 | $markdown = "";
93 |
94 | // read in the content
95 | // based on: https://github.com/mnapoli/FrontYAML/blob/master/src/Parser.php
96 | $lines = explode(PHP_EOL, $text);
97 |
98 | if (count($lines) <= 1) {
99 | $markdown = self::convertMarkdown($text);
100 | return array($yaml,$markdown);
101 | }
102 |
103 | if (rtrim($lines[0]) !== '---') {
104 | $markdown = self::convertMarkdown($text);
105 | return array($yaml,$markdown);
106 | }
107 |
108 | $head = array();
109 | unset($lines[0]);
110 | $i = 1;
111 | foreach ($lines as $line) {
112 | if ($line === '---') {
113 | break;
114 | }
115 | $head[] = $line;
116 | $i++;
117 | }
118 |
119 | $head = implode(PHP_EOL, $head);
120 | $body = implode(PHP_EOL, array_slice($lines, $i));
121 |
122 | $yaml = self::convertYAML($head);
123 | $markdown = self::convertMarkdown($body);
124 |
125 | return array($yaml,$markdown);
126 |
127 | }
128 |
129 | /**
130 | * Set the proper line endings so the text can be parsed properly
131 | */
132 | protected static function setLineEndings() {
133 | if (!self::$lineEndingsSet) {
134 | ini_set("auto_detect_line_endings", true);
135 | self::$lineEndingsSet = true;
136 | }
137 | }
138 |
139 | }
140 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Event.php:
--------------------------------------------------------------------------------
1 | options = $options;
24 | }
25 |
26 | public function getOptions() {
27 | return $this->options;
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Exporter.php:
--------------------------------------------------------------------------------
1 | store = PatternData::get();
28 |
29 | }
30 |
31 | public function run() {
32 |
33 | foreach ($this->store as $patternStoreKey => $patternStoreData) {
34 |
35 | switch ($patternStoreData["category"]) {
36 | // atoms - view all
37 | case "patternType":
38 | if (isset($patternStoreData["pathDash"])) {
39 | $value = "../../patterns/" . $patternStoreData["pathDash"] . "/index.html";
40 | Data::setOptionLink("viewall-" . $patternStoreData["nameDash"] . "-all", $value);
41 | }
42 | break;
43 |
44 | // atoms/forms - view all
45 | case "patternSubtype":
46 | if (isset($patternStoreData["pathDash"])) {
47 | $value = "../../patterns/" . $patternStoreData["pathDash"] . "/index.html";
48 | Data::setOptionLink($patternStoreData["partial"], $value);
49 | }
50 | break;
51 |
52 | // atoms/forms/select.mustache
53 | case "pattern":
54 | if (isset($patternStoreData["pathDash"])) {
55 | $value = "../../patterns/" . $patternStoreData["pathDash"] . "/" . $patternStoreData["pathDash"] . ".html";
56 | Data::setOptionLink($patternStoreKey, $value);
57 | }
58 | break;
59 | }
60 |
61 | }
62 |
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Exporters/DataMergeExporter.php:
--------------------------------------------------------------------------------
1 | store = PatternData::get();
29 |
30 | }
31 |
32 | public function run() {
33 |
34 | foreach ($this->store as $patternStoreKey => $patternStoreData) {
35 |
36 | if ($patternStoreData["category"] == "pattern") {
37 |
38 | if (isset($patternStoreData["data"]) || isset($patternStoreData["listItems"])) {
39 | Data::initPattern($patternStoreKey);
40 | }
41 |
42 | if (isset($patternStoreData["data"])) {
43 | Data::setPatternData($patternStoreKey, $patternStoreData["data"]);
44 | }
45 |
46 | if (isset($patternStoreData["listItems"])) {
47 | Data::setPatternListItems($patternStoreKey, $patternStoreData["listItems"]);
48 | }
49 |
50 | }
51 |
52 | }
53 |
54 | // walk across the data and change link.pattern-partial to real source
55 | Data::compareReplaceListVarsInit();
56 |
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Exporters/NavItemsExporter.php:
--------------------------------------------------------------------------------
1 | store = PatternData::get();
29 | $this->styleGuideExcludes = Config::getOption("styleGuideExcludes");
30 |
31 | }
32 |
33 | public function run() {
34 |
35 | $bi = 0;
36 | $ni = 0;
37 | $patternSubtypeSet = false;
38 | $patternType = "";
39 | $patternTypeDash = "";
40 | $suffixRendered = Config::getOption("outputFileSuffixes.rendered");
41 |
42 | $navItems = array();
43 | $navItems["patternTypes"] = array();
44 |
45 | // iterate over the different categories and add them to the navigation
46 | foreach ($this->store as $patternStoreKey => $patternStoreData) {
47 |
48 | if ($patternStoreData["category"] == "patternType") {
49 |
50 | $bi = (count($navItems["patternTypes"]) == 0) ? 0 : $bi + 1;
51 |
52 | // add a new patternType to the nav
53 | $navItems["patternTypes"][$bi] = array("patternTypeLC" => strtolower($patternStoreData["nameClean"]),
54 | "patternTypeUC" => ucwords($patternStoreData["nameClean"]),
55 | "patternType" => $patternStoreData["name"],
56 | "patternTypeDash" => $patternStoreData["nameDash"],
57 | "patternTypeItems" => array(),
58 | "patternItems" => array());
59 |
60 | // starting a new set of pattern types. it might not have any pattern subtypes
61 | $patternSubtypeSet = false;
62 | $patternType = $patternStoreData["name"];
63 | $patternTypeDash = $patternStoreData["nameDash"];
64 |
65 | } else if ($patternStoreData["category"] == "patternSubtype") {
66 |
67 | $ni = (!$patternSubtypeSet) ? 0 : $ni + 1;
68 |
69 | // add a new patternSubtype to the nav
70 | $navItems["patternTypes"][$bi]["patternTypeItems"][$ni] = array("patternSubtypeLC" => strtolower($patternStoreData["nameClean"]),
71 | "patternSubtypeUC" => ucwords($patternStoreData["nameClean"]),
72 | "patternSubtype" => $patternStoreData["name"],
73 | "patternSubtypeDash" => $patternStoreData["nameDash"],
74 | "patternSubtypeItems" => array());
75 |
76 | // starting a new set of pattern types. it might not have any pattern subtypes
77 | $patternSubtype = $patternStoreData["name"];
78 | $patternSubtypeDash = $patternStoreData["nameDash"];
79 | $patternSubtypeSet = true;
80 |
81 | } else if ($patternStoreData["category"] == "pattern") {
82 |
83 | if (isset($patternStoreData["hidden"]) && !$patternStoreData["hidden"]) {
84 |
85 | // set-up the info for the nav
86 | $patternInfo = array("patternPath" => $patternStoreData["pathDash"]."/".$patternStoreData["pathDash"].$suffixRendered.".html",
87 | "patternSrcPath" => $patternStoreData["pathName"],
88 | "patternName" => ucwords($patternStoreData["nameClean"]),
89 | "patternState" => $patternStoreData["state"],
90 | "patternPartial" => $patternStoreData["partial"]);
91 |
92 | // add to the nav
93 | if ($patternStoreData["depth"] == 1) {
94 | $navItems["patternTypes"][$bi]["patternItems"][] = $patternInfo;
95 | } else {
96 | $navItems["patternTypes"][$bi]["patternTypeItems"][$ni]["patternSubtypeItems"][] = $patternInfo;
97 | }
98 |
99 | }
100 |
101 | }
102 |
103 | }
104 |
105 | // review each subtype. add a view all link or remove the subtype as necessary
106 | foreach ($navItems["patternTypes"] as $patternTypeKey => $patternTypeValues) {
107 |
108 | $reset = false;
109 | $patternType = $patternTypeValues["patternType"];
110 | $patternTypeDash = $patternTypeValues["patternTypeDash"];
111 |
112 | if (!in_array($patternType,$this->styleGuideExcludes)) {
113 |
114 | foreach ($patternTypeValues["patternTypeItems"] as $patternSubtypeKey => $patternSubtypeValues) {
115 |
116 | // if there are no sub-items in a section remove it
117 | if (empty($patternSubtypeValues["patternSubtypeItems"])) {
118 |
119 | unset($navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]);
120 | $reset = true;
121 |
122 | } else {
123 |
124 | $patternSubtype = $patternSubtypeValues["patternSubtype"];
125 | $patternSubtypeDash = $patternSubtypeValues["patternSubtypeDash"];
126 | $subItemsCount = count($patternSubtypeValues["patternSubtypeItems"]);
127 |
128 | // add a view all link
129 | $navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"][$subItemsCount] = array(
130 | "patternPath" => $patternType."-".$patternSubtype."/index.html",
131 | "patternName" => "View All",
132 | "patternType" => $patternType,
133 | "patternSubtype" => $patternSubtype,
134 | "patternPartial" => "viewall-".$patternTypeDash."-".$patternSubtypeDash);
135 |
136 | }
137 |
138 | }
139 |
140 | }
141 |
142 | if ($reset) {
143 | $navItems["patternTypes"][$patternTypeKey]["patternTypeItems"] = array_values($navItems["patternTypes"][$patternTypeKey]["patternTypeItems"]);
144 | $reset = false;
145 | }
146 |
147 | // add an overall view all link to the menus with sub-menus
148 | if (!empty($navItems["patternTypes"][$patternTypeKey]["patternTypeItems"])) {
149 |
150 | $navItems["patternTypes"][$patternTypeKey]["patternItems"][] = array("patternPath" => $patternType."/index.html",
151 | "patternName" => "View All",
152 | "patternType" => $patternType,
153 | "patternSubtype" => "all",
154 | "patternPartial" => "viewall-".$patternTypeDash."-all");
155 |
156 | }
157 |
158 | }
159 |
160 | return $navItems;
161 |
162 | }
163 |
164 | }
165 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Exporters/PatternPartialsExporter.php:
--------------------------------------------------------------------------------
1 | store = PatternData::get();
30 | $this->cacheBuster = Data::getOption("cacheBuster");
31 | $this->styleGuideExcludes = Config::getOption("styleGuideExcludes");
32 |
33 | }
34 |
35 | /**
36 | * Compare the search and ignore props against the name.
37 | * Can use && or || in the comparison
38 | * @param {String} the type of the pattern that should be used in the view all
39 | * @param {String} the subtype of the pattern that be used in the view all
40 | *
41 | * @return {Array} the list of partials
42 | */
43 | public function run($type = "", $subtype = "") {
44 |
45 | // default vars
46 | $patternPartials = array();
47 | $suffixRendered = Config::getOption("outputFileSuffixes.rendered");
48 |
49 | foreach ($this->store as $patternStoreKey => $patternStoreData) {
50 |
51 | // Docs for patternTypes (i.e. `atoms.md`), don't have these rules and need them to pass below conditionals
52 | if (
53 | !isset($patternStoreData['depth'])
54 | && !isset($patternStoreData['hidden'])
55 | && !isset($patternStoreData['noviewall'])
56 | ) {
57 | $patternStoreData["hidden"] = false;
58 | $patternStoreData["noviewall"] = false;
59 | $patternStoreData["depth"] = 0;
60 | }
61 | $canShow = isset($patternStoreData["hidden"]) && (!$patternStoreData["hidden"]) && (!$patternStoreData["noviewall"]);
62 |
63 | if (($patternStoreData["category"] == "pattern") && $canShow && ($patternStoreData["depth"] > 1) && (!in_array($patternStoreData["type"],$this->styleGuideExcludes))) {
64 |
65 | if ((($patternStoreData["type"] == $type) && empty($subtype)) || (empty($type) && empty($subtype)) || (($patternStoreData["type"] == $type) && ($patternStoreData["subtype"] == $subtype))) {
66 |
67 | $patternPartialData = array();
68 | $patternPartialData["patternName"] = $patternStoreData["nameClean"];
69 | $patternPartialData["patternLink"] = $patternStoreData["pathDash"]."/".$patternStoreData["pathDash"].$suffixRendered.".html";
70 | $patternPartialData["patternPartial"] = $patternStoreData["partial"];
71 | $patternPartialData["patternPartialCode"] = $patternStoreData["code"];
72 | $patternPartialData["patternState"] = $patternStoreData["state"];
73 |
74 | $patternPartialData["patternLineageExists"] = isset($patternStoreData["lineages"]);
75 | $patternPartialData["patternLineages"] = isset($patternStoreData["lineages"]) ? $patternStoreData["lineages"] : array();
76 | $patternPartialData["patternLineageRExists"] = isset($patternStoreData["lineagesR"]);
77 | $patternPartialData["patternLineagesR"] = isset($patternStoreData["lineagesR"]) ? $patternStoreData["lineagesR"] : array();
78 | $patternPartialData["patternLineageEExists"] = (isset($patternStoreData["lineages"]) || isset($patternStoreData["lineagesR"]));
79 |
80 | $patternPartialData["patternDescExists"] = isset($patternStoreData["desc"]);
81 | $patternPartialData["patternDesc"] = isset($patternStoreData["desc"]) ? $patternStoreData["desc"] : "";
82 |
83 | $patternPartialData["patternDescAdditions"] = isset($patternStoreData["partialViewDescAdditions"]) ? $patternStoreData["partialViewDescAdditions"] : array();
84 | $patternPartialData["patternExampleAdditions"] = isset($patternStoreData["partialViewExampleAdditions"]) ? $patternStoreData["partialViewExampleAdditions"] : array();
85 |
86 | // add the pattern data so it can be exported
87 | $patternData = array();
88 | $patternData["lineage"] = isset($patternStoreData["lineages"]) ? $patternStoreData["lineages"] : array();
89 | $patternData["lineageR"] = isset($patternStoreData["lineagesR"]) ? $patternStoreData["lineagesR"] : array();
90 | $patternData["patternBreadcrumb"] = $patternStoreData["breadcrumb"];
91 | $patternData["patternDesc"] = (isset($patternStoreData["desc"])) ? $patternStoreData["desc"] : "";
92 | $patternData["patternExtension"] = Config::getOption("patternExtension");
93 | $patternData["patternName"] = $patternStoreData["nameClean"];
94 | $patternData["patternPartial"] = $patternStoreData["partial"];
95 | $patternData["patternState"] = $patternStoreData["state"];
96 | $patternPartialData["patternData"] = json_encode($patternData);
97 |
98 | $patternPartials[] = $patternPartialData;
99 |
100 | }
101 |
102 | } else if (($patternStoreData["category"] == "patternSubtype") && (!in_array($patternStoreData["type"],$this->styleGuideExcludes))) {
103 |
104 | if ((($patternStoreData["type"] == $type) && empty($subtype)) || (empty($type) && empty($subtype)) || (($patternStoreData["type"] == $type) && ($patternStoreData["name"] == $subtype))) {
105 |
106 | $patternPartialData = array();
107 | $patternPartialData["patternName"] = $patternStoreData["nameClean"];
108 | $patternPartialData["patternLink"] = $patternStoreData["pathDash"]."/index.html";
109 | $patternPartialData["patternPartial"] = $patternStoreData["partial"];
110 | $patternPartialData["patternSectionSubtype"] = true;
111 | $patternPartialData["patternDesc"] = isset($patternStoreData["desc"]) ? $patternStoreData["desc"] : "";
112 |
113 | $patternPartials[] = $patternPartialData;
114 |
115 | }
116 |
117 | } else if (
118 | ($patternStoreData["category"] == "pattern")
119 | && $canShow
120 | && (isset($patternStoreData["full"])
121 | && ($type === $patternStoreData["full"] || $type === ""))
122 | && ($subtype === "")
123 | ) {
124 | // This is for `patternType` docs. Given this structure:
125 | // - _patterns/
126 | // - atoms/
127 | // - forms/
128 | // - atoms.md
129 | // This will take the contents of `atoms.md` and place at top of "Atoms > View All"
130 |
131 | $patternPartialData = array();
132 | // Getting the name from md's `title: My Name` works here, as does the link, but it doesn't make sense to link to the view you are already on. Plus you can just do the title in the MD doc. Keeping here for now in case it's wanted later.
133 | // $patternPartialData["patternName"] = isset($patternStoreData["nameClean"]) ? $patternStoreData["nameClean"] : '';
134 | // $patternPartialData["patternLink"] = $patternStoreData["full"] . "/index.html";
135 |
136 | $patternPartialData["patternSectionSubtype"] = true;
137 | $patternPartialData["patternDesc"] = isset($patternStoreData["desc"]) ? $patternStoreData["desc"] : "";
138 |
139 | $patternPartials[] = $patternPartialData;
140 | }
141 |
142 | }
143 |
144 | return array("partials" => $patternPartials, "cacheBuster" => $this->cacheBuster);
145 |
146 | }
147 |
148 | }
149 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Exporters/PatternPathDestsExporter.php:
--------------------------------------------------------------------------------
1 | store = PatternData::get();
28 |
29 | }
30 |
31 | public function run() {
32 |
33 | $patternPathDests = array();
34 |
35 | foreach ($this->store as $patternStoreKey => $patternStoreData) {
36 |
37 | if (($patternStoreData["category"] == "pattern") && isset($patternStoreData["hidden"]) && !$patternStoreData["hidden"]) {
38 |
39 | $nameDash = $patternStoreData["nameDash"];
40 | $typeDash = $patternStoreData["typeDash"];
41 |
42 | if (!isset($patternPathDests[$typeDash])) {
43 | $patternPathDests[$typeDash] = array();
44 | }
45 |
46 | $patternPathDests[$typeDash][$nameDash] = $patternStoreData["pathDash"];
47 |
48 | }
49 |
50 | }
51 |
52 | return $patternPathDests;
53 |
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Exporters/PatternPathSrcExporter.php:
--------------------------------------------------------------------------------
1 | store = PatternData::get();
29 |
30 | }
31 |
32 | public function run() {
33 |
34 | $patternPathDests = array();
35 |
36 | foreach ($this->store as $patternStoreKey => $patternStoreData) {
37 |
38 | if (($patternStoreData["category"] == "pattern") && isset($patternStoreData["nameDash"])) {
39 |
40 | $nameDash = $patternStoreData["nameDash"];
41 | $typeDash = $patternStoreData["typeDash"];
42 |
43 | if (!isset($patternPathDests[$typeDash])) {
44 | $patternPathDests[$typeDash] = array();
45 | }
46 |
47 | $patternPathDests[$typeDash][$nameDash] = (isset($patternStoreData["pseudo"])) ? $patternStoreData["pathOrig"] : $patternStoreData["pathName"];
48 |
49 | }
50 |
51 | }
52 |
53 | return $patternPathDests;
54 |
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Exporters/ViewAllPathsExporter.php:
--------------------------------------------------------------------------------
1 | styleGuideExcludes = Config::getOption("styleGuideExcludes");
28 |
29 | }
30 |
31 | public function run($navItems) {
32 |
33 | // default vars
34 | $viewAllPaths = array();
35 |
36 | foreach ($navItems["patternTypes"] as $patternTypeKey => $patternTypeValues) {
37 |
38 | $patternType = $patternTypeValues["patternType"];
39 | $patternTypeDash = $patternTypeValues["patternTypeDash"];
40 |
41 | if (!in_array($patternType,$this->styleGuideExcludes)) {
42 |
43 | foreach ($patternTypeValues["patternTypeItems"] as $patternSubtypeKey => $patternSubtypeValues) {
44 |
45 | $patternSubtype = $patternSubtypeValues["patternSubtype"];
46 | $patternSubtypeDash = $patternSubtypeValues["patternSubtypeDash"];
47 |
48 | if (isset($patternSubtypeValues["patternSubtypeItems"])) {
49 |
50 | foreach ($patternSubtypeValues["patternSubtypeItems"] as $patternSubtypeItemKey => $patternSubtypeItemValues) {
51 |
52 | if (strpos($patternSubtypeItemValues["patternPartial"],"viewall-") !== false) {
53 |
54 | $viewAllPaths[$patternTypeDash][$patternSubtypeDash] = $patternType."-".$patternSubtype;
55 |
56 | }
57 |
58 | }
59 |
60 | }
61 |
62 | if (strpos($patternSubtypeItemValues["patternPartial"],"viewall-") !== false) {
63 |
64 | $viewAllPaths[$patternTypeDash]["all"] = $patternType;
65 |
66 | }
67 |
68 | }
69 |
70 | }
71 |
72 | }
73 |
74 | return $viewAllPaths;
75 |
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Helper.php:
--------------------------------------------------------------------------------
1 | lineageMatch = html_entity_decode(Config::getOption("lineageMatch"),ENT_QUOTES);
30 | $this->lineageMatchKey = Config::getOption("lineageMatchKey");
31 |
32 | }
33 |
34 | public function run() {
35 |
36 | // set-up default vars
37 | $foundLineages = array();
38 | $patternSourceDir = Config::getOption("patternSourceDir");
39 | $patternExtension = Config::getOption("patternExtension");
40 | $suffixRendered = Config::getOption("outputFileSuffixes.rendered");
41 |
42 | // check for the regular lineages in only normal patterns
43 | $store = PatternData::get();
44 | foreach ($store as $patternStoreKey => $patternStoreData) {
45 |
46 | if (($patternStoreData["category"] == "pattern") && (!isset($patternStoreData["pseudo"]))) {
47 |
48 | $patternLineages = array();
49 | $fileData = isset($patternStoreData["patternRaw"]) ? $patternStoreData["patternRaw"] : "";
50 | $foundLineages = $this->findLineages($fileData);
51 |
52 | if (!empty($foundLineages)) {
53 |
54 | foreach ($foundLineages as $lineage) {
55 |
56 | /**
57 | * Fix for Pattern Lab Lineages when using Twig Namespaces.
58 | * Converts the full file path to PL-friendly shorthand so
59 | * they are internally registered.
60 | *
61 | * 1. Only handle instances where we aren't or can't use the
62 | * shorthand PL path reference in templates, specifically
63 | * in Twig / D8 when we need to use Twig namespaces in
64 | * our template paths.
65 | * 2. Strip off the @ sign at the beginning of our $lineage string.
66 | * 3. Break apart the full lineage path based on any slashes that
67 | * may exist.
68 | * 4. Store the length of our broken up path for reference below
69 | * 5. Store the first part of the string up to the first slash "/"
70 | * 6. Now grab the last part of the pattern key, based on the length
71 | * of the path we previously exploded.
72 | * 7. Remove any "_" from pattern Name.
73 | * 8. Remove any potential prefixed numbers or number + dash
74 | * combos on our Pattern Name.
75 | * 9. Strip off the pattern path extension (.twig,
76 | * .mustache, etc) if it exists.
77 | * 10. If the pattern name parsed had an extension,
78 | * re-assign our Pattern Name to that.
79 | * 11. Finally, re-assign $lineage to the default PL pattern key.
80 | */
81 |
82 | if ($lineage[0] == '@') { /* [1] */
83 | $lineage = ltrim($lineage, '@'); /* [2] */
84 | $lineageParts = explode('/', $lineage); /* [3] */
85 | $length = count($lineageParts); /* [4] */
86 | $patternType = $lineageParts[0]; /* [5] */
87 |
88 | $patternName = $lineageParts[$length - 1]; /* [6] */
89 | $patternName = ltrim($patternName, '_'); /* [7] */
90 | $patternName = preg_replace('/^[0-9\-]+/', '',
91 | $patternName); /* [8] */
92 |
93 | $patternNameStripped = explode('.' . $patternExtension, $patternName); /* [9] */
94 |
95 | if (count($patternNameStripped) > 1) { /* [10] */
96 | $patternName = $patternNameStripped[0];
97 | }
98 | $lineage = $patternType . "-" . $patternName; /* [11] */
99 | }
100 |
101 | if (PatternData::getOption($lineage)) {
102 |
103 | $patternLineages[] = array("lineagePattern" => $lineage,
104 | "lineagePath" => "../../patterns/".$patternStoreData["pathDash"]."/".$patternStoreData["pathDash"].$suffixRendered.".html");
105 |
106 | } else {
107 |
108 | if (strpos($lineage, '/') === false) {
109 | $fileName = $patternStoreData["pathName"].".".$patternExtension;
110 | // This doesn't work very consistently. @todo Improve error reporting when trying to include a Twig file that doesn't exist (b/c doing so simply outputs the path to the file you were trying to include, giving no error to user that include path had a typo)
111 | // Console::writeWarning("you may have a typo in ".$fileName.". `".$lineage."` is not a valid pattern...");
112 | }
113 |
114 | }
115 |
116 | }
117 |
118 | // add the lineages to the PatternData::$store
119 | PatternData::setPatternOption($patternStoreKey,"lineages",$patternLineages);
120 |
121 | }
122 |
123 | }
124 |
125 | }
126 |
127 | // handle all of those pseudo patterns
128 | $store = PatternData::get();
129 | foreach ($store as $patternStoreKey => $patternStoreData) {
130 |
131 | if (($patternStoreData["category"] == "pattern") && (isset($patternStoreData["pseudo"]))) {
132 |
133 | // add the lineages to the PatternData::$store
134 | $patternStoreKeyOriginal = $patternStoreData["original"];
135 | PatternData::setPatternOption($patternStoreKey,"lineages",PatternData::getPatternOption($patternStoreKeyOriginal,"lineages"));
136 |
137 | }
138 |
139 | }
140 |
141 | // check for the reverse lineages and skip pseudo patterns
142 | $store = PatternData::get();
143 | foreach ($store as $patternStoreKey => $patternStoreData) {
144 |
145 | if (($patternStoreData["category"] == "pattern") && (!isset($patternStoreData["pseudo"])) && isset($patternStoreData["partial"])) {
146 |
147 | $patternLineagesR = array();
148 |
149 | $storeTake2 = PatternData::get();
150 | foreach ($storeTake2 as $haystackKey => $haystackData) {
151 |
152 | if (($haystackData["category"] == "pattern") && (isset($haystackData["lineages"])) && (!empty($haystackData["lineages"]))) {
153 |
154 | foreach ($haystackData["lineages"] as $haystackLineage) {
155 |
156 | if ($haystackLineage["lineagePattern"] == $patternStoreData["partial"]) {
157 |
158 | $foundAlready = false;
159 | foreach ($patternLineagesR as $patternCheck) {
160 |
161 | if ($patternCheck["lineagePattern"] == $patternStoreData["partial"]) {
162 | $foundAlready = true;
163 | break;
164 | }
165 |
166 | }
167 |
168 | if (!$foundAlready) {
169 |
170 | if (PatternData::getOption($haystackKey)) {
171 |
172 | $path = PatternData::getPatternOption($haystackKey,"pathDash");
173 | $patternLineagesR[] = array("lineagePattern" => $haystackKey,
174 | "lineagePath" => "../../patterns/".$path."/".$path.$suffixRendered.".html");
175 |
176 | }
177 |
178 | }
179 |
180 | }
181 |
182 | }
183 |
184 | }
185 |
186 | }
187 |
188 | PatternData::setPatternOption($patternStoreKey,"lineagesR",$patternLineagesR);
189 |
190 | }
191 |
192 | }
193 |
194 | // handle all of those pseudo patterns
195 | $store = PatternData::get();
196 | foreach ($store as $patternStoreKey => $patternStoreData) {
197 |
198 | if (($patternStoreData["category"] == "pattern") && (isset($patternStoreData["pseudo"]))) {
199 |
200 | // add the lineages to the PatternData::$store
201 | $patternStoreKeyOriginal = $patternStoreData["original"];
202 | PatternData::setPatternOption($patternStoreKey,"lineagesR",PatternData::getPatternOption($patternStoreKeyOriginal,"lineagesR"));
203 |
204 | }
205 |
206 | }
207 |
208 | }
209 |
210 |
211 | /**
212 | * Get the lineage for a given pattern by parsing it and matching mustache partials
213 | * @param {String} the data from the raw pattern
214 | *
215 | * @return {Array} a list of patterns
216 | */
217 | protected function findLineages($data) {
218 | if (preg_match_all("/".$this->lineageMatch."/",$data,$matches)) {
219 | return array_unique($matches[$this->lineageMatchKey]);
220 | }
221 | return array();
222 | }
223 |
224 | }
225 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Helpers/PatternCodeHelper.php:
--------------------------------------------------------------------------------
1 | exportFiles = $options["exportFiles"];
31 | $this->exportClean = $options["exportClean"];
32 | $this->patternPaths = $options["patternPaths"];
33 |
34 | }
35 |
36 | public function run() {
37 |
38 | // default vars
39 | $options = array();
40 | $options["patternPaths"] = $this->patternPaths;
41 | $patternExtension = Config::getOption("patternExtension");
42 | $patternSourceDir = Config::getOption("patternSourceDir");
43 | $htmlHead = Template::getHTMLHead();
44 | $htmlFoot = Template::getHTMLFoot();
45 | $patternHead = Template::getPatternHead();
46 | $patternFoot = Template::getPatternFoot();
47 | $stringLoader = Template::getStringLoader();
48 |
49 | // re-load the pattern data since we modified it
50 | $store = PatternData::get();
51 |
52 | // load the pattern loader
53 | $patternEngineBasePath = PatternEngine::getInstance()->getBasePath();
54 | $patternLoaderClass = $patternEngineBasePath."\Loaders\PatternLoader";
55 | $patternLoader = new $patternLoaderClass($options);
56 |
57 | // iterate to process each pattern
58 | foreach ($store as $patternStoreKey => $patternStoreData) {
59 |
60 | if (($patternStoreData["category"] == "pattern") && isset($patternStoreData["name"])) {
61 |
62 | $data = Data::getPatternSpecificData($patternStoreKey);
63 |
64 | // add the pattern data so it can be exported
65 | $patternData = array();
66 | //$patternFooterData["patternFooterData"]["cssEnabled"] = (Config::$options["enableCSS"] && isset($this->patternCSS[$p])) ? "true" : "false";
67 | $patternData["cssEnabled"] = false;
68 | $patternData["lineage"] = isset($patternStoreData["lineages"]) ? $patternStoreData["lineages"] : array();
69 | $patternData["lineageR"] = isset($patternStoreData["lineagesR"]) ? $patternStoreData["lineagesR"] : array();
70 | $patternData["patternBreadcrumb"] = $patternStoreData["breadcrumb"];
71 | $patternData["patternDesc"] = (isset($patternStoreData["desc"])) ? $patternStoreData["desc"] : "";
72 | $patternData["patternExtension"] = $patternExtension;
73 | $patternData["patternName"] = $patternStoreData["nameClean"];
74 | $patternData["patternPartial"] = $patternStoreData["partial"];
75 | $patternData["patternState"] = $patternStoreData["state"];
76 |
77 | // extra copy for the code view
78 | $patternData["extraOutput"] = isset($patternStoreData["extraOutput"]) ? $patternStoreData["extraOutput"] : array();
79 |
80 | // add the pattern lab specific mark-up
81 | // set a default var
82 | $exportClean = (isset($options["exportClean"])) ? $options["exportClean"] : false;
83 | $data["patternLabHead"] = (!$this->exportFiles) ? $stringLoader->render(array("string" => $htmlHead, "data" => array("cacheBuster" => $data["cacheBuster"]))) : "";
84 | $data["patternLabFoot"] = (!$this->exportFiles) ? $stringLoader->render(array("string" => $htmlFoot, "data" => array("cacheBuster" => $data["cacheBuster"], "isPattern" => true, "patternData" => json_encode($patternData)))) : "";
85 |
86 | if (isset($patternStoreData["patternRaw"])) {
87 |
88 | $header = (!$this->exportClean) ? $patternLoader->render(array("pattern" => $patternHead, "data" => $data)) : "";
89 | $code = $patternLoader->render(array("pattern" => $patternStoreData["patternRaw"], "data" => $data));
90 | $footer = (!$this->exportClean) ? $patternLoader->render(array("pattern" => $patternFoot, "data" => $data)) : "";
91 |
92 | PatternData::setPatternOption($patternStoreKey,"header",$header);
93 | PatternData::setPatternOption($patternStoreKey,"code",$code);
94 | PatternData::setPatternOption($patternStoreKey,"footer",$footer);
95 |
96 | }
97 |
98 | }
99 |
100 | }
101 |
102 | }
103 |
104 | }
105 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Helpers/PatternStateHelper.php:
--------------------------------------------------------------------------------
1 | $patternStoreData) {
41 |
42 | if (($patternStoreData["category"] == "pattern") && isset($patternStoreData["state"])) {
43 |
44 | $patternState = $patternStoreData["state"];
45 |
46 | // make sure the pattern has a given state
47 | if ($patternState != "") {
48 |
49 | $patternStateDigit = array_search($patternState,$patternStates);
50 |
51 | // if this is a true pattern state update various patterns
52 | if ($patternStateDigit !== false) {
53 |
54 | $storeTake2 = PatternData::get();
55 | foreach ($storeTake2 as $patternStoreKey2 => $patternStoreData2) {
56 |
57 | if (($patternStoreData2["category"] == "pattern") && isset($patternStoreData2["lineagesR"])) {
58 |
59 | foreach ($patternStoreData2["lineagesR"] as $patternCheckInfo) {
60 |
61 | $lineagePatternPartial = $patternCheckInfo["lineagePattern"];
62 |
63 | // if the found pattern's lineage is empty and the pattern state isn't the last (e.g. complete) add the pattern state
64 | // otherwise, if the pattern state is less than the one being checked update the pattern
65 | if ((PatternData::getPatternOption($lineagePatternPartial,"state") == "") && ($patternStateDigit != $patternStateLast)) {
66 |
67 | PatternData::setPatternOption($lineagePatternPartial,"state",$patternState);
68 |
69 | } else {
70 |
71 | $patternStateCheck = array_search(PatternData::getPatternOption($lineagePatternPartial,"state"), $patternStates);
72 | if ($patternStateDigit < $patternStateCheck) {
73 | PatternData::setPatternOption($lineagePatternPartial,"state",$patternState);
74 | }
75 |
76 | }
77 |
78 | }
79 |
80 | }
81 |
82 | }
83 |
84 | }
85 |
86 | }
87 |
88 | }
89 |
90 | }
91 |
92 | // make sure we update the lineages with the pattern state if appropriate
93 | $store = PatternData::get();
94 | foreach ($store as $patternStoreKey => $patternStoreData) {
95 |
96 | if ($patternStoreData["category"] == "pattern") {
97 |
98 | if (isset($patternStoreData["lineages"]) && !empty($patternStoreData["lineages"])) {
99 |
100 | foreach ($patternStoreData["lineages"] as $patternLineageKey => $patternLineageInfo) {
101 |
102 | $lineagePattern = $patternLineageInfo["lineagePattern"];
103 | $patternState = PatternData::getPatternOption($lineagePattern,"state");
104 | if (($patternState != "") && ($patternState != null)) {
105 | PatternData::setPatternSubOption($patternStoreKey,"lineages",$patternLineageKey,"lineageState",$patternState);
106 | }
107 |
108 | }
109 |
110 | }
111 |
112 | if (isset($patternStoreData["lineagesR"]) && !empty($patternStoreData["lineagesR"])) {
113 |
114 | foreach ($patternStoreData["lineagesR"] as $patternLineageKey => $patternLineageInfo) {
115 |
116 | $lineagePattern = $patternLineageInfo["lineagePattern"];
117 | $patternState = PatternData::getPatternOption($lineagePattern,"state");
118 | if (($patternState != "") && ($patternState != null)) {
119 | PatternData::setPatternSubOption($patternStoreKey,"lineagesR",$patternLineageKey,"lineageState",$patternState);
120 | }
121 |
122 | }
123 |
124 | }
125 |
126 | }
127 |
128 | }
129 |
130 | }
131 |
132 | }
133 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Helpers/Plugins/CSSRuleSaverHelperPlugin.php:
--------------------------------------------------------------------------------
1 | // set-up the mark-up for CSS Rule Saver so it can figure out which rules to save
2 | $patternCSSExists = $this->enableCSS;
3 | $patternCSS = "";
4 | if ($this->enableCSS) {
5 | $this->cssRuleSaver->loadHTML($patternCodeRaw,false);
6 | $patternCSS = $this->cssRuleSaver->saveRules();
7 | $this->patternCSS[$patternSubtypeItem["patternPartial"]] = $patternCSS;
8 | }
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Helpers/RawPatternHelper.php:
--------------------------------------------------------------------------------
1 | $patternStoreData) {
43 |
44 | if (($patternStoreData["category"] == "pattern") && isset($patternStoreData["name"])) {
45 |
46 | // figure out the source path for the pattern to render
47 | $srcPath = (isset($patternStoreData["pseudo"])) ? PatternData::getPatternOption($patternStoreData["original"],"pathName") : $patternStoreData["pathName"];
48 |
49 | // load the raw data so it can be modified/rendered
50 | $path = $patternSourceDir.DIRECTORY_SEPARATOR.$srcPath.".".$patternExtension;
51 | if (file_exists($path)) {
52 | PatternData::setPatternOption($patternStoreKey,"patternRaw",file_get_contents($path));
53 | } else {
54 | Console::writeWarning($patternStoreData["partial"]." wasn't found for loading. the given path: ".$path);
55 | }
56 |
57 | }
58 |
59 | }
60 |
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Rule.php:
--------------------------------------------------------------------------------
1 | depthProp != 3) && ($depth != $this->depthProp)) {
43 | return false;
44 | }
45 |
46 | if (($this->compareProp($ext,$this->extProp, true)) && ($isDir == $this->isDirProp) && ($isFile == $this->isFileProp)) {
47 | $result = true;
48 | if ($this->searchProp != "") {
49 | $result = $this->compareProp($name,$this->searchProp);
50 | }
51 | if ($this->ignoreProp != "") {
52 | $result = ($this->compareProp($name,$this->ignoreProp)) ? false : true;
53 | }
54 | return $result;
55 | }
56 |
57 | return false;
58 |
59 | }
60 |
61 | /**
62 | * Compare the search and ignore props against the name.
63 | * Can use && or || in the comparison
64 | * @param {String} the name of the item
65 | * @param {String} the value of the property to compare
66 | *
67 | * @return {Boolean} whether the compare was successful or not
68 | */
69 | protected function compareProp($name, $propCompare, $exact = false) {
70 |
71 | if (($name == "") && ($propCompare == "")) {
72 | $result = true;
73 | } else if ((($name == "") && ($propCompare != "")) || (($name != "") && ($propCompare == ""))) {
74 | $result = false;
75 | } else if (strpos($propCompare,"&&") !== false) {
76 | $result = true;
77 | $props = explode("&&",$propCompare);
78 | foreach ($props as $prop) {
79 | $pos = $this->testProp($name, $prop, $exact);
80 | $result = ($result && $pos);
81 | }
82 | } else if (strpos($propCompare,"||") !== false) {
83 | $result = false;
84 | $props = explode("||",$propCompare);
85 | foreach ($props as $prop) {
86 | $pos = $this->testProp($name, $prop, $exact);
87 | $result = ($result || $pos);
88 | }
89 | } else {
90 | $result = $this->testProp($name, $propCompare, $exact);
91 | }
92 |
93 | return $result;
94 |
95 | }
96 |
97 | /**
98 | * Get the name for a given pattern sans any possible digits used for reordering
99 | * @param {String} the pattern based on the filesystem name
100 | * @param {Boolean} whether or not to strip slashes from the pattern name
101 | *
102 | * @return {String} a lower-cased version of the pattern name
103 | */
104 | protected function getPatternName($pattern, $clean = true) {
105 | $patternBits = explode("-",$pattern,2);
106 | $patternName = (((int)$patternBits[0] != 0) || ($patternBits[0] == '00')) ? $patternBits[1] : $pattern;
107 | // replace possible dots with dashes. pattern names cannot contain dots
108 | // since they are used as id/class names in the styleguidekit.
109 | $patternName = str_replace('.', '-', $patternName);
110 | return ($clean) ? (str_replace("-"," ",$patternName)) : $patternName;
111 | }
112 |
113 | /**
114 | * Get the value for a property on the current PatternData rule
115 | * @param {String} the name of the property
116 | *
117 | * @return {Boolean} whether the set was successful
118 | */
119 | public function getProp($propName) {
120 |
121 | if (isset($this->$propName)) {
122 | return $this->$propName;
123 | }
124 |
125 | return false;
126 |
127 | }
128 |
129 | /**
130 | * Set a value for a property on the current PatternData rule
131 | * @param {String} the name of the property
132 | * @param {String} the value of the property
133 | *
134 | * @return {Boolean} whether the set was successful
135 | */
136 | public function setProp($propName, $propValue) {
137 |
138 | $this->$propName = $this->$propValue;
139 | return true;
140 |
141 | }
142 |
143 | /**
144 | * Test the given property
145 | * @param {String} the value of the property to be tested
146 | * @param {String} the value of the property to be tested against
147 | * @param {Boolean} if this should be an exact match or just a string appearing in another
148 | *
149 | * @return {Boolean} the test result
150 | */
151 | protected function testProp($propToTest, $propToTestAgainst, $beExact) {
152 | if ($beExact) {
153 | $result = ($propToTest === $propToTestAgainst);
154 | } else {
155 | $result = (strpos($propToTest,$propToTestAgainst) !== false) ? true : false;
156 | }
157 | return $result;
158 | }
159 |
160 | /**
161 | * Update a property on a given rule
162 | * @param {String} the name of the property
163 | * @param {String} the value of the property
164 | * @param {String} the action that should be taken with the new value
165 | *
166 | * @return {Boolean} whether the update was successful
167 | */
168 | public function updateProp($propName, $propValue, $action = "or") {
169 |
170 | if (!isset($this->$propName) || !is_scalar($propValue)) {
171 | return false;
172 | }
173 |
174 | if ($action == "or") {
175 |
176 | $propValue = $this->$propName."||".$propValue;
177 |
178 | } else if ($action == "and") {
179 |
180 | $propValue = $this->$propName."&&".$propValue;
181 |
182 | }
183 |
184 | return $this->setProp($this->$propName,$propValue);
185 |
186 | }
187 |
188 | }
189 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Rules/DocumentationRule.php:
--------------------------------------------------------------------------------
1 | depthProp = 3; // 3 means that depth won't be checked
27 | $this->extProp = "md";
28 | $this->isDirProp = false;
29 | $this->isFileProp = true;
30 | $this->searchProp = "";
31 | $this->ignoreProp = "";
32 |
33 | }
34 |
35 | public function run($depth, $ext, $path, $pathName, $name) {
36 |
37 | // load default vars
38 | $patternType = PatternData::getPatternType();
39 | $patternTypeDash = PatternData::getPatternTypeDash();
40 | $dirSep = PatternData::getDirSep();
41 |
42 | // set-up the names, $name == 00-colors.md
43 | $doc = str_replace(".".$this->extProp,"",$name); // 00-colors
44 | $docDash = $this->getPatternName(str_replace("_","",$doc),false); // colors
45 | $docPartial = $patternTypeDash."-".$docDash;
46 |
47 | // default vars
48 | $patternSourceDir = Config::getOption("patternSourceDir");
49 |
50 | // parse data
51 | $text = file_get_contents($patternSourceDir.DIRECTORY_SEPARATOR.$pathName);
52 | list($yaml,$markdown) = Documentation::parse($text);
53 |
54 | // grab the title and unset it from the yaml so it doesn't get duped in the meta
55 | if (isset($yaml["title"])) {
56 | $title = $yaml["title"];
57 | unset($yaml["title"]);
58 | }
59 |
60 | // figure out if this is a pattern subtype
61 | $patternSubtypeDoc = false;
62 | if ($depth == 1) {
63 | // go through all of the directories to see if this one matches our doc
64 | foreach (glob($patternSourceDir.DIRECTORY_SEPARATOR.$patternType.DIRECTORY_SEPARATOR."*",GLOB_ONLYDIR) as $dir) {
65 | $dir = str_replace($patternSourceDir.DIRECTORY_SEPARATOR.$patternType.DIRECTORY_SEPARATOR,"",$dir);
66 | if ($dir == $doc) {
67 | $patternSubtypeDoc = true;
68 | break;
69 | }
70 | }
71 |
72 | }
73 |
74 | $category = ($patternSubtypeDoc) ? "patternSubtype" : "pattern";
75 | $patternStoreKey = ($patternSubtypeDoc) ? $docPartial."-plsubtype" : $docPartial;
76 |
77 | $patternStoreData = array("category" => $category,
78 | "desc" => trim($markdown),
79 | "descExists" => true,
80 | "meta" => $yaml,
81 | "full" => $doc);
82 |
83 | // can set `title: My Cool Pattern` instead of lifting from file name
84 | if (isset($title)) {
85 | $patternStoreData["nameClean"] = $title;
86 | }
87 |
88 | $availableKeys = [
89 | 'state', // can use `state: inprogress` instead of `button@inprogress.mustache`
90 | 'hidden', // setting to `true`, removes from menu and viewall, which is same as adding `_` prefix
91 | 'noviewall', // setting to `true`, removes from view alls but keeps in menu, which is same as adding `-` prefix
92 | 'order', // @todo implement order
93 | 'tags', // not implemented, awaiting spec approval and integration with styleguide kit. adding to be in sync with Node version.
94 | 'links', // not implemented, awaiting spec approval and integration with styleguide kit. adding to be in sync with Node version.
95 | ];
96 |
97 | foreach ($availableKeys as $key) {
98 | if (isset($yaml[$key])) {
99 | $patternStoreData[$key] = $yaml[$key];
100 | }
101 | }
102 |
103 | // if the pattern data store already exists make sure this data overwrites it
104 | $patternStoreData = (PatternData::checkOption($patternStoreKey)) ? array_replace_recursive(PatternData::getOption($patternStoreKey),$patternStoreData) : $patternStoreData;
105 | PatternData::setOption($patternStoreKey, $patternStoreData);
106 |
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Rules/PatternInfoListItemsRule.php:
--------------------------------------------------------------------------------
1 | depthProp = 3; // 3 means that depth won't be checked
29 | $this->extProp = "json||yaml||yml";
30 | $this->isDirProp = false;
31 | $this->isFileProp = true;
32 | $this->searchProp = ".listitems.";
33 | $this->ignoreProp = "";
34 |
35 | }
36 |
37 | public function run($depth, $ext, $path, $pathName, $name) {
38 |
39 | // load default vars
40 | $patternTypeDash = PatternData::getPatternTypeDash();
41 |
42 | // set-up the names, $name == foo.listitems.json
43 | $pattern = str_replace(".listitems.".$ext,"",$name); // foo
44 | $patternDash = $this->getPatternName($pattern,false); // foo
45 | $patternPartial = $patternTypeDash."-".$patternDash; // atoms-foo
46 |
47 | $patternStoreData = array("category" => "pattern");
48 |
49 | $data = Data::getListItems("_patterns/".$pathName,$ext);
50 | $patternStoreData["listItems"] = $data;
51 |
52 | // create a key for the data store
53 | $patternStoreKey = $patternPartial;
54 |
55 | // if the pattern data store already exists make sure it is merged and overwrites this data
56 | $patternStoreData = (PatternData::checkOption($patternStoreKey)) ? array_replace_recursive(PatternData::getOption($patternStoreKey),$patternStoreData) : $patternStoreData;
57 | PatternData::setOption($patternStoreKey, $patternStoreData);
58 |
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Rules/PatternInfoRule.php:
--------------------------------------------------------------------------------
1 | depthProp = 3; // 3 means that depth won't be checked
29 | $this->extProp = "json||yaml||yml";
30 | $this->isDirProp = false;
31 | $this->isFileProp = true;
32 | $this->searchProp = "";
33 | $this->ignoreProp = "~||listitems";
34 |
35 | }
36 |
37 | public function run($depth, $ext, $path, $pathName, $name) {
38 |
39 | // load default vars
40 | $patternTypeDash = PatternData::getPatternTypeDash();
41 |
42 | // set-up the names, $name == foo.json
43 | $pattern = str_replace(".".$ext,"",$name); // foo
44 | $patternDash = $this->getPatternName($pattern,false); // foo
45 | $patternPartial = $patternTypeDash."-".$patternDash; // atoms-foo
46 |
47 | $patternStoreData = array("category" => "pattern");
48 |
49 | $file = file_get_contents(Config::getOption("patternSourceDir")."/".$pathName);
50 |
51 | if ($ext == "json") {
52 | $data = json_decode($file,true);
53 | if ($jsonErrorMessage = JSON::hasError()) {
54 | JSON::lastErrorMsg($name,$jsonErrorMessage,$data);
55 | }
56 | } else {
57 |
58 | try {
59 | $data = YAML::parse($file);
60 | } catch (ParseException $e) {
61 | printf("unable to parse ".$pathNameClean.": %s..\n", $e->getMessage());
62 | }
63 |
64 | // single line of text won't throw a YAML error. returns as string
65 | if (gettype($data) == "string") {
66 | $data = array();
67 | }
68 |
69 | }
70 |
71 | $patternStoreData["data"] = $data;
72 |
73 | // create a key for the data store
74 | $patternStoreKey = $patternPartial;
75 |
76 | // if the pattern data store already exists make sure it is merged and overwrites this data
77 | $patternStoreData = (PatternData::checkOption($patternStoreKey)) ? array_replace_recursive(PatternData::getOption($patternStoreKey),$patternStoreData) : $patternStoreData;
78 | PatternData::setOption($patternStoreKey, $patternStoreData);
79 |
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Rules/PatternRule.php:
--------------------------------------------------------------------------------
1 | depthProp = 3; // 3 means that depth won't be checked
26 | $this->extProp = Config::getOption("patternExtension");
27 | $this->isDirProp = false;
28 | $this->isFileProp = true;
29 | $this->searchProp = "";
30 | $this->ignoreProp = "";
31 |
32 | }
33 |
34 | public function run($depth, $ext, $path, $pathName, $name) {
35 |
36 | // load default vars
37 | $patternSubtype = PatternData::getPatternSubtype();
38 | $patternSubtypeClean = PatternData::getPatternSubtypeClean();
39 | $patternSubtypeDash = PatternData::getPatternSubtypeDash();
40 | $patternType = PatternData::getPatternType();
41 | $patternTypeClean = PatternData::getPatternTypeClean();
42 | $patternTypeDash = PatternData::getPatternTypeDash();
43 | $dirSep = PatternData::getDirSep();
44 | $frontMeta = PatternData::getFrontMeta();
45 |
46 | // should this pattern get rendered?
47 | $hidden = ($name[0] == "_");
48 | $noviewall = ($name[0] == "-");
49 |
50 | // set-up the names
51 | $patternFull = in_array($name[0],$frontMeta) ? substr($name,1) : $name; // 00-colors.mustache
52 | $pattern = str_replace(".".$this->extProp,"",$patternFull); // 00-colors
53 | $patternState = "";
54 |
55 | // check for pattern state
56 | if (strpos($pattern,"@") !== false) {
57 | $patternBits = explode("@",$pattern,2);
58 | $pattern = $patternBits[0];
59 | $patternState = $patternBits[1];
60 | }
61 |
62 | // finish setting up vars
63 | $patternDash = $this->getPatternName($pattern,false); // colors
64 | $patternClean = str_replace("-"," ",$patternDash); // colors (dashes replaced with spaces)
65 | $patternPartial = $patternTypeDash."-".$patternDash; // atoms-colors
66 | $patternPath = str_replace(".".$this->extProp,"",$pathName); // 00-atoms/01-global/00-colors
67 | $patternPathDash = str_replace($dirSep,"-",$patternPath); // 00-atoms-01-global-00-colors (file path)
68 |
69 | // create a key for the data store
70 | $patternStoreKey = $patternPartial;
71 |
72 | // collect the data
73 | $patternStoreData = array("category" => "pattern",
74 | "name" => $pattern,
75 | "partial" => $patternPartial,
76 | "nameDash" => $patternDash,
77 | "nameClean" => $patternClean,
78 | "type" => $patternType,
79 | "typeDash" => $patternTypeDash,
80 | "breadcrumb" => array("patternType" => $patternTypeClean),
81 | "state" => $patternState,
82 | "hidden" => $hidden,
83 | "noviewall" => $noviewall,
84 | "depth" => $depth,
85 | "ext" => $ext,
86 | "path" => $path,
87 | "pathName" => $patternPath,
88 | "pathDash" => $patternPathDash,
89 | "isDir" => $this->isDirProp,
90 | "isFile" => $this->isFileProp,
91 | "partialViewDescAdditions" => array(),
92 | "partialViewExampleAdditions" => array(),
93 | "extraHolder" => array(),
94 | "extraOutput" => array());
95 |
96 | // add any subtype info if necessary
97 | if ($depth > 1) {
98 | $patternStoreData["subtype"] = $patternSubtype;
99 | $patternStoreData["subtypeDash"] = $patternSubtypeDash;
100 | $patternStoreData["breadcrumb"] = array("patternType" => $patternTypeClean, "patternSubtype" => $patternSubtypeClean);
101 | }
102 |
103 | // if the pattern data store already exists make sure it is merged and overwrites this data
104 | $patternStoreData = (PatternData::checkOption($patternStoreKey)) ? array_replace_recursive($patternStoreData, PatternData::getOption($patternStoreKey)) : $patternStoreData;
105 | PatternData::setOption($patternStoreKey, $patternStoreData);
106 |
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Rules/PatternSubtypeRule.php:
--------------------------------------------------------------------------------
1 | depthProp = 1;
25 | $this->extProp = "";
26 | $this->isDirProp = true;
27 | $this->isFileProp = false;
28 | $this->searchProp = "";
29 | $this->ignoreProp = "";
30 |
31 | }
32 |
33 | public function run($depth, $ext, $path, $pathName, $name) {
34 |
35 | // load default vars
36 | $patternType = PatternData::getPatternType();
37 | $patternTypeDash = PatternData::getPatternTypeDash();
38 | $patternTypeClean = PatternData::getPatternTypeClean();
39 | $dirSep = PatternData::getDirSep();
40 |
41 | // set-up the names
42 | $patternSubtype = $name; // 02-blocks
43 | $patternSubtypeDash = $this->getPatternName($name,false); // blocks
44 | $patternSubtypeClean = str_replace("-"," ",$patternSubtypeDash); // blocks (dashes replaced with spaces)
45 | $patternSubtypePath = $pathName; // 00-atoms/02-blocks
46 | $patternSubtypePathDash = str_replace($dirSep,"-",$patternSubtypePath); // 00-atoms-02-blocks (file path)
47 |
48 | $patternPartial = "viewall-".$patternTypeDash."-".$patternSubtypeDash;
49 |
50 | // create a key for the data store
51 | $patternStoreKey = $patternTypeDash."-".$patternSubtypeDash."-plsubtype";
52 |
53 | // collect the data
54 | $patternStoreData = array("category" => "patternSubtype",
55 | "name" => $patternSubtype,
56 | "nameDash" => $patternSubtypeDash,
57 | "nameClean" => $patternSubtypeClean,
58 | "partial" => $patternPartial,
59 | "type" => $patternType,
60 | "typeDash" => $patternTypeDash,
61 | "breadcrumb" => array("patternType" => $patternTypeClean),
62 | "depth" => $depth,
63 | "ext" => $ext,
64 | "path" => $path,
65 | "pathName" => $patternSubtypePath,
66 | "pathDash" => $patternSubtypePathDash,
67 | "isDir" => $this->isDirProp,
68 | "isFile" => $this->isFileProp);
69 |
70 | // if the pattern data store already exists make sure it is merged and overwrites this data
71 | $patternStoreData = (PatternData::checkOption($patternStoreKey)) ? array_replace_recursive(PatternData::getOption($patternStoreKey),$patternStoreData) : $patternStoreData;
72 | PatternData::setOption($patternStoreKey, $patternStoreData);
73 |
74 | // starting a new set of pattern types. it might not have any pattern subtypes
75 | PatternData::setPatternSubtype($patternSubtype);
76 | PatternData::setPatternSubtypeClean($patternSubtypeClean);
77 | PatternData::setPatternSubtypeDash($patternSubtypeDash);
78 | PatternData::setPatternSubtypeSet(true);
79 |
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Rules/PatternTypeRule.php:
--------------------------------------------------------------------------------
1 | depthProp = 0;
25 | $this->extProp = "";
26 | $this->isDirProp = true;
27 | $this->isFileProp = false;
28 | $this->searchProp = "";
29 | $this->ignoreProp = "";
30 |
31 | }
32 |
33 | public function run($depth, $ext, $path, $pathName, $name) {
34 |
35 | // load default vars
36 | $dirSep = PatternData::getDirSep();
37 |
38 | // set-up the names
39 | $patternType = $name; // 00-atoms
40 | $patternTypeDash = $this->getPatternName($name,false); // atoms
41 | $patternTypeClean = str_replace("-"," ",$patternTypeDash); // atoms (dashes replaced with spaces)
42 |
43 | $patternTypePath = $pathName; // 00-atoms/02-blocks
44 | $patternTypePathDash = str_replace($dirSep,"-",$patternTypePath); // 00-atoms-02-blocks (file path)
45 |
46 | // create a key for the data store
47 | $patternStoreKey = $patternTypeDash."-pltype";
48 |
49 | // add a new patternType to the nav
50 | $patternData = array("category" => "patternType",
51 | "name" => $patternType,
52 | "nameDash" => $patternTypeDash,
53 | "nameClean" => $patternTypeClean,
54 | "depth" => $depth,
55 | "ext" => $ext,
56 | "path" => $path,
57 | "pathName" => $patternTypePath,
58 | "pathDash" => $patternTypePathDash,
59 | "isDir" => $this->isDirProp,
60 | "isFile" => $this->isFileProp);
61 |
62 | PatternData::setOption($patternStoreKey,$patternData);
63 |
64 | // starting a new set of pattern types. it might not have any pattern subtypes
65 | PatternData::setPatternType($patternType);
66 | PatternData::setPatternTypeClean($patternTypeClean);
67 | PatternData::setPatternTypeDash($patternTypeDash);
68 |
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternData/Rules/PseudoPatternRule.php:
--------------------------------------------------------------------------------
1 | depthProp = 3; // 3 means that depth won't be checked
29 | $this->extProp = "json||yaml||yml";
30 | $this->isDirProp = false;
31 | $this->isFileProp = true;
32 | $this->searchProp = "~";
33 | $this->ignoreProp = "";
34 |
35 | }
36 |
37 | public function run($depth, $ext, $path, $pathName, $name) {
38 |
39 | // load default vars
40 | $patternSubtype = PatternData::getPatternSubtype();
41 | $patternSubtypeClean = PatternData::getPatternSubtypeClean();
42 | $patternSubtypeDash = PatternData::getPatternSubtypeDash();
43 | $patternType = PatternData::getPatternType();
44 | $patternTypeClean = PatternData::getPatternTypeClean();
45 | $patternTypeDash = PatternData::getPatternTypeDash();
46 | $dirSep = PatternData::getDirSep();
47 | $frontMeta = PatternData::getFrontMeta();
48 |
49 | // should this pattern get rendered?
50 | $hidden = ($name[0] == "_");
51 | $noviewall = ($name[0] == "-");
52 |
53 | // set-up the names
54 | $patternFull = in_array($name[0],$frontMeta) ? substr($name,1) : $name; // 00-colors~foo.mustache
55 | $patternState = "";
56 |
57 | // check for pattern state
58 | if (strpos($patternFull,"@") !== false) {
59 | $patternBits = explode("@",$patternFull,2);
60 | $patternState = str_replace(".".$ext,"",$patternBits[1]);
61 | $patternFull = preg_replace("/@(.*?)\./",".",$patternFull);
62 | }
63 |
64 | // finish setting up vars
65 | $patternBits = explode("~",$patternFull);
66 | $patternBase = $patternBits[0].".".Config::getOption("patternExtension"); // 00-homepage.mustache
67 | $patternBaseDash = $this->getPatternName($patternBits[0],false); // homepage
68 | $patternBaseOrig = $patternTypeDash."-".$patternBaseDash; // pages-homepage
69 | $patternBaseData = $patternBits[0].".".$ext; // 00-homepage.json
70 | $stripJSON = str_replace(".".$ext,"",$patternBits[1]);
71 | $patternBitClean = preg_replace("/@(.*?)/","",$patternBits[0]);
72 | $pattern = $patternBitClean."-".$stripJSON; // 00-homepage-00-emergency
73 | $patternInt = $patternBitClean."-".$this->getPatternName($stripJSON, false); // 00-homepage-emergency
74 | $patternDash = $this->getPatternName($patternInt,false); // homepage-emergency
75 | $patternClean = str_replace("-"," ",$patternDash); // homepage emergency
76 | $patternPartial = $patternTypeDash."-".$patternDash; // pages-homepage-emergency
77 | $patternPath = str_replace(".".$ext,"",str_replace("~","-",$pathName)); // 00-atoms/01-global/00-colors
78 | $patternPathDash = str_replace($dirSep,"-",$patternPath); // 00-atoms-01-global-00-colors (file path)
79 |
80 | // check the original pattern path. if it doesn't exist make a guess
81 | $patternPathOrig = PatternData::getPatternOption($patternBaseOrig,"pathName"); // 04-pages/00-homepage
82 | $patternPathOrigDash = PatternData::getPatternOption($patternBaseOrig,"pathDash"); // 04-pages-00-homepage
83 | if (!$patternPathOrig) {
84 | $patternPathOrigBits = explode("~",$pathName);
85 | $patternPathOrig = $patternPathOrigBits[0]; // 04-pages/00-homepage
86 | $patternPathOrigDash = str_replace($dirSep,"-",$patternPathOrig); // 04-pages-00-homepage
87 | }
88 |
89 | // create a key for the data store
90 | $patternStoreKey = $patternPartial;
91 |
92 | // collect the data
93 | $patternStoreData = array("category" => "pattern",
94 | "name" => $pattern,
95 | "partial" => $patternPartial,
96 | "nameDash" => $patternDash,
97 | "nameClean" => $patternClean,
98 | "type" => $patternType,
99 | "typeDash" => $patternTypeDash,
100 | "breadcrumb" => array("patternType" => $patternTypeClean),
101 | "state" => $patternState,
102 | "hidden" => $hidden,
103 | "noviewall" => $noviewall,
104 | "depth" => $depth,
105 | "ext" => $ext,
106 | "path" => $path,
107 | "pathName" => $patternPath,
108 | "pathDash" => $patternPathDash,
109 | "isDir" => $this->isDirProp,
110 | "isFile" => $this->isFileProp,
111 | "pseudo" => true,
112 | "original" => $patternBaseOrig,
113 | "pathOrig" => $patternPathOrig,
114 | "pathOrigDash" => $patternPathOrigDash);
115 |
116 | // add any subtype info if necessary
117 | if ($depth > 1) {
118 | $patternStoreData["subtype"] = $patternSubtype;
119 | $patternStoreData["subtypeDash"] = $patternSubtypeDash;
120 | $patternStoreData["breadcrumb"] = array("patternType" => $patternTypeClean, "patternSubtype" => $patternSubtypeClean);
121 | }
122 |
123 | $patternDataBase = array();
124 | if (file_exists(Config::getOption("patternSourceDir").DIRECTORY_SEPARATOR.$path.DIRECTORY_SEPARATOR.$patternBaseData)) {
125 | $data = file_get_contents(Config::getOption("patternSourceDir").DIRECTORY_SEPARATOR.$path.DIRECTORY_SEPARATOR.$patternBaseData);
126 | if ($ext == "json") {
127 | $patternDataBase = json_decode($data,true);
128 | if ($jsonErrorMessage = JSON::hasError()) {
129 | JSON::lastErrorMsg($patternBaseJSON,$jsonErrorMessage,$data);
130 | }
131 | } else {
132 |
133 | try {
134 | $patternDataBase = YAML::parse($data);
135 | } catch (ParseException $e) {
136 | printf("unable to parse ".$pathNameClean.": %s..\n", $e->getMessage());
137 | }
138 |
139 | // single line of text won't throw a YAML error. returns as string
140 | if (gettype($patternDataBase) == "string") {
141 | $patternDataBase = array();
142 | }
143 |
144 | }
145 |
146 | }
147 |
148 | // get the data for the pseudo-pattern
149 | $data = file_get_contents(Config::getOption("patternSourceDir").DIRECTORY_SEPARATOR.$pathName);
150 | if ($ext == "json") {
151 | $patternData = json_decode($data,true);
152 | if ($jsonErrorMessage = JSON::hasError()) {
153 | JSON::lastErrorMsg($name,$jsonErrorMessage,$data);
154 | }
155 | } else {
156 |
157 | try {
158 | $patternData = YAML::parse($data);
159 | } catch (ParseException $e) {
160 | printf("unable to parse ".$pathNameClean.": %s..\n", $e->getMessage());
161 | }
162 |
163 | // single line of text won't throw a YAML error. returns as string
164 | if (gettype($patternData) == "string") {
165 | $patternData = array();
166 | }
167 |
168 | }
169 |
170 | // make sure the pattern data is an array before merging the data
171 | $patternStoreData["data"] = is_array($patternData) ? array_replace_recursive($patternDataBase, $patternData) : $patternDataBase;
172 |
173 | // if the pattern data store already exists make sure it is merged and overwrites this data
174 | if (PatternData::checkOption($patternStoreKey)) {
175 | $existingData = PatternData::getOption($patternStoreKey);
176 | if (array_key_exists('nameClean', $existingData)) {
177 | // don't overwrite nameClean
178 | unset($patternStoreData['nameClean']);
179 | }
180 | $patternStoreData = array_replace_recursive($existingData, $patternStoreData);
181 | }
182 | PatternData::setOption($patternStoreKey, $patternStoreData);
183 |
184 | }
185 |
186 | }
187 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternEngine.php:
--------------------------------------------------------------------------------
1 | test($patternExtension)) {
42 | self::$instance = $rule;
43 | $found = true;
44 | break;
45 | }
46 | }
47 |
48 | if (!$found) {
49 | Console::writeError("the supplied pattern extension didn't match a pattern loader rule. check your config...");
50 | }
51 |
52 | }
53 |
54 | /**
55 | * Load all of the rules related to Pattern Engines. They're located in the plugin dir
56 | */
57 | public static function loadRules() {
58 |
59 | // default var
60 | $configDir = Config::getOption("configDir");
61 |
62 | // make sure the pattern engine data exists
63 | if (file_exists($configDir."/patternengines.json")) {
64 |
65 | // get pattern engine list data
66 | $patternEngineList = json_decode(file_get_contents($configDir."/patternengines.json"), true);
67 |
68 | // get the pattern engine info
69 | foreach ($patternEngineList["patternengines"] as $patternEngineName) {
70 |
71 | self::$rules[] = new $patternEngineName();
72 |
73 | }
74 |
75 | } else {
76 | Console::writeError("The pattern engines list isn't available in ".$configDir."...");
77 | }
78 |
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternEngine/Loader.php:
--------------------------------------------------------------------------------
1 | basePath;
32 |
33 | }
34 |
35 | public function test($patternExtension) {
36 |
37 | return ($this->engineProp === $patternExtension);
38 |
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/PatternLab/PatternEngine/Util.php:
--------------------------------------------------------------------------------
1 | patternPaths = $options["patternPaths"];
27 |
28 | }
29 |
30 | /**
31 | * Helper function to find and replace the given parameters in a particular partial before handing it back to Mustache
32 | * @param {String} the file contents
33 | * @param {Array} an array of paramters to match
34 | *
35 | * @return {String} the modified file contents
36 | */
37 | public function findReplaceParameters($fileData, $parameters) {
38 | $numbers = array("zero","one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve");
39 | foreach ($parameters as $k => $v) {
40 | if (is_array($v)) {
41 | if (preg_match('/{{\#([\s]*'.$k.'[\s]*)}}(.*?){{\/([\s]*'.$k.'[\s]*)}}/s',$fileData,$matches)) {
42 | if (isset($matches[2])) {
43 | $partialData = "";
44 | foreach ($v as $v2) {
45 | $partialData .= $this->findReplaceParameters($matches[2], $v2);
46 | }
47 | $fileData = preg_replace('/{{\#([\s]*'.$k.'[\s]*)}}(.*?){{\/([\s]*'.$k .'[\s]*)}}/s',$partialData,$fileData);
48 | }
49 | }
50 | } else if ($v == "true") {
51 | $fileData = preg_replace('/{{\#([\s]*'.$k.'[\s]*)}}(.*?){{\/([\s]*'.$k .'[\s]*)}}/s','$2',$fileData); // {{# asdf }}STUFF{{/ asdf}}
52 | $fileData = preg_replace('/{{\^([\s]*'.$k.'[\s]*)}}(.*?){{\/([\s]*'.$k .'[\s]*)}}/s','',$fileData); // {{^ asdf }}STUFF{{/ asdf}}
53 | } else if ($v == "false") {
54 | $fileData = preg_replace('/{{\^([\s]*'.$k.'[\s]*)}}(.*?){{\/([\s]*'.$k .'[\s]*)}}/s','$2',$fileData); // {{# asdf }}STUFF{{/ asdf}}
55 | $fileData = preg_replace('/{{\#([\s]*'.$k.'[\s]*)}}(.*?){{\/([\s]*'.$k .'[\s]*)}}/s','',$fileData); // {{^ asdf }}STUFF{{/ asdf}}
56 | } else if ($k == "listItems") {
57 | $v = ((int)$v != 0) && ((int)$v < 13) ? $numbers[$v] : $v;
58 | if (($v != "zero") && in_array($v,$numbers)) {
59 | $fileData = preg_replace('/{{\#([\s]*listItems\.[A-z]{3,10}[\s]*)}}/s','{{# listItems.'.$v.' }}',$fileData);
60 | $fileData = preg_replace('/{{\/([\s]*listItems\.[A-z]{3,10}[\s]*)}}/s','{{/ listItems.'.$v.' }}',$fileData);
61 | }
62 | } else {
63 | $fileData = preg_replace('/{{{([\s]*'.$k.'[\s]*)}}}/', $v, $fileData); // {{{ asdf }}}
64 | $fileData = preg_replace('/{{([\s]*'.$k.'[\s]*)}}/', htmlspecialchars($v), $fileData); // escaped {{ asdf }}
65 | }
66 | }
67 | return $fileData;
68 | }
69 |
70 | /**
71 | * Helper function for getting a Mustache template file name.
72 | * @param {String} the pattern type for the pattern
73 | * @param {String} the pattern sub-type
74 | *
75 | * @return {Array} an array of rendered partials that match the given path
76 | */
77 | public function getFileName($name,$ext) {
78 |
79 | $fileName = "";
80 | $dirSep = DIRECTORY_SEPARATOR;
81 |
82 | // test to see what kind of path was supplied
83 | $posDash = strpos($name,"-");
84 | $posSlash = strpos($name,$dirSep);
85 |
86 | if (($posSlash === false) && ($posDash !== false)) {
87 | $fileName = $this->getPatternFileName($name);
88 | } else {
89 | $fileName = $name;
90 | }
91 |
92 | if (substr($fileName, 0 - strlen($ext)) !== $ext) {
93 | $fileName .= $ext;
94 | }
95 |
96 | return $fileName;
97 |
98 | }
99 |
100 | /**
101 | * Helper function to return the pattern file name
102 | * @param {String} the name of the pattern
103 | *
104 | * @return {String} the file path to the pattern
105 | */
106 | public function getPatternFileName($name) {
107 |
108 | $patternFileName = "";
109 |
110 | list($patternType,$pattern) = $this->getPatternInfo($name);
111 |
112 | // see if the pattern is an exact match for patternPaths. if not iterate over patternPaths to find a likely match
113 | if (isset($this->patternPaths[$patternType][$pattern])) {
114 | $patternFileName = $this->patternPaths[$patternType][$pattern];
115 | } else if (isset($this->patternPaths[$patternType])) {
116 | foreach($this->patternPaths[$patternType] as $patternMatchKey=>$patternMatchValue) {
117 | $pos = strpos($patternMatchKey,$pattern);
118 | if ($pos !== false) {
119 | $patternFileName = $patternMatchValue;
120 | break;
121 | }
122 | }
123 | }
124 |
125 | return $patternFileName;
126 |
127 | }
128 |
129 | /**
130 | * Helper function to return the parts of a partial name
131 | * @param {String} the name of the partial
132 | *
133 | * @return {Array} the pattern type and the name of the pattern
134 | */
135 | public function getPatternInfo($name) {
136 |
137 | $patternBits = explode("-",$name);
138 |
139 | $i = 1;
140 | $k = 2;
141 | $c = count($patternBits);
142 | $patternType = $patternBits[0];
143 | while (!isset($this->patternPaths[$patternType]) && ($i < $c)) {
144 | $patternType .= "-".$patternBits[$i];
145 | $i++;
146 | $k++;
147 | }
148 |
149 | $patternBits = explode("-",$name,$k);
150 | $pattern = $patternBits[count($patternBits)-1];
151 |
152 | return array($patternType, $pattern);
153 |
154 | }
155 |
156 | /**
157 | * Helper function for finding if a partial name has style modifier or parameters
158 | * @param {String} the pattern name
159 | *
160 | * @return {Array} an array containing just the partial name, a style modifier, and any parameters
161 | */
162 | public function getPartialInfo($partial) {
163 |
164 | $styleModifier = array();
165 | $parameters = array();
166 |
167 | if (strpos($partial, "(") !== false) {
168 | $partialBits = explode("(",$partial,2);
169 | $partial = trim($partialBits[0]);
170 | $parametersString = substr($partialBits[1],0,(strlen($partialBits[1]) - strlen(strrchr($partialBits[1],")"))));
171 | $parameters = $this->parseParameters($parametersString);
172 | }
173 |
174 | if (strpos($partial, ":") !== false) {
175 | $partialBits = explode(":",$partial,2);
176 | $partial = $partialBits[0];
177 | $styleModifier = $partialBits[1];
178 | if (strpos($styleModifier, "|") !== false) {
179 | $styleModifierBits = explode("|",$styleModifier);
180 | $styleModifier = join(" ",$styleModifierBits);
181 | }
182 | $styleModifier = array("styleModifier" => $styleModifier);
183 | }
184 |
185 | return array($partial,$styleModifier,$parameters);
186 |
187 | }
188 |
189 | /**
190 | * Helper function to parse the parameters and return them as an array
191 | * @param {String} the parameter string
192 | *
193 | * @return {Array} the keys and values for the parameters
194 | */
195 | private function parseParameters($string) {
196 |
197 | $parameters = array();
198 | $arrayParameters = array();
199 | $arrayOptions = array();
200 | $betweenSQuotes = false;
201 | $betweenDQuotes = false;
202 | $inKey = true;
203 | $inValue = false;
204 | $inArray = false;
205 | $inOption = false;
206 | $char = "";
207 | $buffer = "";
208 | $keyBuffer = "";
209 | $arrayKeyBuffer = "";
210 | $strLength = strlen($string);
211 |
212 | for ($i = 0; $i < $strLength; $i++) {
213 |
214 | $previousChar = $char;
215 | $char = $string[$i];
216 |
217 | if ($inKey && !$betweenDQuotes && !$betweenSQuotes && (($char == "\"") || ($char == "'"))) {
218 | // if inKey, a quote, and betweenQuotes is false ignore quote, set betweenQuotes to true and empty buffer to kill spaces
219 | ($char == "\"") ? ($betweenDQuotes = true) : ($betweenSQuotes = true);
220 | } else if ($inKey && (($betweenDQuotes && ($char == "\"")) || ($betweenSQuotes && ($char == "'"))) && ($previousChar == "\\")) {
221 | // if inKey, a quote, betweenQuotes is true, and previous character is \ add to buffer
222 | $buffer .= $char;
223 | } else if ($inKey && (($betweenDQuotes && ($char == "\"")) || ($betweenSQuotes && ($char == "'")))) {
224 | // if inKey, a quote, betweenQuotes is true set betweenQuotes to false, save as key buffer, empty buffer set inKey false
225 | $keyBuffer = $buffer;
226 | $buffer = "";
227 | $inKey = false;
228 | $betweenSQuotes = false;
229 | $betweenDQuotes = false;
230 | } else if ($inKey && !$betweenDQuotes && !$betweenSQuotes && ($char == ":")) {
231 | // if inKey, a colon, betweenQuotes is false, save as key buffer, empty buffer, set inKey false set inValue true
232 | $keyBuffer = $buffer;
233 | $buffer = "";
234 | $inKey = false;
235 | $inValue = true;
236 | } else if ($inKey) {
237 | // if inKey add to buffer
238 | $buffer .= $char;
239 | } else if (!$inKey && !$inValue && ($char == ":")) {
240 | // if inKey is false, inValue false, and a colon set inValue true
241 | $inValue = true;
242 | } else if ($inValue && !$inArray && !$betweenDQuotes && !$betweenSQuotes && ($char == "[")) {
243 | // if inValue, outside quotes, and find a bracket set inArray to true and add to array buffer
244 | $inArray = true;
245 | $inValue = false;
246 | $arrayKeyBuffer = trim($keyBuffer);
247 | } else if ($inArray && !$betweenDQuotes && !$betweenSQuotes && ($char == "]")) {
248 | // if inValue, outside quotes, and find a bracket set inArray to true and add to array buffer
249 | $inArray = false;
250 | $parameters[$arrayKeyBuffer] = $arrayParameters;
251 | $arrayParameters = array();
252 | } else if ($inArray && !$inOption && !$betweenDQuotes && !$betweenSQuotes && ($char == "{")) {
253 | $inOption = true;
254 | $inKey = true;
255 | } else if ($inArray && $inOption && !$betweenDQuotes && !$betweenSQuotes && ($char == "}")) {
256 | $inOption = false;
257 | $inValue = false;
258 | $inKey = false;
259 | $arrayParameters[] = $arrayOptions;
260 | $arrayOptions = array();
261 | } else if ($inValue && !$betweenDQuotes && !$betweenSQuotes && (($char == "\"") || ($char == "'"))) {
262 | // if inValue, a quote, and betweenQuote is false set betweenQuotes to true and empty buffer to kill spaces
263 | ($char == "\"") ? ($betweenDQuotes = true) : ($betweenSQuotes = true);
264 | } else if ($inValue && (($betweenDQuotes && ($char == "\"")) || ($betweenSQuotes && ($char == "'"))) && ($previousChar == "\\")) {
265 | // if inValue, a quote, betweenQuotes is true, and previous character is \ add to buffer
266 | $buffer .= $char;
267 | } else if ($inValue && (($betweenDQuotes && ($char == "\"")) || ($betweenSQuotes && ($char == "'")))) {
268 | // if inValue, a quote, betweenQuotes is true set betweenQuotes to false, save to parameters array, empty buffer, set inValue false
269 | $buffer = str_replace("\\\"","\"",$buffer);
270 | $buffer = str_replace('\\\'','\'',$buffer);
271 | if ($inArray) {
272 | $arrayOptions[trim($keyBuffer)] = trim($buffer);
273 | } else {
274 | $parameters[trim($keyBuffer)] = trim($buffer);
275 | }
276 | $buffer = "";
277 | $inValue = false;
278 | $betweenSQuotes = false;
279 | $betweenDQuotes = false;
280 | } else if ($inValue && !$betweenDQuotes && !$betweenSQuotes && ($char == ",")) {
281 | // if inValue, a comman, betweenQuotes is false, save to parameters array, empty buffer, set inValue false, set inKey true
282 | if ($inArray) {
283 | $arrayOptions[trim($keyBuffer)] = trim($buffer);
284 | } else {
285 | $parameters[trim($keyBuffer)] = trim($buffer);
286 | }
287 | $buffer = "";
288 | $inValue = false;
289 | $inKey = true;
290 | } else if ($inValue && (($i + 1) == $strLength)) {
291 | // if inValue and end of the string add to buffer, save to parameters array
292 | $buffer .= $char;
293 | if ($inArray) {
294 | $arrayOptions[trim($keyBuffer)] = trim($buffer);
295 | } else {
296 | $parameters[trim($keyBuffer)] = trim($buffer);
297 | }
298 | } else if ($inValue) {
299 | // if inValue add to buffer
300 | $buffer .= $char;
301 | } else if (!$inValue && !$inKey && ($char == ",")) {
302 | // if inValue is false, inKey false, and a comma set inKey true
303 | if ($inArray && !$inOption) {
304 | // don't do anything
305 | } else {
306 | $inKey = true;
307 | }
308 |
309 | }
310 | }
311 |
312 | return $parameters;
313 |
314 | }
315 |
316 |
317 | }
318 |
--------------------------------------------------------------------------------
/src/PatternLab/Saying.php:
--------------------------------------------------------------------------------
1 | <(((º>",
70 | "@}~}~~~",
71 | "(>'.')> (>'.')> (>'.')> ",
72 | "\(^-^)/",
73 | "you've been at this awhile; perhaps it's time for a walk outside?"
74 | );
75 |
76 | // grab user sayings
77 | $userSayings = Config::getOption("sayings");
78 | if (is_array($userSayings)) {
79 | $sayings = array_merge($sayings, $userSayings);
80 | }
81 |
82 | // i just didn't want to indent the crap above
83 | $this->sayings = $sayings;
84 |
85 | }
86 |
87 | /**
88 | * Randomly prints a saying after the generate is complete
89 | */
90 | public function say() {
91 |
92 | // set a color
93 | $colors = array("ok","options","info","warning");
94 | $randomNumber = rand(0,count($colors)-1);
95 | $color = (isset($colors[$randomNumber])) ? $colors[$randomNumber] : "desc";
96 |
97 | // set a 1 in 3 chance that a saying is printed
98 | $randomNumber = rand(0,(count($this->sayings)-1)*3);
99 | if (isset($this->sayings[$randomNumber])) {
100 | Console::writeLine("<".$color.">".$this->sayings[$randomNumber]."...".$color.">");
101 | }
102 |
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/src/PatternLab/Template.php:
--------------------------------------------------------------------------------
1 | ".Console::getHumanReadablePath($styleguideKitPath)."? you can fix this in ./config/config.yml by editing styleguideKitPath...");
51 | }
52 |
53 | // load pattern-lab's resources
54 | $partialPath = $styleguideKitPath.DIRECTORY_SEPARATOR."views".DIRECTORY_SEPARATOR."partials";
55 | $generalHeaderPath = $partialPath.DIRECTORY_SEPARATOR."general-header.".$patternExtension;
56 | $generalFooterPath = $partialPath.DIRECTORY_SEPARATOR."general-footer.".$patternExtension;
57 | self::$htmlHead = (file_exists($generalHeaderPath)) ? file_get_contents($generalHeaderPath) : "";
58 | self::$htmlFoot = (file_exists($generalFooterPath)) ? file_get_contents($generalFooterPath) : "";
59 |
60 | // gather the user-defined header and footer information
61 | $patternHeadPath = $metaDir.DIRECTORY_SEPARATOR."_00-head.".$patternExtension;
62 | $patternFootPath = $metaDir.DIRECTORY_SEPARATOR."_01-foot.".$patternExtension;
63 | self::$patternHead = (file_exists($patternHeadPath)) ? file_get_contents($patternHeadPath) : "";
64 | self::$patternFoot = (file_exists($patternFootPath)) ? file_get_contents($patternFootPath) : "";
65 |
66 | // add the filesystemLoader
67 | $patternEngineBasePath = PatternEngine::getInstance()->getBasePath();
68 | $filesystemLoaderClass = $patternEngineBasePath."\Loaders\FilesystemLoader";
69 |
70 | $options = array();
71 | $options["templatePath"] = $styleguideKitPath.DIRECTORY_SEPARATOR."views";
72 | $options["partialsPath"] = $options["templatePath"].DIRECTORY_SEPARATOR."partials";
73 |
74 | self::$filesystemLoader = new $filesystemLoaderClass($options);
75 |
76 | $stringLoaderClass = $patternEngineBasePath."\Loaders\StringLoader";
77 | self::$stringLoader = new $stringLoaderClass();
78 |
79 | // i can't remember why i chose to implement the pattern loader directly in classes
80 | // i figure i had a good reason which is why it's not showing up here
81 |
82 | }
83 |
84 | /*
85 | * Get the html header
86 | */
87 | public static function getHTMLHead() {
88 | return self::$htmlHead;
89 | }
90 |
91 | /*
92 | * Get the html foot
93 | */
94 | public static function getHTMLFoot() {
95 | return self::$htmlFoot;
96 | }
97 |
98 | /*
99 | * Get the pattern header
100 | */
101 | public static function getPatternHead() {
102 | return self::$patternHead;
103 | }
104 |
105 | /*
106 | * Get the pattern footer
107 | */
108 | public static function getPatternFoot() {
109 | return self::$patternFoot;
110 | }
111 |
112 | /*
113 | * Get the file system loader
114 | */
115 | public static function getFilesystemLoader() {
116 | return self::$filesystemLoader;
117 | }
118 |
119 | /*
120 | * Get the html loader
121 | */
122 | public static function getStringLoader() {
123 | return self::$stringLoader;
124 | }
125 |
126 | }
127 |
--------------------------------------------------------------------------------
/src/PatternLab/Timer.php:
--------------------------------------------------------------------------------
1 | ".$text." >> ";
41 | }
42 |
43 | // get the current time
44 | $checkTime = self::getTime();
45 |
46 | // get the data for the output
47 | $totalTime = ($checkTime - self::$startTime);
48 | $mem = round((memory_get_peak_usage(true)/1024)/1024,2);
49 |
50 | // figure out what tag to show
51 | $timeTag = "info";
52 | if (($checkTime - self::$checkTime) > 0.2) {
53 | $timeTag = "error";
54 | } else if (($checkTime - self::$checkTime) > 0.1) {
55 | $timeTag = "warning";
56 | }
57 |
58 | // set the checkTime for the next check comparison
59 | self::$checkTime = $checkTime;
60 |
61 | // write out time/mem stats
62 | Console::writeLine($insert."currently taken <".$timeTag.">".$totalTime."".$timeTag."> seconds and used ".$mem."MB of memory...");
63 |
64 | }
65 |
66 | /*
67 | * Get the time stamp
68 | */
69 | protected static function getTime() {
70 | $mtime = microtime();
71 | $mtime = explode(" ",$mtime);
72 | $mtime = $mtime[1] + $mtime[0];
73 | return $mtime;
74 | }
75 |
76 | /**
77 | * Start the timer
78 | */
79 | public static function start() {
80 |
81 | // get the current time
82 | self::$startTime = self::getTime();
83 |
84 | }
85 |
86 | /**
87 | * Stop the timer
88 | */
89 | public static function stop() {
90 |
91 | // make sure start time is set
92 | if (empty(self::$startTime)) {
93 | Console::writeError("the timer wasn't started...");
94 | }
95 |
96 | // get the current time
97 | $endTime = self::getTime();
98 |
99 | // get the data for the output
100 | $totalTime = ($endTime - self::$startTime);
101 | $mem = round((memory_get_peak_usage(true)/1024)/1024,2);
102 |
103 | // figure out what tag to show
104 | $timeTag = "info";
105 | if ($totalTime > 0.5) {
106 | $timeTag = "error";
107 | } else if ($totalTime > 0.3) {
108 | $timeTag = "warning";
109 | }
110 |
111 | // write out time/mem stats
112 | Console::writeLine("site generation took <".$timeTag.">".$totalTime."".$timeTag."> seconds and used ".$mem."MB of memory...");
113 |
114 | }
115 |
116 | }
117 |
--------------------------------------------------------------------------------
/src/PatternLab/Util.php:
--------------------------------------------------------------------------------
1 | options = array();
44 |
45 | }
46 |
47 | /**
48 | * Watch the source/ directory for any changes to existing files. Will run forever if given the chance.
49 | * @param {Boolean} decide if the reload server should be turned on
50 | * @param {Boolean} decide if static files like CSS and JS should be moved
51 | */
52 | public function watch($options = array()) {
53 |
54 | // double-checks options was properly set
55 | if (empty($options)) {
56 | Console::writeError("need to pass options to generate...");
57 | }
58 |
59 | // set default attributes
60 | $moveStatic = (isset($options["moveStatic"])) ? $options["moveStatic"] : true;
61 | $noCacheBuster = (isset($options["noCacheBuster"])) ? $options["noCacheBuster"] : false;
62 |
63 | // make sure a copy of the given options are saved for using when running generate
64 | $this->options = $options;
65 |
66 | // set-up the Dispatcher
67 | $dispatcherInstance = Dispatcher::getInstance();
68 | $dispatcherInstance->dispatch("watcher.start");
69 |
70 | if ($noCacheBuster) {
71 | Config::setOption("cacheBuster",0);
72 | }
73 |
74 | $c = false; // track that one loop through the pattern file listing has completed
75 | $o = new \stdClass(); // create an object to hold the properties
76 | $cp = new \stdClass(); // create an object to hold a clone of $o
77 |
78 | $o->patterns = new \stdClass();
79 |
80 | Console::writeLine("watching your site for changes...");
81 |
82 | // default vars
83 | $publicDir = Config::getOption("publicDir");
84 | $sourceDir = Config::getOption("sourceDir");
85 | $patternSourceDir = Config::getOption("patternSourceDir");
86 | $ignoreExts = Config::getOption("ie");
87 | $ignoreDirs = Config::getOption("id");
88 | $patternExt = Config::getOption("patternExtension");
89 |
90 | // build the file extensions based on the rules
91 | $fileExtensions = array();
92 | $patternRules = PatternData::getRules();
93 | foreach ($patternRules as $patternRule) {
94 | $extensions = $patternRule->getProp("extProp");
95 | if (strpos($extensions,"&&") !== false) {
96 | $extensions = explode("&&",$extensions);
97 | } else if (strpos($extensions,"||") !== false) {
98 | $extensions = explode("||",$extensions);
99 | } else {
100 | $extensions = array($extensions);
101 | }
102 | foreach ($extensions as $extension) {
103 | if (!in_array($extension, $fileExtensions)) {
104 | $fileExtensions[] = $extension;
105 | }
106 | }
107 | }
108 |
109 | // run forever
110 | while (true) {
111 |
112 | // clone the patterns so they can be checked in case something gets deleted
113 | $cp = clone $o->patterns;
114 |
115 | // iterate over the patterns & related data and regenerate the entire site if they've changed
116 | $patternObjects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($patternSourceDir), \RecursiveIteratorIterator::SELF_FIRST);
117 |
118 | // make sure dots are skipped
119 | $patternObjects->setFlags(\FilesystemIterator::SKIP_DOTS);
120 |
121 | foreach($patternObjects as $name => $object) {
122 |
123 | // clean-up the file name and make sure it's not one of the pattern lab files or to be ignored
124 | $fileName = str_replace($patternSourceDir.DIRECTORY_SEPARATOR,"",$name);
125 | $fileNameClean = str_replace(DIRECTORY_SEPARATOR."_",DIRECTORY_SEPARATOR,$fileName);
126 |
127 | if ($object->isFile() && in_array($object->getExtension(), $fileExtensions)) {
128 |
129 | // make sure this isn't a hidden pattern
130 | $patternParts = explode(DIRECTORY_SEPARATOR,$fileName);
131 | $pattern = isset($patternParts[2]) ? $patternParts[2] : $patternParts[1];
132 |
133 | // make sure the pattern still exists in source just in case it's been deleted during the iteration
134 | if (file_exists($name)) {
135 |
136 | $mt = $object->getMTime();
137 | if (isset($o->patterns->$fileName) && ($o->patterns->$fileName != $mt)) {
138 | $o->patterns->$fileName = $mt;
139 | $this->updateSite($fileName,"changed");
140 | } else if (!isset($o->patterns->$fileName) && $c) {
141 | $o->patterns->$fileName = $mt;
142 | $this->updateSite($fileName,"added");
143 | if ($object->getExtension() == $patternExt) {
144 | $patternSrcPath = str_replace(".".$patternExt,"",$fileName);
145 | $patternDestPath = str_replace("/","-",$patternSrcPath);
146 | $render = ($pattern[0] != "_") ? true : false;
147 | $this->patternPaths[$patternParts[0]][$pattern] = array("patternSrcPath" => $patternSrcPath, "patternDestPath" => $patternDestPath, "render" => $render);
148 | }
149 | } else if (!isset($o->patterns->$fileName)) {
150 | $o->patterns->$fileName = $mt;
151 | }
152 |
153 | if ($c && isset($o->patterns->$fileName)) {
154 | unset($cp->$fileName);
155 | }
156 |
157 | } else {
158 |
159 | // the file was removed during the iteration so remove references to the item
160 | unset($o->patterns->$fileName);
161 | unset($cp->$fileName);
162 | unset($this->patternPaths[$patternParts[0]][$pattern]);
163 | $this->updateSite($fileName,"removed");
164 |
165 | }
166 |
167 | }
168 |
169 | }
170 |
171 | // make sure old entries are deleted
172 | // will throw "pattern not found" errors if an entire directory is removed at once but that shouldn't be a big deal
173 | if ($c) {
174 |
175 | foreach($cp as $fileName => $mt) {
176 |
177 | unset($o->patterns->$fileName);
178 | $patternParts = explode(DIRECTORY_SEPARATOR,$fileName);
179 | $pattern = isset($patternParts[2]) ? $patternParts[2] : $patternParts[1];
180 |
181 | unset($this->patternPaths[$patternParts[0]][$pattern]);
182 | $this->updateSite($fileName,"removed");
183 |
184 | }
185 |
186 | }
187 |
188 | // iterate over annotations, data, meta and any other _ dirs
189 | $watchDirs = glob($sourceDir.DIRECTORY_SEPARATOR."_*",GLOB_ONLYDIR);
190 | foreach ($watchDirs as $watchDir) {
191 |
192 | if ($watchDir != $patternSourceDir) {
193 |
194 | // iterate over the data files and regenerate the entire site if they've changed
195 | $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($watchDir), \RecursiveIteratorIterator::SELF_FIRST);
196 |
197 | // make sure dots are skipped
198 | $objects->setFlags(\FilesystemIterator::SKIP_DOTS);
199 |
200 | foreach($objects as $name => $object) {
201 |
202 | $fileName = str_replace($sourceDir.DIRECTORY_SEPARATOR,"",$name);
203 | $mt = $object->getMTime();
204 |
205 | if (!isset($o->$fileName)) {
206 | $o->$fileName = $mt;
207 | if ($c) {
208 | $this->updateSite($fileName,"added");
209 | }
210 | } else if ($o->$fileName != $mt) {
211 | $o->$fileName = $mt;
212 | if ($c) {
213 | $this->updateSite($fileName,"changed");
214 | }
215 | }
216 |
217 | }
218 |
219 | }
220 |
221 | }
222 |
223 | // iterate over all of the other files in the source directory and move them if their modified time has changed
224 | if ($moveStatic) {
225 |
226 | $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($sourceDir.DIRECTORY_SEPARATOR), \RecursiveIteratorIterator::SELF_FIRST);
227 |
228 | // make sure dots are skipped
229 | $objects->setFlags(\FilesystemIterator::SKIP_DOTS);
230 |
231 | foreach($objects as $name => $object) {
232 |
233 | // clean-up the file name and make sure it's not one of the pattern lab files or to be ignored
234 | $fileName = str_replace($sourceDir.DIRECTORY_SEPARATOR,"",$name);
235 | if (($fileName[0] != "_") && (!in_array($object->getExtension(),$ignoreExts)) && (!in_array($object->getFilename(),$ignoreDirs))) {
236 |
237 | // catch directories that have the ignored dir in their path
238 | $ignoreDir = FileUtil::ignoreDir($fileName);
239 |
240 | // check to see if it's a new directory
241 | if (!$ignoreDir && $object->isDir() && !isset($o->$fileName) && !is_dir($publicDir."/".$fileName)) {
242 | mkdir($publicDir."/".$fileName);
243 | $o->$fileName = "dir created"; // placeholder
244 | Console::writeLine($fileName."/ directory was created...");
245 | }
246 |
247 | // check to see if it's a new file or a file that has changed
248 | if (file_exists($name)) {
249 |
250 | $mt = $object->getMTime();
251 | if (!$ignoreDir && $object->isFile() && !isset($o->$fileName) && !file_exists($publicDir."/".$fileName)) {
252 | $o->$fileName = $mt;
253 | FileUtil::moveStaticFile($fileName,"added");
254 | if ($object->getExtension() == "css") {
255 | $this->updateSite($fileName,"changed",0); // make sure the site is updated for MQ reasons
256 | }
257 | } else if (!$ignoreDir && $object->isFile() && isset($o->$fileName) && ($o->$fileName != $mt)) {
258 | $o->$fileName = $mt;
259 | FileUtil::moveStaticFile($fileName,"changed");
260 | if ($object->getExtension() == "css") {
261 | $this->updateSite($fileName,"changed",0); // make sure the site is updated for MQ reasons
262 | }
263 | } else if (!isset($o->fileName)) {
264 | $o->$fileName = $mt;
265 | }
266 |
267 | } else {
268 | unset($o->$fileName);
269 | }
270 |
271 | }
272 |
273 | }
274 |
275 | }
276 |
277 |
278 | $c = true;
279 |
280 | // taking out the garbage. basically killing mustache after each run.
281 | if (gc_enabled()) gc_collect_cycles();
282 |
283 | // pause for .05 seconds to give the CPU a rest
284 | usleep(50000);
285 |
286 | }
287 |
288 | }
289 |
290 | /**
291 | * Updates the Pattern Lab Website and prints the appropriate message
292 | * @param {String} file name to included in the message
293 | * @param {String} a switch for decided which message isn't printed
294 | *
295 | * @return {String} the final message
296 | */
297 | private function updateSite($fileName,$message,$verbose = true) {
298 |
299 | $watchMessage = "";
300 | if ($verbose) {
301 | if ($message == "added") {
302 | $watchMessage = "".$fileName." was added to Pattern Lab. reload the website to see this change in the navigation...";
303 | } elseif ($message == "removed") {
304 | $watchMessage = "".$fileName." was removed from Pattern Lab. reload the website to see this change reflected in the navigation...";
305 | } elseif ($message == "hidden") {
306 | $watchMessage = "".$fileName." was hidden from Pattern Lab. reload the website to see this change reflected in the navigation...";
307 | } else {
308 | $watchMessage = "".$fileName." changed...";
309 | }
310 | }
311 |
312 | $options = $this->options;
313 |
314 | $options["watchVerbose"] = $verbose;
315 | $options["watchMessage"] = $watchMessage;
316 | $options["moveStatic"] = false;
317 |
318 | // clear the various data stores for re-population
319 | Data::clear();
320 | PatternData::clear();
321 | Annotations::clear();
322 |
323 | $g = new Generator();
324 | $g->generate($options);
325 |
326 | }
327 |
328 | protected function starterKitPathPrompt() {
329 |
330 | // need to figure this out long-term
331 | InstallerUtil::$isInteractive = true;
332 | $input = Console::promptInput("Tell me the path to the starterkit you want to watch.","e.g. vendor/pattern-lab/starterkit-mustache-demo/dist","baz",false);
333 |
334 | // set-up the full starterkit path
335 | $starterKitPath = Config::getOption("baseDir").$input;
336 | if (!is_dir($starterKitPath)) {
337 | Console::writeWarning("that doesn't seem to be a real directory. let's try again...");
338 | $starterKitPath = $this->starterKitPathPrompt();
339 | }
340 |
341 | return $starterKitPath;
342 |
343 | }
344 |
345 | public function watchStarterKit() {
346 |
347 | // default vars
348 | $starterKitPath = $this->starterKitPathPrompt();
349 | $sourceDir = Config::getOption("sourceDir");
350 |
351 | $fs = new Filesystem();
352 |
353 | $c = false; // track that one loop through the pattern file listing has completed
354 | $o = new \stdClass(); // create an object to hold the properties
355 | $cp = new \stdClass(); // create an object to hold a clone of $o
356 |
357 | $o->patterns = new \stdClass();
358 |
359 | Console::writeLine("watching your starterkit for changes...");
360 |
361 | // run forever
362 | while (true) {
363 |
364 | // clone the patterns so they can be checked in case something gets deleted
365 | $cp = clone $o->patterns;
366 |
367 | $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($starterKitPath), \RecursiveIteratorIterator::SELF_FIRST);
368 |
369 | // make sure dots are skipped
370 | $objects->setFlags(\FilesystemIterator::SKIP_DOTS);
371 |
372 | foreach ($objects as $name => $object) {
373 |
374 | // clean-up the file name and make sure it's not one of the pattern lab files or to be ignored
375 | $fileName = str_replace($starterKitPath.DIRECTORY_SEPARATOR,"",$name);
376 |
377 | // check to see if it's a new directory
378 | if ($object->isDir() && !isset($o->$fileName) && !is_dir($starterKitPath."/".$fileName)) {
379 | mkdir($sourceDir."/".$fileName);
380 | $o->$fileName = "dir created"; // placeholder
381 | Console::writeLine($fileName."/ directory was created...");
382 | }
383 |
384 | // check to see if it's a new file or a file that has changed
385 | if (file_exists($name)) {
386 |
387 | $mt = $object->getMTime();
388 | if ($object->isFile() && !isset($o->$fileName) && !file_exists($sourceDir.DIRECTORY_SEPARATOR.$fileName)) {
389 | $o->$fileName = $mt;
390 | $fs->copy($starterKitPath.DIRECTORY_SEPARATOR.$fileName,$sourceDir.DIRECTORY_SEPARATOR.$fileName);
391 | Console::writeInfo($fileName." added...");
392 | } else if ($object->isFile() && isset($o->$fileName) && ($o->$fileName != $mt)) {
393 | $o->$fileName = $mt;
394 | $fs->copy($starterKitPath.DIRECTORY_SEPARATOR.$fileName,$sourceDir.DIRECTORY_SEPARATOR.$fileName);
395 | Console::writeInfo($fileName." changed...");
396 | } else if (!isset($o->fileName)) {
397 | $o->$fileName = $mt;
398 | }
399 |
400 | } else {
401 | unset($o->$fileName);
402 | }
403 |
404 | }
405 |
406 | $c = true;
407 |
408 | // taking out the garbage. basically killing mustache after each run.
409 | if (gc_enabled()) gc_collect_cycles();
410 |
411 | // pause for .05 seconds to give the CPU a rest
412 | usleep(50000);
413 |
414 | }
415 |
416 | }
417 |
418 | }
419 |
--------------------------------------------------------------------------------
/src/PatternLab/Zippy/UnpackAdapter.php:
--------------------------------------------------------------------------------
1 | container = AdapterContainer::load();
24 | }
25 |
26 | public function getAdapters() {
27 | return array(UnpackAdapter::newInstance($this->container['executable-finder'],$this->container['resource-manager'],$this->container['gnu-tar.inflator'],$this->container['gnu-tar.deflator']));
28 | }
29 |
30 | public function getFileExtension() {
31 | return 'tar.gz';
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------