microcms_sdk_generator
Version:
A type-safe MicroCMS SDK Generator
217 lines (216 loc) • 7.9 kB
JavaScript
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
import * as dntShim from "../../../../_dnt.shims.js";
import { globToRegExp, isAbsolute, isGlob, joinGlobs, resolve, SEP_PATTERN, } from "../path/mod.js";
import { walk, walkSync } from "./walk.js";
import { assert } from "../_util/asserts.js";
import { isWindows } from "../_util/os.js";
import { createWalkEntry, createWalkEntrySync, toPathString, } from "./_util.js";
function split(path) {
const s = SEP_PATTERN.source;
const segments = path
.replace(new RegExp(`^${s}|${s}$`, "g"), "")
.split(SEP_PATTERN);
const isAbsolute_ = isAbsolute(path);
return {
segments,
isAbsolute: isAbsolute_,
hasTrailingSep: !!path.match(new RegExp(`${s}$`)),
winRoot: isWindows && isAbsolute_ ? segments.shift() : undefined,
};
}
function throwUnlessNotFound(error) {
if (!(error instanceof dntShim.Deno.errors.NotFound)) {
throw error;
}
}
function comparePath(a, b) {
if (a.path < b.path)
return -1;
if (a.path > b.path)
return 1;
return 0;
}
/**
* Expand the glob string from the specified `root` directory and yield each
* result as a `WalkEntry` object.
*
* See [`globToRegExp()`](../path/glob.ts#globToRegExp) for details on supported
* syntax.
*
* @example
* ```ts
* import { expandGlob } from "https://deno.land/std@$STD_VERSION/fs/expand_glob.ts";
* for await (const file of expandGlob("**\/*.ts")) {
* console.log(file);
* }
* ```
*/
export async function* expandGlob(glob, { root = dntShim.Deno.cwd(), exclude = [], includeDirs = true, extended = true, globstar = true, caseInsensitive, followSymlinks, } = {}) {
const globOptions = { extended, globstar, caseInsensitive };
const absRoot = resolve(root);
const resolveFromRoot = (path) => resolve(absRoot, path);
const excludePatterns = exclude
.map(resolveFromRoot)
.map((s) => globToRegExp(s, globOptions));
const shouldInclude = (path) => !excludePatterns.some((p) => !!path.match(p));
const { segments, isAbsolute: isGlobAbsolute, hasTrailingSep, winRoot, } = split(toPathString(glob));
let fixedRoot = isGlobAbsolute
? winRoot != undefined ? winRoot : "/"
: absRoot;
while (segments.length > 0 && !isGlob(segments[0])) {
const seg = segments.shift();
assert(seg != null);
fixedRoot = joinGlobs([fixedRoot, seg], globOptions);
}
let fixedRootInfo;
try {
fixedRootInfo = await createWalkEntry(fixedRoot);
}
catch (error) {
return throwUnlessNotFound(error);
}
async function* advanceMatch(walkInfo, globSegment) {
if (!walkInfo.isDirectory) {
return;
}
else if (globSegment == "..") {
const parentPath = joinGlobs([walkInfo.path, ".."], globOptions);
try {
if (shouldInclude(parentPath)) {
return yield await createWalkEntry(parentPath);
}
}
catch (error) {
throwUnlessNotFound(error);
}
return;
}
else if (globSegment == "**") {
return yield* walk(walkInfo.path, {
skip: excludePatterns,
maxDepth: globstar ? Infinity : 1,
followSymlinks,
});
}
const globPattern = globToRegExp(globSegment, globOptions);
for await (const walkEntry of walk(walkInfo.path, {
maxDepth: 1,
skip: excludePatterns,
followSymlinks,
})) {
if (walkEntry.path != walkInfo.path &&
walkEntry.name.match(globPattern)) {
yield walkEntry;
}
}
}
let currentMatches = [fixedRootInfo];
for (const segment of segments) {
// Advancing the list of current matches may introduce duplicates, so we
// pass everything through this Map.
const nextMatchMap = new Map();
await Promise.all(currentMatches.map(async (currentMatch) => {
for await (const nextMatch of advanceMatch(currentMatch, segment)) {
nextMatchMap.set(nextMatch.path, nextMatch);
}
}));
currentMatches = [...nextMatchMap.values()].sort(comparePath);
}
if (hasTrailingSep) {
currentMatches = currentMatches.filter((entry) => entry.isDirectory);
}
if (!includeDirs) {
currentMatches = currentMatches.filter((entry) => !entry.isDirectory);
}
yield* currentMatches;
}
/**
* Synchronous version of `expandGlob()`.
*
* @example
* ```ts
* import { expandGlobSync } from "https://deno.land/std@$STD_VERSION/fs/expand_glob.ts";
* for (const file of expandGlobSync("**\/*.ts")) {
* console.log(file);
* }
* ```
*/
export function* expandGlobSync(glob, { root = dntShim.Deno.cwd(), exclude = [], includeDirs = true, extended = true, globstar = true, caseInsensitive, followSymlinks, } = {}) {
const globOptions = { extended, globstar, caseInsensitive };
const absRoot = resolve(root);
const resolveFromRoot = (path) => resolve(absRoot, path);
const excludePatterns = exclude
.map(resolveFromRoot)
.map((s) => globToRegExp(s, globOptions));
const shouldInclude = (path) => !excludePatterns.some((p) => !!path.match(p));
const { segments, isAbsolute: isGlobAbsolute, hasTrailingSep, winRoot, } = split(toPathString(glob));
let fixedRoot = isGlobAbsolute
? winRoot != undefined ? winRoot : "/"
: absRoot;
while (segments.length > 0 && !isGlob(segments[0])) {
const seg = segments.shift();
assert(seg != null);
fixedRoot = joinGlobs([fixedRoot, seg], globOptions);
}
let fixedRootInfo;
try {
fixedRootInfo = createWalkEntrySync(fixedRoot);
}
catch (error) {
return throwUnlessNotFound(error);
}
function* advanceMatch(walkInfo, globSegment) {
if (!walkInfo.isDirectory) {
return;
}
else if (globSegment == "..") {
const parentPath = joinGlobs([walkInfo.path, ".."], globOptions);
try {
if (shouldInclude(parentPath)) {
return yield createWalkEntrySync(parentPath);
}
}
catch (error) {
throwUnlessNotFound(error);
}
return;
}
else if (globSegment == "**") {
return yield* walkSync(walkInfo.path, {
skip: excludePatterns,
maxDepth: globstar ? Infinity : 1,
followSymlinks,
});
}
const globPattern = globToRegExp(globSegment, globOptions);
for (const walkEntry of walkSync(walkInfo.path, {
maxDepth: 1,
skip: excludePatterns,
followSymlinks,
})) {
if (walkEntry.path != walkInfo.path &&
walkEntry.name.match(globPattern)) {
yield walkEntry;
}
}
}
let currentMatches = [fixedRootInfo];
for (const segment of segments) {
// Advancing the list of current matches may introduce duplicates, so we
// pass everything through this Map.
const nextMatchMap = new Map();
for (const currentMatch of currentMatches) {
for (const nextMatch of advanceMatch(currentMatch, segment)) {
nextMatchMap.set(nextMatch.path, nextMatch);
}
}
currentMatches = [...nextMatchMap.values()].sort(comparePath);
}
if (hasTrailingSep) {
currentMatches = currentMatches.filter((entry) => entry.isDirectory);
}
if (!includeDirs) {
currentMatches = currentMatches.filter((entry) => !entry.isDirectory);
}
yield* currentMatches;
}