blob: 2a79be8330e51b1bb0d0a5c9aa7a3675bd98c250 [file] [log] [blame]
// Copyright (c) 2014, 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.
/// This is a helper library to make working with io easier.
library dartdoc.io_utils;
import 'dart:io';
import 'package:path/path.dart' as path;
/// Lists the contents of [dir].
///
/// If [recursive] is `true`, lists subdirectory contents (defaults to `false`).
///
/// Excludes files and directories beginning with `.`
///
/// The returned paths are guaranteed to begin with [dir].
Iterable<String> listDir(String dir,
{bool recursive: false,
Iterable<FileSystemEntity> listDir(Directory dir)}) {
if (listDir == null) listDir = (Directory dir) => dir.listSync();
return _doList(dir, new Set<String>(), recursive, listDir);
}
Iterable<String> _doList(String dir, Set<String> listedDirectories,
bool recurse, Iterable<FileSystemEntity> listDir(Directory dir)) sync* {
// Avoid recursive symlinks.
var resolvedPath = new Directory(dir).resolveSymbolicLinksSync();
if (!listedDirectories.contains(resolvedPath)) {
listedDirectories = new Set<String>.from(listedDirectories);
listedDirectories.add(resolvedPath);
for (var entity in listDir(new Directory(dir))) {
// Skip hidden files and directories
if (path.basename(entity.path).startsWith('.')) {
continue;
}
yield entity.path;
if (entity is Directory) {
if (recurse) {
yield* _doList(entity.path, listedDirectories, recurse, listDir);
}
}
}
}
}
/// Given a package name, explore the directory and pull out all top level
/// library files in the "lib" directory to document.
Iterable<String> findFilesToDocumentInPackage(String packageDir) sync* {
final String sep = path.separator;
var packageLibDir = path.join(packageDir, 'lib');
var packageLibSrcDir = path.join(packageLibDir, 'src');
// To avoid analyzing package files twice, only files with paths not
// containing '/packages' will be added. The only exception is if the file
// to analyze already has a '/package' in its path.
for (var lib
in listDir(packageDir, recursive: true, listDir: _packageDirList)) {
if (lib.endsWith('.dart') &&
(!lib.contains('${sep}packages${sep}') ||
packageDir.contains('${sep}packages${sep}'))) {
// Only include libraries within the lib dir that are not in lib/src
if (path.isWithin(packageLibDir, lib) &&
!path.isWithin(packageLibSrcDir, lib)) {
// Only add the file if it does not contain 'part of'
var contents = new File(lib).readAsStringSync();
if (contents.contains(_newLinePartOfRegexp) ||
contents.startsWith(_partOfRegexp)) {
// NOOP: it's a part file
} else {
yield lib;
}
}
}
}
}
/// If [dir] contains both a `lib` directory and a `pubspec.yaml` file treat
/// it like a package and only return the `lib` dir.
///
/// This ensures that packages don't have non-`lib` content documented.
Iterable<FileSystemEntity> _packageDirList(Directory dir) sync* {
var entities = dir.listSync();
var pubspec = entities.firstWhere(
(e) => e is File && path.basename(e.path) == 'pubspec.yaml',
orElse: () => null);
var libDir = entities.firstWhere(
(e) => e is Directory && path.basename(e.path) == 'lib',
orElse: () => null);
if (pubspec != null && libDir != null) {
yield libDir;
} else {
yield* entities;
}
}
/// Converts `.` and `:` into `-`, adding a ".html" extension.
///
/// For example:
///
/// * dart.dartdoc => dart_dartdoc.html
/// * dart:core => dart_core.html
String getFileNameFor(String name) =>
'${name.replaceAll(_libraryNameRegexp, '-')}.html';
final _libraryNameRegexp = new RegExp('[.:]');
final _partOfRegexp = new RegExp('part of ');
final _newLinePartOfRegexp = new RegExp('\npart of ');