blob: e2869ed661bd4afa04c2e050918cce9efaddfa62 [file] [log] [blame]
///
/// Script to create boilerplate for a Polymer element.
/// Produces .dart and .html files for the element.
///
/// Run this script with pub run:
///
/// pub run polymer:new_element element-name [-o output_dir]
///
import 'dart:io';
import 'package:args/args.dart';
import 'package:path/path.dart' as path show absolute, dirname, join, split;
void main(List<String> args) {
var parser = new ArgParser(allowTrailingOptions: true);
parser.addOption('output-dir', abbr: 'o', help: 'Output directory');
var options, element;
try {
options = parser.parse(args);
if (options.rest == null || options.rest.length > 1) {
throw new FormatException("No element specified");
}
element = options.rest[0];
_validateElementName(element);
} catch(e) {
print('${e}.\n');
print('Usage:');
print(' pub run polymer:new_element [-o output_dir] element-name');
exitCode = 1;
return;
}
var outputDir, startDir;
var outputPath = options['output-dir'];
if (outputPath == null) {
if ((new File('pubspec.yaml')).existsSync()) {
print('When creating elements in root directory of package, '
'-o <dir> must be specified');
exitCode = 1;
return;
}
outputDir = (new Directory('.')).resolveSymbolicLinksSync();
} else {
var outputDirLocation = new Directory(outputPath);
if (!outputDirLocation.existsSync()) {
outputDirLocation.createSync(recursive: true);
}
outputDir = (new Directory(outputPath)).resolveSymbolicLinksSync();
}
var pubspecDir = _findDirWithFile(outputDir, 'pubspec.yaml');
if (pubspecDir == null) {
print('Could not find pubspec.yaml when walking up from $outputDir');
exitCode = 1;
return;
}
var length = path.split(pubspecDir).length;
var distanceToPackageRoot =
path.split(outputDir).length - length;
// See dartbug.com/20076 for the algorithm used here.
if (distanceToPackageRoot > 0) {
if (path.split(outputDir)[length] == 'lib') {
distanceToPackageRoot++;
} else {
distanceToPackageRoot--;
}
}
try {
_createBoilerPlate(element, outputDir, distanceToPackageRoot);
} on Exception catch(e) {
print('Error creating files in $outputDir');
print('Exception: $e');
exitCode = 1;
return;
}
return;
}
String _findDirWithFile(String dir, String filename) {
while (!new File(path.join(dir, filename)).existsSync()) {
var parentDir = path.dirname(dir);
// If we reached root and failed to find it, bail.
if (parentDir == dir) return null;
dir = parentDir;
}
return dir;
}
void _validateElementName(String element) {
if (!element.contains('-') || element.toLowerCase() != element) {
throw new FormatException('element-name must be all lower case '
'and contain at least 1 hyphen');
}
}
String _toCamelCase(String s) {
return s[0].toUpperCase() + s.substring(1);
}
void _createBoilerPlate(String element, String directory,
int distanceToPackageRoot) {
var segments = element.split('-');
var capitalizedName = segments.map((e) => _toCamelCase(e)).join('');
var underscoreName = element.replaceAll('-', '_');
var pathToPackages = '../' * distanceToPackageRoot;
String html = '''
<!-- import polymer-element's definition -->
<link rel="import" href="${pathToPackages}packages/polymer/polymer.html">
<polymer-element name="$element">
<template>
<style>
<!-- template styling here -->
</style>
<!-- template content here -->
</template>
<script type="application/dart" src="${underscoreName}.dart"></script>
</polymer-element>
''';
String htmlFile = path.join(directory, underscoreName + '.html');
new File(htmlFile).writeAsStringSync(html);
String dart = '''
import 'package:polymer/polymer.dart';
/**
* A Polymer $element element.
*/
@CustomTag('$element')
class $capitalizedName extends PolymerElement {
/// Constructor used to create instance of ${capitalizedName}.
${capitalizedName}.created() : super.created() {
}
/*
* Optional lifecycle methods - uncomment if needed.
*
/// Called when an instance of $element is inserted into the DOM.
attached() {
super.attached();
}
/// Called when an instance of $element is removed from the DOM.
detached() {
super.detached();
}
/// Called when an attribute (such as a class) of an instance of
/// $element is added, changed, or removed.
attributeChanged(String name, String oldValue, String newValue) {
}
/// Called when $element has been fully prepared (Shadow DOM created,
/// property observers set up, event listeners attached).
ready() {
}
*/
}
''';
String dartFile = path.join(directory, underscoreName + '.dart');
new File(dartFile).writeAsStringSync(dart);
print('Successfully created:');
print(' ' + path.absolute(path.join(directory, underscoreName + '.dart')));
print(' ' + path.absolute(path.join(directory, underscoreName + '.html')));
}