blob: 1db39bfd5a9f9140ecb1c9dfd3edeb3997e26a40 [file] [log] [blame]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:collection';
import 'package:source_span/source_span.dart';
import 'package:yaml/yaml.dart';
PSEntry _findEntry(YamlMap map, String key) {
PSEntry entry;
map.nodes.forEach((k, v) {
if (k is YamlScalar && key == k.toString()) {
entry = _processScalar(k, v);
}
});
return entry;
}
PSDependencyList _processDependencies(YamlScalar key, YamlNode v) {
if (v is! YamlMap) {
return null;
}
YamlMap depsMap = v;
_PSDependencyList deps = new _PSDependencyList(new _PSNode(key));
depsMap.nodes.forEach((k, v) => deps.add(new _PSDependency(k, v)));
return deps;
}
PSGitRepo _processGitRepo(YamlScalar key, YamlNode v) {
if (v is! YamlMap) {
return null;
}
YamlMap hostMap = v;
// url: git://github.com/munificent/kittens.git
// ref: some-branch
_PSGitRepo repo = new _PSGitRepo();
repo.token = new _PSNode(key);
repo.ref = _findEntry(hostMap, 'ref');
repo.url = _findEntry(hostMap, 'url');
return repo;
}
PSHost _processHost(YamlScalar key, YamlNode v) {
if (v is! YamlMap) {
return null;
}
YamlMap hostMap = v;
// name: transmogrify
// url: http://your-package-server.com
_PSHost host = new _PSHost();
host.token = new _PSNode(key);
host.name = _findEntry(hostMap, 'name');
host.url = _findEntry(hostMap, 'url');
return host;
}
PSNodeList _processList(YamlScalar key, YamlNode v) {
if (v is! YamlList) {
return null;
}
YamlList nodeList = v;
return new _PSNodeList(
new _PSNode(key), nodeList.nodes.map((n) => new _PSNode(n)));
}
PSEntry _processScalar(YamlScalar key, YamlNode value) {
if (value is! YamlScalar) {
return null;
//WARN?
}
return new PSEntry(new _PSNode(key), new _PSNode(value));
}
abstract class PSDependency {
PSGitRepo get git;
PSHost get host;
PSNode get name;
PSEntry get version;
}
abstract class PSDependencyList extends Object
with IterableMixin<PSDependency> {}
class PSEntry {
final PSNode key;
final PSNode value;
PSEntry(this.key, this.value);
@override
String toString() => '${key != null ? (key.toString() + ': ') : ''}$value';
}
abstract class PSGitRepo {
PSEntry get ref;
PSNode get token;
PSEntry get url;
}
abstract class PSHost {
PSEntry get name;
PSNode get token;
PSEntry get url;
}
abstract class PSNode {
SourceSpan get span;
String get text;
}
abstract class PSNodeList extends Object with IterableMixin<PSNode> {
@override
Iterator<PSNode> get iterator;
PSNode get token;
}
abstract class Pubspec {
factory Pubspec.parse(String source, {Uri sourceUrl}) =>
new _Pubspec(source, sourceUrl: sourceUrl);
PSEntry get author;
PSNodeList get authors;
PSDependencyList get dependencies;
PSDependencyList get dependencyOverrides;
PSEntry get description;
PSDependencyList get devDependencies;
PSEntry get documentation;
PSEntry get homepage;
PSEntry get name;
PSEntry get version;
accept(PubspecVisitor visitor);
}
abstract class PubspecVisitor<T> {
T visitPackageAuthor(PSEntry author) => null;
T visitPackageAuthors(PSNodeList authors) => null;
T visitPackageDependencies(PSDependencyList dependencies) => null;
T visitPackageDependency(PSDependency dependency) => null;
T visitPackageDependencyOverrides(PSDependencyList dependencies) => null;
T visitPackageDependencyOverride(PSDependency dependency) => null;
T visitPackageDescription(PSEntry description) => null;
T visitPackageDevDependencies(PSDependencyList dependencies) => null;
T visitPackageDevDependency(PSDependency dependency) => null;
T visitPackageDocumentation(PSEntry documentation) => null;
T visitPackageHomepage(PSEntry homepage) => null;
T visitPackageName(PSEntry name) => null;
T visitPackageVersion(PSEntry version) => null;
}
class _PSDependency extends PSDependency {
@override
PSNode name;
@override
PSEntry version;
@override
PSHost host;
@override
PSGitRepo git;
factory _PSDependency(dynamic k, YamlNode v) {
if (k is! YamlScalar) {
return null;
}
YamlScalar key = k;
_PSDependency dep = new _PSDependency._();
dep.name = new _PSNode(key);
if (v is YamlScalar) {
// Simple version
dep.version = new PSEntry(null, new _PSNode(v));
} else if (v is YamlMap) {
// hosted:
// name: transmogrify
// url: http://your-package-server.com
// version: '>=0.4.0 <1.0.0'
YamlMap details = v;
details.nodes.forEach((k, v) {
if (k is! YamlScalar) {
return;
}
YamlScalar key = k;
switch (key.toString()) {
case 'version':
dep.version = _processScalar(key, v);
break;
case 'hosted':
dep.host = _processHost(key, v);
break;
case 'git':
dep.git = _processGitRepo(key, v);
break;
}
});
}
return dep;
}
_PSDependency._();
@override
String toString() {
var sb = new StringBuffer();
if (name != null) {
sb.write('$name:');
}
var versionInfo = '';
if (version != null) {
if (version.key == null) {
versionInfo = ' $version';
} else {
versionInfo = '\n $version';
}
}
sb.writeln(versionInfo);
if (host != null) {
sb.writeln(host);
}
if (git != null) {
sb.writeln(git);
}
return sb.toString();
}
}
class _PSDependencyList extends PSDependencyList {
final dependencies = <PSDependency>[];
final PSNode token;
_PSDependencyList(this.token);
@override
Iterator<PSDependency> get iterator => dependencies.iterator;
add(PSDependency dependency) {
if (dependency != null) {
dependencies.add(dependency);
}
}
@override
String toString() => '$token\n${dependencies.join(' ')}';
}
class _PSGitRepo implements PSGitRepo {
@override
PSNode token;
@override
PSEntry ref;
@override
PSEntry url;
@override
String toString() => '''
$token:
$url
$ref''';
}
class _PSHost implements PSHost {
@override
PSNode token;
@override
PSEntry name;
@override
PSEntry url;
@override
String toString() => '''
$token:
$name
$url''';
}
class _PSNode implements PSNode {
@override
final String text;
@override
final SourceSpan span;
_PSNode(YamlNode node)
: text = node.value?.toString(),
span = node.span;
@override
String toString() => '$text';
}
class _PSNodeList extends PSNodeList {
@override
final PSNode token;
final Iterable<PSNode> nodes;
_PSNodeList(this.token, this.nodes);
@override
Iterator<PSNode> get iterator => nodes.iterator;
@override
String toString() => '''
$token:
- ${nodes.join('\n - ')}''';
}
class _Pubspec implements Pubspec {
@override
PSEntry author;
@override
PSNodeList authors;
@override
PSEntry description;
@override
PSEntry documentation;
@override
PSEntry homepage;
@override
PSEntry name;
@override
PSEntry version;
@override
PSDependencyList dependencies;
@override
PSDependencyList devDependencies;
@override
PSDependencyList dependencyOverrides;
_Pubspec(String src, {Uri sourceUrl}) {
try {
_parse(src, sourceUrl: sourceUrl);
} on Exception {
// ignore
}
}
@override
void accept(PubspecVisitor visitor) {
if (author != null) {
visitor.visitPackageAuthor(author);
}
if (authors != null) {
visitor.visitPackageAuthors(authors);
}
if (description != null) {
visitor.visitPackageDescription(description);
}
if (documentation != null) {
visitor.visitPackageDocumentation(documentation);
}
if (homepage != null) {
visitor.visitPackageHomepage(homepage);
}
if (name != null) {
visitor.visitPackageName(name);
}
if (version != null) {
visitor.visitPackageVersion(version);
}
if (dependencies != null) {
visitor.visitPackageDependencies(dependencies);
dependencies.forEach(visitor.visitPackageDependency);
}
if (devDependencies != null) {
visitor.visitPackageDevDependencies(devDependencies);
devDependencies.forEach(visitor.visitPackageDevDependency);
}
if (dependencyOverrides != null) {
visitor.visitPackageDependencyOverrides(dependencyOverrides);
dependencyOverrides.forEach(visitor.visitPackageDependencyOverride);
}
}
@override
String toString() {
var sb = new _StringBuilder();
sb.writelin(name);
sb.writelin(version);
sb.writelin(author);
sb.writelin(authors);
sb.writelin(description);
sb.writelin(homepage);
sb.writelin(dependencies);
sb.writelin(devDependencies);
sb.writelin(dependencyOverrides);
return sb.toString();
}
_parse(String src, {Uri sourceUrl}) {
var yaml = loadYamlNode(src, sourceUrl: sourceUrl);
if (yaml is! YamlMap) {
return;
}
YamlMap yamlMap = yaml;
yamlMap.nodes.forEach((k, v) {
if (k is! YamlScalar) {
return;
}
YamlScalar key = k;
switch (key.toString()) {
case 'author':
author = _processScalar(key, v);
break;
case 'authors':
authors = _processList(key, v);
break;
case 'homepage':
homepage = _processScalar(key, v);
break;
case 'name':
name = _processScalar(key, v);
break;
case 'description':
description = _processScalar(key, v);
break;
case 'documentation':
documentation = _processScalar(key, v);
break;
case 'dependencies':
dependencies = _processDependencies(key, v);
break;
case 'dev_dependencies':
devDependencies = _processDependencies(key, v);
break;
case 'dependency_overrides':
dependencyOverrides = _processDependencies(key, v);
break;
case 'version':
version = _processScalar(key, v);
break;
}
});
}
}
class _StringBuilder {
StringBuffer buffer = new StringBuffer();
@override
String toString() => buffer.toString();
writelin(Object value) {
if (value != null) {
buffer.writeln(value);
}
}
}