@penskemediacorp/larva 1.2.0-alpha.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) hide show
  1. package/.eslintignore +6 -0
  2. package/LICENSE +21 -0
  3. package/README.md +119 -4
  4. package/__tests__/fixtures/build/css/common.inline.css +1 -0
  5. package/__tests__/fixtures/build/images/test.png +0 -0
  6. package/__tests__/fixtures/build/js/larva-ui.js +1 -0
  7. package/__tests__/fixtures/build/svg/defs/sprite.svg +1 -0
  8. package/__tests__/fixtures/larva.config.js +43 -0
  9. package/__tests__/fixtures/public/some-library.js +1 -0
  10. package/__tests__/fixtures/src/patterns/__tests__/.gitkeep +0 -0
  11. package/__tests__/fixtures/src/patterns/components/c-nav-link/c-nav-link.featured.aia.js +3 -0
  12. package/__tests__/fixtures/src/patterns/components/c-nav-link/c-nav-link.featured.js +3 -0
  13. package/__tests__/fixtures/src/patterns/components/c-nav-link/c-nav-link.js +1 -0
  14. package/__tests__/fixtures/src/patterns/components/c-nav-link/c-nav-link.json +3 -0
  15. package/__tests__/fixtures/src/patterns/components/c-nav-link/c-nav-link.prototype.js +3 -0
  16. package/__tests__/fixtures/src/patterns/components/c-nav-link/c-nav-link.twig +3 -0
  17. package/__tests__/fixtures/src/patterns/components/c-tagline/c-tagline.prototype.js +3 -0
  18. package/__tests__/fixtures/src/patterns/modules/_also-ignored/_also-ignored.prototype.js +3 -0
  19. package/__tests__/fixtures/src/patterns/modules/_also-ignored/_also-ignored.twig +3 -0
  20. package/__tests__/fixtures/src/patterns/modules/ignore-me/ignore-me.prototype.js +0 -0
  21. package/__tests__/fixtures/src/patterns/modules/ignore-me/ignore-me.twig +0 -0
  22. package/__tests__/fixtures/src/patterns/modules/test-module/test-module.featured.js +3 -0
  23. package/__tests__/fixtures/src/patterns/modules/test-module/test-module.prototype.js +3 -0
  24. package/__tests__/fixtures/src/patterns/modules/test-module/test-module.twig +0 -0
  25. package/__tests__/fixtures/src/patterns/objects/_objects.scss +0 -0
  26. package/__tests__/fixtures/src/patterns/objects/o-crap/o-crap.json +3 -0
  27. package/__tests__/fixtures/src/patterns/objects/o-crap/o-crap.scss +0 -0
  28. package/__tests__/fixtures/src/patterns/objects/o-crap/o-crap.twig +1 -0
  29. package/__tests__/fixtures/src/patterns/objects/o-nav/o-nav.twig +14 -0
  30. package/__tests__/fixtures/src/patterns/one-offs/newswire/newswire.html +1 -0
  31. package/__tests__/fixtures/src/patterns/one-offs/newswire/newswire.prototype.js +3 -0
  32. package/__tests__/fixtures/template-parts/some-template.php +3 -0
  33. package/__tests__/lib/generateStatic.test.js +140 -0
  34. package/__tests__/lib/utils/clonePatternData.test.js +23 -0
  35. package/__tests__/lib/utils/getAllPatternsObj.test.js +45 -0
  36. package/__tests__/lib/utils/getAppConfiguration.test.js +13 -0
  37. package/__tests__/lib/utils/getModuleNamesFromDirectory.test.js +23 -0
  38. package/__tests__/lib/utils/getPatternData.test.js +55 -0
  39. package/__tests__/lib/utils/getPatternPathsToLoad.test.js +13 -0
  40. package/__tests__/lib/utils/getPatternRoutes.test.js +29 -0
  41. package/__tests__/lib/utils/getPatternType.test.js +16 -0
  42. package/__tests__/lib/utils/getPatternVariants.test.js +20 -0
  43. package/__tests__/lib/utils/getPatternsIndexPath.test.js +9 -0
  44. package/__tests__/lib/utils/getSubDirectoryNames.test.js +17 -0
  45. package/__tests__/lib/utils/isCoreTheme.test.js +12 -0
  46. package/__tests__/lib/utils/writeJsonToFile.test.js +29 -0
  47. package/__tests__/lib/writeJson.test.js +83 -0
  48. package/bin/larva.js +25 -0
  49. package/build/css/larva-important.css +1 -0
  50. package/build/css/larva-ui.css +1 -0
  51. package/build/css/larva.css +1 -0
  52. package/build/css/larva.inline-important.css +1 -0
  53. package/build/css/larva.inline.css +1 -0
  54. package/build/css/variety.compat-important.css +1 -0
  55. package/build/css/variety.compat.css +1 -0
  56. package/build/js/common.js +26 -0
  57. package/build/js/larva-ui.js +1 -0
  58. package/build/js/standalone/video-showcase.js +26 -0
  59. package/build/svg/brand-logo-white.svg +1 -0
  60. package/build/svg/brand-logo.svg +1 -0
  61. package/build/svg/defs/sprite.defs.html +852 -0
  62. package/build/svg/defs/sprite.defs.svg +1 -0
  63. package/build/tokens/artinamerica.custom-properties.css +546 -0
  64. package/build/tokens/artinamerica.json +533 -0
  65. package/build/tokens/artinamerica.map.scss +546 -0
  66. package/build/tokens/artinamerica.raw.json +4341 -0
  67. package/build/tokens/artnews.custom-properties.css +550 -0
  68. package/build/tokens/artnews.json +536 -0
  69. package/build/tokens/artnews.map.scss +550 -0
  70. package/build/tokens/artnews.raw.json +4373 -0
  71. package/build/tokens/bbpro.custom-properties.css +96 -0
  72. package/build/tokens/bbpro.json +80 -0
  73. package/build/tokens/bbpro.map.scss +96 -0
  74. package/build/tokens/bbpro.raw.json +789 -0
  75. package/build/tokens/billboard.custom-properties.css +96 -0
  76. package/build/tokens/billboard.json +80 -0
  77. package/build/tokens/billboard.map.scss +96 -0
  78. package/build/tokens/billboard.raw.json +789 -0
  79. package/build/tokens/deadline.custom-properties.css +533 -0
  80. package/build/tokens/deadline.json +517 -0
  81. package/build/tokens/deadline.map.scss +533 -0
  82. package/build/tokens/deadline.raw.json +4204 -0
  83. package/build/tokens/default.custom-properties.css +533 -0
  84. package/build/tokens/default.json +517 -0
  85. package/build/tokens/default.map.scss +533 -0
  86. package/build/tokens/default.raw.json +4204 -0
  87. package/build/tokens/dirt.custom-properties.css +81 -0
  88. package/build/tokens/dirt.json +66 -0
  89. package/build/tokens/dirt.map.scss +81 -0
  90. package/build/tokens/dirt.raw.json +690 -0
  91. package/build/tokens/indiewire.custom-properties.css +536 -0
  92. package/build/tokens/indiewire.json +520 -0
  93. package/build/tokens/indiewire.map.scss +536 -0
  94. package/build/tokens/indiewire.raw.json +4221 -0
  95. package/build/tokens/rivet.custom-properties.css +82 -0
  96. package/build/tokens/rivet.json +68 -0
  97. package/build/tokens/rivet.map.scss +82 -0
  98. package/build/tokens/rivet.raw.json +703 -0
  99. package/build/tokens/robbreport.custom-properties.css +536 -0
  100. package/build/tokens/robbreport.json +518 -0
  101. package/build/tokens/robbreport.map.scss +536 -0
  102. package/build/tokens/robbreport.raw.json +4215 -0
  103. package/build/tokens/rollingstone-2022.custom-properties.css +534 -0
  104. package/build/tokens/rollingstone-2022.json +519 -0
  105. package/build/tokens/rollingstone-2022.map.scss +534 -0
  106. package/build/tokens/rollingstone-2022.raw.json +4035 -0
  107. package/build/tokens/rollingstone.custom-properties.css +530 -0
  108. package/build/tokens/rollingstone.json +518 -0
  109. package/build/tokens/rollingstone.map.scss +530 -0
  110. package/build/tokens/rollingstone.raw.json +4207 -0
  111. package/build/tokens/sheknows.custom-properties.css +92 -0
  112. package/build/tokens/sheknows.json +76 -0
  113. package/build/tokens/sheknows.map.scss +92 -0
  114. package/build/tokens/sheknows.raw.json +761 -0
  115. package/build/tokens/sourcingjournal.custom-properties.css +87 -0
  116. package/build/tokens/sourcingjournal.json +70 -0
  117. package/build/tokens/sourcingjournal.map.scss +87 -0
  118. package/build/tokens/sourcingjournal.raw.json +720 -0
  119. package/build/tokens/sportico.custom-properties.css +73 -0
  120. package/build/tokens/sportico.json +59 -0
  121. package/build/tokens/sportico.map.scss +73 -0
  122. package/build/tokens/sportico.raw.json +640 -0
  123. package/build/tokens/thr.custom-properties.css +83 -0
  124. package/build/tokens/thr.json +67 -0
  125. package/build/tokens/thr.map.scss +83 -0
  126. package/build/tokens/thr.raw.json +698 -0
  127. package/build/tokens/variety-compat.custom-properties.css +36 -0
  128. package/build/tokens/variety-compat.json +33 -0
  129. package/build/tokens/variety-compat.map.scss +36 -0
  130. package/build/tokens/variety-compat.raw.json +224 -0
  131. package/build/tokens/variety-vip.custom-properties.css +532 -0
  132. package/build/tokens/variety-vip.json +521 -0
  133. package/build/tokens/variety-vip.map.scss +532 -0
  134. package/build/tokens/variety-vip.raw.json +4223 -0
  135. package/build/tokens/variety.custom-properties.css +534 -0
  136. package/build/tokens/variety.json +521 -0
  137. package/build/tokens/variety.map.scss +534 -0
  138. package/build/tokens/variety.raw.json +4225 -0
  139. package/build/tokens/vibe.custom-properties.css +77 -0
  140. package/build/tokens/vibe.json +63 -0
  141. package/build/tokens/vibe.map.scss +77 -0
  142. package/build/tokens/vibe.raw.json +668 -0
  143. package/build/tokens/wwd-2021.custom-properties.css +82 -0
  144. package/build/tokens/wwd-2021.json +67 -0
  145. package/build/tokens/wwd-2021.map.scss +82 -0
  146. package/build/tokens/wwd-2021.raw.json +701 -0
  147. package/build/tokens/wwd-beauty.custom-properties.css +86 -0
  148. package/build/tokens/wwd-beauty.json +70 -0
  149. package/build/tokens/wwd-beauty.map.scss +86 -0
  150. package/build/tokens/wwd-beauty.raw.json +719 -0
  151. package/build/tokens/wwd-dd.custom-properties.css +18 -0
  152. package/build/tokens/wwd-dd.json +13 -0
  153. package/build/tokens/wwd-dd.map.scss +18 -0
  154. package/build/tokens/wwd-dd.raw.json +90 -0
  155. package/build/tokens/wwd.custom-properties.css +70 -0
  156. package/build/tokens/wwd.json +60 -0
  157. package/build/tokens/wwd.map.scss +70 -0
  158. package/build/tokens/wwd.raw.json +643 -0
  159. package/index.js +7 -0
  160. package/lib/generateStatic.js +133 -0
  161. package/lib/server.js +284 -0
  162. package/lib/start.js +7 -0
  163. package/lib/utils/clonePatternData.js +13 -0
  164. package/lib/utils/copySyncHelper.js +33 -0
  165. package/lib/utils/getAllPatternsObj.js +48 -0
  166. package/lib/utils/getAppConfiguration.js +82 -0
  167. package/lib/utils/getArgsFromCli.js +3 -0
  168. package/lib/utils/getModuleNamesFromDirectory.js +11 -0
  169. package/lib/utils/getPatternData.js +34 -0
  170. package/lib/utils/getPatternPathsToLoad.js +20 -0
  171. package/lib/utils/getPatternRoutes.js +58 -0
  172. package/lib/utils/getPatternType.js +15 -0
  173. package/lib/utils/getPatternVariants.js +24 -0
  174. package/lib/utils/getPatternsIndexPath.js +11 -0
  175. package/lib/utils/getSubDirectoryNames.js +23 -0
  176. package/lib/utils/isCoreTheme.js +8 -0
  177. package/lib/utils/renderSass.js +20 -0
  178. package/lib/utils/spawnScript.js +26 -0
  179. package/lib/utils/writeJsonToFile.js +6 -0
  180. package/lib/writeJson.js +53 -0
  181. package/package.json +72 -5
  182. package/public/webfontloader.js +22 -0
  183. package/scripts/build-html.js +52 -0
  184. package/scripts/build-icons.js +80 -0
  185. package/scripts/build-scss.js +15 -0
  186. package/scripts/config/.eslintrc.json +11 -0
  187. package/scripts/config/gulpfile.js +191 -0
  188. package/scripts/config/stylelint.config.js +5 -0
  189. package/scripts/config/svgo-config.json +67 -0
  190. package/scripts/config/webpack.config.js +95 -0
  191. package/scripts/dev-js.js +13 -0
  192. package/scripts/dev-scss.js +20 -0
  193. package/scripts/help.js +65 -0
  194. package/scripts/init.js +21 -0
  195. package/scripts/larva/.nvmrc +1 -0
  196. package/scripts/larva/README.md +29 -0
  197. package/scripts/larva/larva.config.js +3 -0
  198. package/scripts/larva/src/patterns/README.md +3 -0
  199. package/scripts/larva/src/patterns/base.html +6 -0
  200. package/scripts/larva/src/patterns/components/README.md +3 -0
  201. package/scripts/larva/src/patterns/modules/README.md +3 -0
  202. package/scripts/larva/src/patterns/objects/README.md +3 -0
  203. package/scripts/larva/src/patterns/one-offs/README.md +3 -0
  204. package/scripts/link-all.js +40 -0
  205. package/scripts/lint-js.js +11 -0
  206. package/scripts/lint-scss.js +13 -0
  207. package/scripts/lint.js +73 -0
  208. package/scripts/prod-js.js +12 -0
  209. package/scripts/prod-scss.js +24 -0
  210. package/scripts/prod.js +122 -0
  211. package/scripts/server.js +11 -0
  212. package/scripts/start.js +36 -0
  213. package/scripts/upgrade.js +99 -0
  214. package/scripts/write-json.js +14 -0
  215. package/.DS_Store +0 -0
  216. package/__tests__/larva.test.js +0 -7
  217. package/lib/larva.js +0 -7
  218. package/lib/patterns.js +0 -48
  219. package/setup.scss +0 -1
  220. package/src/02-generic/breakpoint-label.scss +0 -33
  221. package/src/06-algorithms/a-glue/a-glue.html +0 -4
  222. package/src/06-algorithms/a-glue/a-glue.scss +0 -56
  223. package/src/06-algorithms/a-glue/index.js +0 -1
  224. package/src/06-algorithms/a-grid.scss +0 -29
  225. package/src/07-utilities/u-background.scss +0 -5
  226. package/src/07-utilities/u-color.scss +0 -5
  227. package/src/07-utilities/u-crop.scss +0 -5
  228. package/src/07-utilities/u-flex.scss +0 -35
  229. package/src/07-utilities/u-margin.scss +0 -5
  230. package/src/07-utilities/u-padding.scss +0 -5
  231. package/src/07-utilities/u-text.scss +0 -33
  232. package/src/07-utilities/utilities.scss +0 -5
  233. package/static/css/components.css +0 -4
  234. package/static/css/objects.css +0 -21
  235. package/static/css/prism.css +0 -126
  236. package/static/js/prism.js +0 -8
@@ -0,0 +1,133 @@
1
+ const path = require( 'path' );
2
+ const mkdirp = require( 'mkdirp' );
3
+ const fs = require( 'fs-extra' );
4
+ const chalk = require( 'chalk' );
5
+ const axios = require( 'axios' );
6
+
7
+ const getAppConfiguration = require( './utils/getAppConfiguration' );
8
+ const copySyncHelper = require( './utils/copySyncHelper' );
9
+
10
+ const assetsConfig = getAppConfiguration( 'assets' );
11
+ const themeAssetsConfig = getAppConfiguration( 'themeAssets' );
12
+
13
+ /**
14
+ * Generate Static HTML
15
+ *
16
+ * Given an array of pattern routes from the Larva server and
17
+ * a target build directory, use HTTP requests the get the HTML content
18
+ * of each route, and write the content to directory structure that
19
+ * mirrors the pattern routes.
20
+ *
21
+ * @param {array} routesArr An array of routes in a pattern server, excluding the pattern source (i.e. larva or project).
22
+ * This is the result of getPatternRoutes.
23
+ * @param {string} buildPath A directory where the HTML files should be written.
24
+ * @param {function} done A callback function to run when the site generation completes.
25
+ * @param {string} urlBase The base URL for the pattern library e.g. 'http://localhost:3001/larva'.
26
+ * Pattern routes will be appended to this. Should not end in slash.
27
+ *
28
+ * @see {@link getPatternRoutes}.
29
+ */
30
+
31
+
32
+ module.exports = function generateStatic( routesArr, buildPath, done, urlBase = 'http://localhost:3000/larva' ) {
33
+ const errors = [];
34
+
35
+ fs.mkdirpSync( buildPath );
36
+
37
+ // Copy assets from assets/build and assets/public
38
+ // to the static site build directory.
39
+ console.log( '\nCopying assets...\n')
40
+
41
+ // assets/public dir contains fonts and non-built things.
42
+ const publicAssetsSrc = ( () => {
43
+ let pubPath = path.join( assetsConfig.path, `public` );
44
+
45
+ // Fallback to assets in Larva
46
+ if ( ! fs.existsSync( pubPath ) ) {
47
+ pubPath = path.join( assetsConfig.path, 'public' )
48
+ }
49
+
50
+ return pubPath;
51
+ })();
52
+ const publicAssetsDest = path.join( buildPath, '../assets/public' );
53
+
54
+ const builtAssets = [
55
+ 'js',
56
+ 'css',
57
+ 'tokens',
58
+ 'images',
59
+ 'svg'
60
+ ];
61
+
62
+ builtAssets.forEach( item => {
63
+ const dest = path.join( buildPath, `../assets/build/${item}` );
64
+ const src = path.join( assetsConfig.path, `build/${item}` );
65
+
66
+ copySyncHelper( src, dest );
67
+ });
68
+
69
+ copySyncHelper( publicAssetsSrc, publicAssetsDest );
70
+
71
+ const themeAssetKeys = Object.keys( themeAssetsConfig );
72
+
73
+ themeAssetKeys.forEach( key => {
74
+ const src = themeAssetsConfig[key];
75
+ const dest = path.join( buildPath, `../assets/theme/${key}` );
76
+
77
+ copySyncHelper( src, dest );
78
+ });
79
+
80
+ // Build the site.
81
+ // Cycle through the list of routes and write the response
82
+ // to files.
83
+ console.log( '\nBuilding site...\n');
84
+
85
+ try {
86
+
87
+ const promises = routesArr.map( ( route ) => {
88
+
89
+ const dir = path.join( buildPath, route );
90
+ const url = `${urlBase}/${route}`;
91
+
92
+ return axios.get( url ).then( ( response ) => {
93
+
94
+ if ( 200 === response.status ) {
95
+ mkdirp.sync( dir );
96
+ fs.writeFileSync( `${dir}/index.html`, response.data );
97
+ console.log( `Built ${route}.` );
98
+ }
99
+
100
+ } ).catch( ( e ) => {
101
+
102
+ if ( 'ECONNREFUSED' === e.code ) {
103
+ process.exitCode = 1;
104
+ } else {
105
+ mkdirp.sync( dir );
106
+ fs.writeFileSync( `${dir}/index.html`, e.message );
107
+
108
+ console.log( chalk.yellow( `Error writing ${route}: ${e.message}.` ) );
109
+ }
110
+
111
+ });
112
+
113
+ } );
114
+
115
+ axios.all( promises ).then( () => {
116
+
117
+ if ( errors.length > 0 ) {
118
+ console.log( errors );
119
+ }
120
+
121
+ done( chalk.green( `\nSite built to build/html/${path.basename( buildPath )}. Check output for issues.\n` ) );
122
+
123
+ } ).catch( ( e ) => {
124
+
125
+ done( chalk.bold.red( e ) );
126
+
127
+ });
128
+
129
+ } catch ( e ) {
130
+ console.error( e );
131
+ }
132
+
133
+ }
package/lib/server.js ADDED
@@ -0,0 +1,284 @@
1
+ const path = require( 'path' );
2
+ const express = require('express');
3
+ const { marked } = require( 'marked' );
4
+ const fs = require( 'fs' );
5
+ const globby = require( 'globby' );
6
+
7
+ const {
8
+ TwingEnvironment,
9
+ TwingLoaderFilesystem,
10
+ TwingFilter,
11
+ TwingFunction
12
+ } = require('twing');
13
+
14
+ const fontData = require( '../../larva-tokens/lib/font-data' );
15
+
16
+ const getAppConfiguration = require('./utils/getAppConfiguration' );
17
+ const getPatternPathsToLoad = require( './utils/getPatternPathsToLoad' );
18
+ const getPatternData = require( './utils/getPatternData' );
19
+ const getAllPatternsObj = require( './utils/getAllPatternsObj' );
20
+
21
+ const app = express();
22
+
23
+ const patternConfig = getAppConfiguration( 'patterns' );
24
+ const brandConfig = getAppConfiguration( 'brand' );
25
+ const assetsConfig = getAppConfiguration( 'assets' );
26
+ const themeAssetsConfig = getAppConfiguration( 'themeAssets' );
27
+ const twigPaths = getPatternPathsToLoad( patternConfig );
28
+
29
+ let loader = new TwingLoaderFilesystem( twigPaths );
30
+
31
+ // Add markdown filter
32
+ const markdownFilter = new TwingFilter( 'markdown', ( string ) => {
33
+ if ( string ) {
34
+ return Promise.resolve( marked( string ) );
35
+ } else {
36
+ const noDocsMessage = '**This needs docs!** <br>Create a README.md in the pattern\'s directory and add details about using this pattern in markdown.';
37
+
38
+ return Promise.resolve( marked( noDocsMessage ) );
39
+ }
40
+ });
41
+
42
+ // Support `{{ item|markup }}` syntax for outputting escaped content within loops.
43
+ const markupFilter = new TwingFilter(
44
+ 'markup',
45
+ ( string ) => Promise.resolve( string ),
46
+ {},
47
+ { is_safe: ['html'] }
48
+ );
49
+
50
+ const kebabify = ( name ) => {
51
+ let kebabCase = [];
52
+
53
+ // TODO: find a more concise way of turning a string into an iterable
54
+ for (let i = 0; i < name.length; i++) {
55
+ let letter = name[i];
56
+ kebabCase[i] = letter;
57
+ }
58
+
59
+ return kebabCase.reduce( ( a, b ) => {
60
+ if ( '_' === b ) {
61
+ return a.toLowerCase() + '-';
62
+ }
63
+ return a.toLowerCase() + b.toLowerCase();
64
+ });
65
+ };
66
+
67
+ // TODO: Could be an array/iterator if the namespace can be extracted from the key, the larva.config API could
68
+ // change to `patterns: { larva: /larva/path/here/, project: /project/path/here }`
69
+ loader.addPath( patternConfig.larvaPatternsDir, 'larva' );
70
+
71
+ if( fs.existsSync( patternConfig.projectPatternsDir ) ) {
72
+ loader.addPath( patternConfig.projectPatternsDir, 'project' );
73
+ }
74
+
75
+ let twing = new TwingEnvironment( loader, { debug: true } );
76
+
77
+ twing.addFilter( markdownFilter );
78
+ twing.addFilter( markupFilter );
79
+
80
+ // Add custom function support for doing wp action: {{ wp_action( ... ) }}
81
+ twing.addFunction(new TwingFunction('wp_action',() => {
82
+ // We're relying on twig-to-php-parser for translation, so just return empty string for now
83
+ return Promise.resolve('');
84
+ }));
85
+
86
+ let patterns = {
87
+ larva: getAllPatternsObj( patternConfig.larvaPatternsDir ),
88
+ project: getAllPatternsObj( patternConfig.projectPatternsDir )
89
+ };
90
+
91
+ // Use the project version if it exists, else use the larva version
92
+ if ( fs.existsSync( assetsConfig.path ) ) {
93
+ app.use( '/assets' , express.static( assetsConfig.path ) );
94
+ }
95
+
96
+ // Expose any theme directories with assets in the express server
97
+ const themeAssetKeys = Object.keys( themeAssetsConfig );
98
+
99
+ themeAssetKeys.forEach( key => {
100
+ app.use( '/assets/theme/' + key , express.static( themeAssetsConfig[key] ) );
101
+ });
102
+
103
+ app.use( '/:source?/css', function (req, res) {
104
+
105
+ /**
106
+ * Generate Larva CSS Docs
107
+ *
108
+ * (Something similar can be done for project CSS unless we eradicate it)
109
+ *
110
+ * 1. Get all CSS from the larva-css npm package.
111
+ * 2. Use PostCSS to generate an abstract syntax tree.
112
+ * 3. Generate a "spec" for the CSS by getting the base selector names
113
+ * from Sass files in larva-scss
114
+ * 4. Walk the rules in the AST, checking the selectors against keys
115
+ * in the spec object, and adding them to an array of
116
+ * selectors for each property. Mark if it is in the hasTokens array.
117
+ * 5. Send that spec object to the template.
118
+ */
119
+
120
+ const postcss = require( 'postcss' );
121
+ const cssPath = path.join( process.cwd(), './node_modules/@penskemediacorp/larva/build/css/larva.css' );
122
+ const sassPath = path.join( process.cwd(), './node_modules/@penskemediacorp/larva-css/src/' );
123
+
124
+ const hasTokens = [
125
+ 'u-background-color',
126
+ 'u-border-color',
127
+ 'u-color',
128
+ 'u-font-family',
129
+ 'u-letter-spacing',
130
+ 'u-margin',
131
+ 'u-padding',
132
+ ];
133
+
134
+ const baseNames = ( () => {
135
+
136
+ let files = globby.sync( sassPath, {
137
+ expandDirectories: {
138
+ files: ['*.scss']
139
+ }
140
+ } );
141
+
142
+ return files.map( ( item ) => {
143
+ let parts = item.split( '/' );
144
+ let baseName = parts[ parts.length - 1 ].split( '.' );
145
+ return baseName[0];
146
+ } );
147
+ } )();
148
+
149
+ const cssString = fs.readFileSync( cssPath );
150
+
151
+ const cssRoot = postcss.parse( cssString )
152
+
153
+ const generatedSpec = ( () => {
154
+ let obj = {};
155
+
156
+ baseNames.forEach( ( item ) => {
157
+ obj[item] = {
158
+ selectors: [],
159
+ tokens: false
160
+ };
161
+ })
162
+
163
+ return obj;
164
+ } )();
165
+
166
+ cssRoot.walkRules( rule => {
167
+
168
+ Object.keys( generatedSpec ).forEach( key => {
169
+ let regex = new RegExp( '.*lrv-' + key + '.*', 'g' );
170
+
171
+ if ( -1 !== hasTokens.indexOf( key ) ) {
172
+ generatedSpec[key]['tokens'] = true;
173
+ }
174
+
175
+ if ( rule.selector.match( regex ) ) {
176
+ generatedSpec[key]['selectors'].push( rule.selector );
177
+ }
178
+
179
+ });
180
+
181
+ } );
182
+
183
+ req.params[ 'name' ] = 'Larva CSS';
184
+ req.params[ 'spec' ] = generatedSpec;
185
+
186
+ req.params[ 'source' ] = 'larva';
187
+ req.params[ 'pattern_nav' ] = patterns;
188
+
189
+ twing.render( 'css.html', req.params ).then( output => res.end( output ) );
190
+ });
191
+
192
+ app.get( '/:source/:type/:name/:variant?', function (req, res) {
193
+
194
+ let patternsPath;
195
+
196
+ if ( 'larva' === req.params.source ) {
197
+ patternsPath = patternConfig.larvaPatternsDir;
198
+ } else if ( 'project' === req.params.source ) {
199
+ patternsPath = patternConfig.projectPatternsDir;
200
+ } else if ( 'assets' === req.params.source ) {
201
+ return res.end();
202
+ }
203
+
204
+ // Support query parameters for conditionally loading stylesheets and scripts
205
+ req.params[ 'query' ] = req.query;
206
+ req.params[ 'pattern_nav' ] = patterns;
207
+ req.params[ 'data' ] = undefined !== patternsPath ? getPatternData( patternsPath, req.params ) : null;
208
+ req.params[ 'brand' ] = req.query.tokens ? req.query.tokens : brandConfig;
209
+ req.params[ 'variants' ] = patterns[req.params.source][req.params.type][req.params.name];
210
+
211
+ if ( 'algorithms' !== req.params.type ) {
212
+ req.params[ 'json_pretty' ] = JSON.stringify( req.params[ 'data' ], null, '\t' );
213
+ }
214
+
215
+ twing.render( 'pattern.html', req.params ).then( ( output ) => {
216
+ res.end( output );
217
+ }).catch( e => {
218
+ const errorMessage = `Cannot render template! \n\n${e}`;
219
+
220
+ console.log( e );
221
+
222
+ res.end( errorMessage );
223
+ } );
224
+ });
225
+
226
+ app.get( '/:source?/style-guide', function (req, res ) {
227
+
228
+ const brand = req.query.tokens ? req.query.tokens : brandConfig;
229
+ const tokensPath = path.join( assetsConfig.path, 'build/tokens' );
230
+
231
+ const tokensData = (() => {
232
+ try {
233
+ return require( path.join( tokensPath, `${brand}.json` ) );
234
+ } catch ( e ) {
235
+ return null;
236
+ }
237
+ })();
238
+
239
+ const colorsByProperty = ( () => {
240
+ if ( ! tokensData ) return;
241
+
242
+ const colorTokens = Object.keys( tokensData ).filter( item => item.includes( 'COLOR' ) );
243
+ const colorNames = colorTokens.map( token => kebabify( token ) );
244
+
245
+ return colorNames.reduce( (acc, curr) => {
246
+ Object.keys( acc ).forEach( key => {
247
+ if ( curr.startsWith( key ) ) {
248
+ acc[key].push( 'lrv-u-' + curr );
249
+ }
250
+ });
251
+
252
+ return acc;
253
+ }, {
254
+ color: [],
255
+ 'background-color': [],
256
+ 'border-color': []
257
+ });
258
+ })();
259
+
260
+ req.params[ 'name' ] = `Style Guide`;
261
+ req.params[ 'font_styles' ] = fontData.groupedSelectors;
262
+ req.params[ 'colors' ] = colorsByProperty;
263
+ req.params[ 'brand' ] = req.query.tokens ? req.query.tokens : brandConfig;
264
+ req.params[ 'pattern_nav' ] = patterns;
265
+
266
+ twing.render( 'style-guide/index.html', req.params ).then( output => res.end( output ) ).catch( e => {
267
+ const errorMessage = `Cannot render template! \n\n${e}`;
268
+
269
+ console.log( e );
270
+
271
+ res.end( errorMessage );
272
+ } );
273
+
274
+ });
275
+
276
+ app.get( '/:source?/:type?', function (req, res) {
277
+ req.params[ 'source' ] = 'larva';
278
+ req.params[ 'type' ] = req.params.type;
279
+ req.params[ 'pattern_nav' ] = patterns;
280
+ req.params[ 'brand' ] = req.query.tokens ? req.query.tokens : brandConfig;
281
+ twing.render( 'index.html', req.params ).then( output => res.end( output ) );
282
+ });
283
+
284
+ module.exports = app;
package/lib/start.js ADDED
@@ -0,0 +1,7 @@
1
+ const app = require( './server' );
2
+
3
+ const port = process.env.NODE_PORT || 3000;
4
+
5
+ app.listen( port, () => {
6
+ console.log( 'Larva server is listening on port ' + port );
7
+ });
@@ -0,0 +1,13 @@
1
+ const path = require( 'path' );
2
+ const clonedeep = require( 'lodash.clonedeep' );
3
+ const getConfig = require( './getAppConfiguration' );
4
+
5
+ const { larvaPatternsDir, projectPatternsDir } = getConfig( 'patterns' );
6
+
7
+ module.exports = function clonePatternData( slug ) {
8
+ try {
9
+ return clonedeep( require( path.join( projectPatternsDir, slug ) ) );
10
+ } catch {
11
+ return clonedeep( require( path.join( larvaPatternsDir, slug ) ) );
12
+ }
13
+ }
@@ -0,0 +1,33 @@
1
+ const path = require( 'path' );
2
+ const fs = require( 'fs-extra' );
3
+ const chalk = require( 'chalk' );
4
+
5
+ /**
6
+ * copySync Helper
7
+ *
8
+ * Wrap the fs.copySync funtion and provide useful logging.
9
+ * See {@link https://github.com/jprichardson/node-fs-extra/blob/master/docs/copy-sync.md fs.copySync}.
10
+ *
11
+ * @param {string} src Path of directory or file to copy.
12
+ * @param {string} dest Path of destination for copied directory or file.
13
+ *
14
+ */
15
+
16
+ module.exports = function copySyncHelper( src, dest ) {
17
+
18
+ const name = path.basename( src );
19
+
20
+ try {
21
+ fs.copySync( src, dest );
22
+
23
+ console.log( `Copied '${name}'.` );
24
+ } catch ( e ) {
25
+
26
+ if ( 'ENOENT' === e.code ) {
27
+ console.log( chalk.grey( `Can't find '${name}' to copy, skipping.` ) );
28
+ } else {
29
+ console.error( e );
30
+ }
31
+
32
+ }
33
+ }
@@ -0,0 +1,48 @@
1
+ const path = require( 'path' );
2
+ const getAppConfiguration = require( './getAppConfiguration' );
3
+ const getPatternVariants = require( './getPatternVariants' );
4
+ const getSubDirectoryNames = require( './getSubDirectoryNames' );
5
+ const getModuleNamesFromDirectory = require( './getModuleNamesFromDirectory' );
6
+
7
+ const config = getAppConfiguration( 'patterns' );
8
+
9
+ /**
10
+ * Get All Patterns
11
+ *
12
+ * Given a directory contianing patterns in the Larva structure (components/object/modules/one-offs),
13
+ * return an object representing all the pattern types, patterns, and their variants.
14
+ *
15
+ * @param {string} startPath - Path to look in for all patterns. Should be assets/src/patterns.
16
+ * @return {object} - Object representing all patterns and variants
17
+ */
18
+
19
+ module.exports = function getAllPatternsObj( startPath ) {
20
+
21
+ const patternDirs = getSubDirectoryNames( startPath );
22
+
23
+ let obj = {};
24
+
25
+ try {
26
+ patternDirs.map( ( patternType ) => {
27
+ let patterns = [];
28
+ obj[patternType] = {};
29
+
30
+ // Modules can be ignored, which maybe is unecessary
31
+ // but for now continue on that path.
32
+ if ( 'modules' === patternType ) {
33
+ patterns = getModuleNamesFromDirectory( startPath, config.ignoredModules );
34
+ } else {
35
+ patterns = getSubDirectoryNames( path.join( startPath, patternType ) );
36
+ }
37
+
38
+ patterns.map( ( pattern ) => {
39
+ obj[patternType][pattern] = getPatternVariants( path.join( startPath, `${patternType}/${pattern}` ) );
40
+ } );
41
+
42
+ } );
43
+ } catch ( e ) {
44
+ console.error( e );
45
+ }
46
+
47
+ return obj;
48
+ }
@@ -0,0 +1,82 @@
1
+ const fs = require( 'fs' );
2
+ const path = require( 'path' );
3
+
4
+ /**
5
+ * Get Larva Configuration
6
+ *
7
+ * Find larva.config.js according to the current working directory.
8
+ * For consuming projects, this will be theme/assets/, and for the
9
+ * mono-repo, it will be packages/larva.
10
+ *
11
+ * For test env, the CWD is overridden to the local directory for fixtures.
12
+ * (this is a problem for writing project-level tests, but for a later time.)
13
+ *
14
+ * @param {string} key string that indicates a specific configuration property, e.g. patterns.
15
+ * @param {boolean} usePackageDefault fall back to package default if not defined in app
16
+ *
17
+ * @return value of the specified key.
18
+ */
19
+
20
+ const defaultConfig = {
21
+
22
+ eslint: {
23
+ configFile: path.join( __dirname, '../../scripts/config/.eslintrc.json' ),
24
+ },
25
+
26
+ webpack: {
27
+ aliases: {
28
+ '@js': path.resolve( './src/js' ),
29
+ '@npm': path.resolve( './node_modules' ),
30
+ '@larva-js': path.resolve( './node_modules/@penskemediacorp/larva-js/src' ),
31
+ },
32
+ entries: {
33
+ 'larva-ui': path.resolve( './entries/larva-ui.entry.js' ),
34
+ common: path.resolve( './entries/common.entry.js' )
35
+ }
36
+ },
37
+
38
+ patterns: {
39
+ larvaPatternsDir: path.resolve( './node_modules/@penskemediacorp/larva-patterns' ),
40
+ projectPatternsDir: path.resolve( './src/patterns' ),
41
+ },
42
+
43
+ assets: {
44
+ path: ( () => {
45
+
46
+ // Fragile way to detect existing Larva sites
47
+ if ( fs.existsSync( path.resolve( './build/css' ) ) ) {
48
+ return path.resolve( './' );
49
+ }
50
+
51
+ return path.resolve( './node_modules/@penskemediacorp/larva' );
52
+ })(),
53
+ },
54
+
55
+ themeAssets: {},
56
+ };
57
+
58
+ module.exports = function getAppConfiguration( key, usePackageDefault = true ) {
59
+
60
+ try {
61
+
62
+ let appRoot = process.cwd();
63
+
64
+ if ( 'test' === process.env.NODE_ENV ) {
65
+ appRoot = path.join( __dirname, '../../__tests__/fixtures/' );
66
+ }
67
+
68
+ let config = require( `${appRoot}/larva.config.js` );
69
+
70
+ // If config not found in approot, fallback to package default in root
71
+ if ( undefined === config[key] && usePackageDefault ) {
72
+ return defaultConfig[ key ];
73
+ }
74
+
75
+ return config[key];
76
+
77
+ } catch ( error ) {
78
+ console.warn( 'Using default configuration. ');
79
+
80
+ return defaultConfig[ key ];
81
+ }
82
+ };
@@ -0,0 +1,3 @@
1
+ module.exports = function getArgsFromCli() {
2
+ return process.argv.slice(2);
3
+ }
@@ -0,0 +1,11 @@
1
+ const getSubDirectoryNames = require( './getSubDirectoryNames' );
2
+ const path = require( 'path' );
3
+
4
+ module.exports = function getModuleNamesFromDirectory( directory, ignoredModules = [] ) {
5
+ let moduleNames = getSubDirectoryNames( path.join( directory , 'modules' ) );
6
+
7
+ return moduleNames.filter( ( moduleName ) => {
8
+ return ! moduleName.startsWith( '_' ) && -1 === ignoredModules.indexOf( moduleName );
9
+ });
10
+
11
+ }
@@ -0,0 +1,34 @@
1
+ const chalk = require( 'chalk' );
2
+ const path = require( 'path' );
3
+ /**
4
+ * Get Pattern Data
5
+ *
6
+ * @param {string} patternsPath
7
+ * @param {object} params Object containing name of pattern
8
+ */
9
+ function getPatternData( patternsPath, params ) {
10
+
11
+ const variant = params.variant || 'prototype';
12
+ const patternPath = path.join( patternsPath, params.type, params.name, params.name + '.' + variant + '.js' );
13
+ const jsonPath = path.join( patternsPath, params.type, params.name, params.name + '.json' )
14
+
15
+ try {
16
+ return require( patternPath );
17
+ } catch( e ) {
18
+ const originalError = e;
19
+
20
+ try {
21
+ // Backwards compat for Deadline when patterns were stored as JSON
22
+ let patternData = require( jsonPath );
23
+ return patternData;
24
+ } catch ( e ) {
25
+ return {
26
+ message: `Error getting data for "${params.name}".<br>There is likely a problem with ${params.name}.${variant}.js.`,
27
+ error: originalError
28
+ }
29
+ }
30
+ }
31
+
32
+ }
33
+
34
+ module.exports = getPatternData;
@@ -0,0 +1,20 @@
1
+ const fs = require( 'fs' );
2
+
3
+ module.exports = function getPatternPathsToLoad( config ) {
4
+ let paths = [];
5
+
6
+ if ( undefined === config ) {
7
+ throw new Error( `Pattern configuration is undefined.` );
8
+ };
9
+
10
+ // Look in projectPatternsDir first.
11
+ if( fs.existsSync( config.projectPatternsDir ) ) {
12
+ paths.push( config.projectPatternsDir );
13
+ }
14
+
15
+ if( fs.existsSync( config.larvaPatternsDir ) ) {
16
+ paths.push( config.larvaPatternsDir );
17
+ }
18
+
19
+ return paths;
20
+ }