| OLD | NEW |
| (Empty) |
| 1 /// | |
| 2 /// Script to create boilerplate for a Polymer element. | |
| 3 /// Produces .dart and .html files for the element. | |
| 4 /// | |
| 5 /// Run this script with pub run: | |
| 6 /// | |
| 7 /// pub run polymer:new_element element-name [-o output_dir] | |
| 8 /// | |
| 9 import 'dart:io'; | |
| 10 import 'package:args/args.dart'; | |
| 11 import 'package:path/path.dart' as path show absolute, dirname, join, split; | |
| 12 import 'package:polymer/html_element_names.dart'; | |
| 13 | |
| 14 void printUsage(ArgParser parser) { | |
| 15 print('pub run polymer:new_element [-o output_dir] [-e super-element] ' | |
| 16 'element-name'); | |
| 17 print(parser.getUsage()); | |
| 18 } | |
| 19 | |
| 20 void main(List<String> args) { | |
| 21 var parser = new ArgParser(allowTrailingOptions: true); | |
| 22 | |
| 23 parser.addOption('output-dir', abbr: 'o', help: 'Output directory'); | |
| 24 parser.addOption('extends', abbr: 'e', | |
| 25 help: 'Extends polymer-element or DOM element (e.g., div, span)'); | |
| 26 parser.addFlag('help', abbr: 'h'); | |
| 27 | |
| 28 var options, element; | |
| 29 try { | |
| 30 options = parser.parse(args); | |
| 31 if (options['help']) { | |
| 32 printUsage(parser); | |
| 33 return; | |
| 34 } | |
| 35 if (options.rest == null || options.rest.isEmpty) { | |
| 36 throw new FormatException('No element specified'); | |
| 37 } | |
| 38 element = options.rest[0]; | |
| 39 if (!_isPolymerElement(element)) { | |
| 40 throw new FormatException('Must specify polymer-element to create.\n' | |
| 41 'polymer-element must be all lowercase with at least 1 hyphen.'); | |
| 42 } | |
| 43 } catch(e) { | |
| 44 print('$e\n'); | |
| 45 printUsage(parser); | |
| 46 exitCode = 1; | |
| 47 return; | |
| 48 } | |
| 49 | |
| 50 var outputDir, startDir; | |
| 51 | |
| 52 var outputPath = options['output-dir']; | |
| 53 | |
| 54 if (outputPath == null) { | |
| 55 if ((new File('pubspec.yaml')).existsSync()) { | |
| 56 print('When creating elements in root directory of package, ' | |
| 57 '-o <dir> must be specified'); | |
| 58 exitCode = 1; | |
| 59 return; | |
| 60 } | |
| 61 outputDir = (new Directory('.')).resolveSymbolicLinksSync(); | |
| 62 } else { | |
| 63 var outputDirLocation = new Directory(outputPath); | |
| 64 if (!outputDirLocation.existsSync()) { | |
| 65 outputDirLocation.createSync(recursive: true); | |
| 66 } | |
| 67 outputDir = (new Directory(outputPath)).resolveSymbolicLinksSync(); | |
| 68 } | |
| 69 | |
| 70 var pubspecDir = _findDirWithFile(outputDir, 'pubspec.yaml'); | |
| 71 | |
| 72 if (pubspecDir == null) { | |
| 73 print('Could not find pubspec.yaml when walking up from $outputDir'); | |
| 74 exitCode = 1; | |
| 75 return; | |
| 76 } | |
| 77 | |
| 78 var length = path.split(pubspecDir).length; | |
| 79 var distanceToPackageRoot = | |
| 80 path.split(outputDir).length - length; | |
| 81 | |
| 82 // See dartbug.com/20076 for the algorithm used here. | |
| 83 if (distanceToPackageRoot > 0) { | |
| 84 if (path.split(outputDir)[length] == 'lib') { | |
| 85 distanceToPackageRoot++; | |
| 86 } else { | |
| 87 distanceToPackageRoot--; | |
| 88 } | |
| 89 } | |
| 90 | |
| 91 var superElement = options['extends']; | |
| 92 | |
| 93 if ((superElement == null ) || | |
| 94 _isDOMElement(superElement) || | |
| 95 _isPolymerElement(superElement)) { | |
| 96 try { | |
| 97 _createBoilerPlate(element, options['extends'], outputDir, | |
| 98 distanceToPackageRoot); | |
| 99 } on Exception catch(e, t) { | |
| 100 print('Error creating files in $outputDir'); | |
| 101 print('$e $t'); | |
| 102 exitCode = 1; | |
| 103 return; | |
| 104 } | |
| 105 } else { | |
| 106 if (superElement.contains('-')) { | |
| 107 print('Extending invalid element "$superElement". Polymer elements ' | |
| 108 'may contain only lowercase letters at least one hyphen.'); | |
| 109 } else { | |
| 110 print('Extending invalid element "$superElement". $superElement is not ' | |
| 111 ' a builtin DOM type.'); | |
| 112 } | |
| 113 exitCode = 1; | |
| 114 return; | |
| 115 } | |
| 116 | |
| 117 return; | |
| 118 } | |
| 119 | |
| 120 String _findDirWithFile(String dir, String filename) { | |
| 121 while (!new File(path.join(dir, filename)).existsSync()) { | |
| 122 var parentDir = path.dirname(dir); | |
| 123 // If we reached root and failed to find it, bail. | |
| 124 if (parentDir == dir) return null; | |
| 125 dir = parentDir; | |
| 126 } | |
| 127 return dir; | |
| 128 } | |
| 129 | |
| 130 bool _isDOMElement(String element) => (HTML_ELEMENT_NAMES[element] != null); | |
| 131 | |
| 132 bool _isPolymerElement(String element) { | |
| 133 return element.contains('-') && (element.toLowerCase() == element); | |
| 134 } | |
| 135 | |
| 136 String _toCamelCase(String s) { | |
| 137 return s[0].toUpperCase() + s.substring(1); | |
| 138 } | |
| 139 | |
| 140 void _createBoilerPlate(String element, String superClass, String directory, | |
| 141 int distanceToPackageRoot) { | |
| 142 var segments = element.split('-'); | |
| 143 var capitalizedName = segments.map((e) => _toCamelCase(e)).join(''); | |
| 144 var underscoreName = element.replaceAll('-', '_'); | |
| 145 var pathToPackages = '../' * distanceToPackageRoot; | |
| 146 | |
| 147 bool superClassIsPolymer = | |
| 148 (superClass == null ? false : _isPolymerElement(superClass)); | |
| 149 | |
| 150 var classDeclaration = ''; | |
| 151 var importDartHtml = ''; | |
| 152 var polymerCreatedString = ''; | |
| 153 var extendsElementString = ''; | |
| 154 var shadowString = ''; | |
| 155 | |
| 156 if (superClass == null) { | |
| 157 classDeclaration = '\nclass $capitalizedName extends PolymerElement {'; | |
| 158 } else if (superClassIsPolymer) { | |
| 159 // The element being extended is a PolymerElement. | |
| 160 var camelSuperClass = | |
| 161 superClass.split('-').map((e) => _toCamelCase(e)).join(''); | |
| 162 classDeclaration = 'class $capitalizedName extends $camelSuperClass {'; | |
| 163 extendsElementString = ' extends="$superClass"'; | |
| 164 shadowString = | |
| 165 '\n <!-- Render extended element\'s Shadow DOM here -->\n' | |
| 166 ' <shadow>\n </shadow>'; | |
| 167 } else { | |
| 168 // The element being extended is a DOM Class. | |
| 169 importDartHtml = "import 'dart:html';\n"; | |
| 170 classDeclaration = | |
| 171 'class $capitalizedName extends ${HTML_ELEMENT_NAMES[superClass]} ' | |
| 172 'with Polymer, Observable {'; | |
| 173 polymerCreatedString = '\n polymerCreated();'; | |
| 174 extendsElementString = ' extends="$superClass"'; | |
| 175 } | |
| 176 | |
| 177 String html = ''' | |
| 178 <!-- import polymer-element's definition --> | |
| 179 <link rel="import" href="${pathToPackages}packages/polymer/polymer.html"> | |
| 180 | |
| 181 <polymer-element name="$element"$extendsElementString> | |
| 182 <template> | |
| 183 <style> | |
| 184 :host { | |
| 185 display: block; | |
| 186 } | |
| 187 </style>$shadowString | |
| 188 <!-- Template content here --> | |
| 189 </template> | |
| 190 <script type="application/dart" src="${underscoreName}.dart"></script> | |
| 191 </polymer-element> | |
| 192 '''; | |
| 193 | |
| 194 String htmlFile = path.join(directory, underscoreName + '.html'); | |
| 195 new File(htmlFile).writeAsStringSync(html); | |
| 196 | |
| 197 String dart = ''' | |
| 198 ${importDartHtml}import 'package:polymer/polymer.dart'; | |
| 199 | |
| 200 /** | |
| 201 * A Polymer $element element. | |
| 202 */ | |
| 203 @CustomTag('$element') | |
| 204 $classDeclaration | |
| 205 | |
| 206 /// Constructor used to create instance of ${capitalizedName}. | |
| 207 ${capitalizedName}.created() : super.created() {$polymerCreatedString | |
| 208 } | |
| 209 | |
| 210 /* | |
| 211 * Optional lifecycle methods - uncomment if needed. | |
| 212 * | |
| 213 | |
| 214 /// Called when an instance of $element is inserted into the DOM. | |
| 215 attached() { | |
| 216 super.attached(); | |
| 217 } | |
| 218 | |
| 219 /// Called when an instance of $element is removed from the DOM. | |
| 220 detached() { | |
| 221 super.detached(); | |
| 222 } | |
| 223 | |
| 224 /// Called when an attribute (such as a class) of an instance of | |
| 225 /// $element is added, changed, or removed. | |
| 226 attributeChanged(String name, String oldValue, String newValue) { | |
| 227 } | |
| 228 | |
| 229 /// Called when $element has been fully prepared (Shadow DOM created, | |
| 230 /// property observers set up, event listeners attached). | |
| 231 ready() { | |
| 232 } | |
| 233 | |
| 234 */ | |
| 235 | |
| 236 } | |
| 237 '''; | |
| 238 | |
| 239 String dartFile = path.join(directory, underscoreName + '.dart'); | |
| 240 new File(dartFile).writeAsStringSync(dart); | |
| 241 | |
| 242 print('Successfully created:'); | |
| 243 print(' ' + path.absolute(path.join(directory, underscoreName + '.dart'))); | |
| 244 print(' ' + path.absolute(path.join(directory, underscoreName + '.html'))); | |
| 245 } | |
| OLD | NEW |