feat(blog): add file-based blog with dynamic slugs, MDX content and layout shell

- Introduced blog routing using Next.js App Router
- Implemented dynamic [slug] pages for blog posts
- Added MDX-based content loading via lib/posts
- Integrated shared TopBar layout with navigation
- Established clear content, lib and component separation
This commit is contained in:
PascalSchattenburg
2026-01-22 14:14:15 +01:00
parent b717952234
commit d147843c76
10412 changed files with 2475583 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
import type { FileReader } from './helpers/file-reader/file-reader';
import { AppPageRouteMatcher } from '../../route-matchers/app-page-route-matcher';
import { FileCacheRouteMatcherProvider } from './file-cache-route-matcher-provider';
export declare class DevAppPageRouteMatcherProvider extends FileCacheRouteMatcherProvider<AppPageRouteMatcher> {
private readonly expression;
private readonly normalizers;
private readonly isTurbopack;
constructor(appDir: string, extensions: ReadonlyArray<string>, reader: FileReader, isTurbopack: boolean);
protected transform(files: ReadonlyArray<string>): Promise<ReadonlyArray<AppPageRouteMatcher>>;
}

View File

@@ -0,0 +1,90 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "DevAppPageRouteMatcherProvider", {
enumerable: true,
get: function() {
return DevAppPageRouteMatcherProvider;
}
});
const _apppageroutematcher = require("../../route-matchers/app-page-route-matcher");
const _routekind = require("../../route-kind");
const _filecacheroutematcherprovider = require("./file-cache-route-matcher-provider");
const _app = require("../../normalizers/built/app");
const _normalizecatchallroutes = require("../../../build/normalize-catchall-routes");
class DevAppPageRouteMatcherProvider extends _filecacheroutematcherprovider.FileCacheRouteMatcherProvider {
constructor(appDir, extensions, reader, isTurbopack){
super(appDir, reader);
this.normalizers = new _app.DevAppNormalizers(appDir, extensions, isTurbopack);
// Match any page file that ends with `/page.${extension}` or `/default.${extension}` under the app
// directory.
this.expression = new RegExp(`[/\\\\](page|default)\\.(?:${extensions.join('|')})$`);
this.isTurbopack = isTurbopack;
}
async transform(files) {
// Collect all the app paths for each page. This could include any parallel
// routes.
const cache = new Map();
const routeFilenames = new Array();
let appPaths = {};
for (const filename of files){
// If the file isn't a match for this matcher, then skip it.
if (!this.expression.test(filename)) continue;
let page = this.normalizers.page.normalize(filename);
// Validate that this is not an ignored page.
if (page.includes('/_')) continue;
// Turbopack uses the correct page name with the underscore normalized.
// TODO: Move implementation to packages/next/src/server/normalizers/built/app/app-page-normalizer.ts.
// The `includes('/_')` check above needs to be moved for that to work as otherwise `%5Fsegmentname`
// will result in `_segmentname` which hits that includes check and be skipped.
if (this.isTurbopack) {
page = page.replace(/%5F/g, '_');
}
// This is a valid file that we want to create a matcher for.
routeFilenames.push(filename);
const pathname = this.normalizers.pathname.normalize(filename);
const bundlePath = this.normalizers.bundlePath.normalize(filename);
// Save the normalization results.
cache.set(filename, {
page,
pathname,
bundlePath
});
if (pathname in appPaths) appPaths[pathname].push(page);
else appPaths[pathname] = [
page
];
}
(0, _normalizecatchallroutes.normalizeCatchAllRoutes)(appPaths);
// Make sure to sort parallel routes to make the result deterministic.
appPaths = Object.fromEntries(Object.entries(appPaths).map(([k, v])=>[
k,
v.sort()
]));
const matchers = [];
for (const filename of routeFilenames){
// Grab the cached values (and the appPaths).
const cached = cache.get(filename);
if (!cached) {
throw Object.defineProperty(new Error('Invariant: expected filename to exist in cache'), "__NEXT_ERROR_CODE", {
value: "E190",
enumerable: false,
configurable: true
});
}
const { pathname, page, bundlePath } = cached;
matchers.push(new _apppageroutematcher.AppPageRouteMatcher({
kind: _routekind.RouteKind.APP_PAGE,
pathname,
page,
bundlePath,
filename,
appPaths: appPaths[pathname]
}));
}
return matchers;
}
}
//# sourceMappingURL=dev-app-page-route-matcher-provider.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
import type { FileReader } from './helpers/file-reader/file-reader';
import { AppRouteRouteMatcher } from '../../route-matchers/app-route-route-matcher';
import { FileCacheRouteMatcherProvider } from './file-cache-route-matcher-provider';
export declare class DevAppRouteRouteMatcherProvider extends FileCacheRouteMatcherProvider<AppRouteRouteMatcher> {
private readonly normalizers;
private readonly appDir;
private readonly isTurbopack;
constructor(appDir: string, extensions: ReadonlyArray<string>, reader: FileReader, isTurbopack: boolean);
protected transform(files: ReadonlyArray<string>): Promise<ReadonlyArray<AppRouteRouteMatcher>>;
}

View File

@@ -0,0 +1,112 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "DevAppRouteRouteMatcherProvider", {
enumerable: true,
get: function() {
return DevAppRouteRouteMatcherProvider;
}
});
const _approuteroutematcher = require("../../route-matchers/app-route-route-matcher");
const _routekind = require("../../route-kind");
const _filecacheroutematcherprovider = require("./file-cache-route-matcher-provider");
const _isapprouteroute = require("../../../lib/is-app-route-route");
const _app = require("../../normalizers/built/app");
const _ismetadataroute = require("../../../lib/metadata/is-metadata-route");
const _getmetadataroute = require("../../../lib/metadata/get-metadata-route");
const _path = /*#__PURE__*/ _interop_require_default(require("../../../shared/lib/isomorphic/path"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
class DevAppRouteRouteMatcherProvider extends _filecacheroutematcherprovider.FileCacheRouteMatcherProvider {
constructor(appDir, extensions, reader, isTurbopack){
super(appDir, reader);
this.appDir = appDir;
this.isTurbopack = isTurbopack;
this.normalizers = new _app.DevAppNormalizers(appDir, extensions, isTurbopack);
}
async transform(files) {
const matchers = [];
for (const filename of files){
// Skip static metadata files as they are served from filesystem.
if ((0, _ismetadataroute.isStaticMetadataFile)(filename.replace(this.appDir, ''))) {
continue;
}
let page = this.normalizers.page.normalize(filename);
// If the file isn't a match for this matcher, then skip it.
if (!(0, _isapprouteroute.isAppRouteRoute)(page)) continue;
// Validate that this is not an ignored page.
if (page.includes('/_')) continue;
// Turbopack uses the correct page name with the underscore normalized.
// TODO: Move implementation to packages/next/src/server/normalizers/built/app/app-page-normalizer.ts.
// The `includes('/_')` check above needs to be moved for that to work as otherwise `%5Fsegmentname`
// will result in `_segmentname` which hits that includes check and be skipped.
if (this.isTurbopack) {
page = page.replace(/%5F/g, '_');
}
const pathname = this.normalizers.pathname.normalize(filename);
const bundlePath = this.normalizers.bundlePath.normalize(filename);
const ext = _path.default.extname(filename).slice(1);
const isEntryMetadataRouteFile = (0, _ismetadataroute.isMetadataRouteFile)(filename.replace(this.appDir, ''), [
ext
], true);
if (isEntryMetadataRouteFile && !(0, _ismetadataroute.isStaticMetadataRoute)(page)) {
// Matching dynamic metadata routes.
// Add 2 possibilities for both single and multiple routes:
{
// single:
// /sitemap.ts -> /sitemap.xml/route
// /icon.ts -> /icon/route
// We'll map the filename before normalization:
// sitemap.ts -> sitemap.xml/route.ts
// icon.ts -> icon/route.ts
const metadataPage = (0, _getmetadataroute.normalizeMetadataPageToRoute)(page, false);
const metadataPathname = (0, _getmetadataroute.normalizeMetadataPageToRoute)(pathname, false);
const metadataBundlePath = (0, _getmetadataroute.normalizeMetadataPageToRoute)(bundlePath, false);
const matcher = new _approuteroutematcher.AppRouteRouteMatcher({
kind: _routekind.RouteKind.APP_ROUTE,
page: metadataPage,
pathname: metadataPathname,
bundlePath: metadataBundlePath,
filename
});
matchers.push(matcher);
}
{
// multiple:
// /sitemap.ts -> /sitemap/[__metadata_id__]/route
// /icon.ts -> /icon/[__metadata_id__]/route
// We'll map the filename before normalization:
// sitemap.ts -> sitemap.xml/[__metadata_id__].ts
// icon.ts -> icon/[__metadata_id__].ts
const metadataPage = (0, _getmetadataroute.normalizeMetadataPageToRoute)(page, true);
const metadataPathname = (0, _getmetadataroute.normalizeMetadataPageToRoute)(pathname, true);
const metadataBundlePath = (0, _getmetadataroute.normalizeMetadataPageToRoute)(bundlePath, true);
const matcher = new _approuteroutematcher.AppRouteRouteMatcher({
kind: _routekind.RouteKind.APP_ROUTE,
page: metadataPage,
pathname: metadataPathname,
bundlePath: metadataBundlePath,
filename
});
matchers.push(matcher);
}
} else {
// Normal app routes.
matchers.push(new _approuteroutematcher.AppRouteRouteMatcher({
kind: _routekind.RouteKind.APP_ROUTE,
page,
pathname,
bundlePath,
filename
}));
}
}
return matchers;
}
}
//# sourceMappingURL=dev-app-route-route-matcher-provider.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,14 @@
import type { FileReader } from './helpers/file-reader/file-reader';
import { PagesAPIRouteMatcher } from '../../route-matchers/pages-api-route-matcher';
import type { LocaleRouteNormalizer } from '../../normalizers/locale-route-normalizer';
import { FileCacheRouteMatcherProvider } from './file-cache-route-matcher-provider';
export declare class DevPagesAPIRouteMatcherProvider extends FileCacheRouteMatcherProvider<PagesAPIRouteMatcher> {
private readonly pagesDir;
private readonly extensions;
private readonly localeNormalizer?;
private readonly expression;
private readonly normalizers;
constructor(pagesDir: string, extensions: ReadonlyArray<string>, reader: FileReader, localeNormalizer?: LocaleRouteNormalizer | undefined);
private test;
protected transform(files: ReadonlyArray<string>): Promise<ReadonlyArray<PagesAPIRouteMatcher>>;
}

View File

@@ -0,0 +1,77 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "DevPagesAPIRouteMatcherProvider", {
enumerable: true,
get: function() {
return DevPagesAPIRouteMatcherProvider;
}
});
const _pagesapiroutematcher = require("../../route-matchers/pages-api-route-matcher");
const _routekind = require("../../route-kind");
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
const _filecacheroutematcherprovider = require("./file-cache-route-matcher-provider");
const _pages = require("../../normalizers/built/pages");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
class DevPagesAPIRouteMatcherProvider extends _filecacheroutematcherprovider.FileCacheRouteMatcherProvider {
constructor(pagesDir, extensions, reader, localeNormalizer){
super(pagesDir, reader), this.pagesDir = pagesDir, this.extensions = extensions, this.localeNormalizer = localeNormalizer;
// Match any route file that ends with `/${filename}.${extension}` under the
// pages directory.
this.expression = new RegExp(`\\.(?:${extensions.join('|')})$`);
this.normalizers = new _pages.DevPagesNormalizers(pagesDir, extensions);
}
test(filename) {
// If the file does not end in the correct extension it's not a match.
if (!this.expression.test(filename)) return false;
// Pages API routes must exist in the pages directory with the `/api/`
// prefix. The pathnames being tested here though are the full filenames,
// so we need to include the pages directory.
// TODO: could path separator normalization be needed here?
if (filename.startsWith(_path.default.join(this.pagesDir, '/api/'))) return true;
for (const extension of this.extensions){
// We can also match if we have `pages/api.${extension}`, so check to
// see if it's a match.
if (filename === _path.default.join(this.pagesDir, `api.${extension}`)) {
return true;
}
}
return false;
}
async transform(files) {
const matchers = [];
for (const filename of files){
// If the file isn't a match for this matcher, then skip it.
if (!this.test(filename)) continue;
const pathname = this.normalizers.pathname.normalize(filename);
const page = this.normalizers.page.normalize(filename);
const bundlePath = this.normalizers.bundlePath.normalize(filename);
if (this.localeNormalizer) {
matchers.push(new _pagesapiroutematcher.PagesAPILocaleRouteMatcher({
kind: _routekind.RouteKind.PAGES_API,
pathname,
page,
bundlePath,
filename,
i18n: {}
}));
} else {
matchers.push(new _pagesapiroutematcher.PagesAPIRouteMatcher({
kind: _routekind.RouteKind.PAGES_API,
pathname,
page,
bundlePath,
filename
}));
}
}
return matchers;
}
}
//# sourceMappingURL=dev-pages-api-route-matcher-provider.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,14 @@
import type { FileReader } from './helpers/file-reader/file-reader';
import { PagesRouteMatcher } from '../../route-matchers/pages-route-matcher';
import type { LocaleRouteNormalizer } from '../../normalizers/locale-route-normalizer';
import { FileCacheRouteMatcherProvider } from './file-cache-route-matcher-provider';
export declare class DevPagesRouteMatcherProvider extends FileCacheRouteMatcherProvider<PagesRouteMatcher> {
private readonly pagesDir;
private readonly extensions;
private readonly localeNormalizer?;
private readonly expression;
private readonly normalizers;
constructor(pagesDir: string, extensions: ReadonlyArray<string>, reader: FileReader, localeNormalizer?: LocaleRouteNormalizer | undefined);
private test;
protected transform(files: ReadonlyArray<string>): Promise<ReadonlyArray<PagesRouteMatcher>>;
}

View File

@@ -0,0 +1,77 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "DevPagesRouteMatcherProvider", {
enumerable: true,
get: function() {
return DevPagesRouteMatcherProvider;
}
});
const _pagesroutematcher = require("../../route-matchers/pages-route-matcher");
const _routekind = require("../../route-kind");
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
const _filecacheroutematcherprovider = require("./file-cache-route-matcher-provider");
const _pages = require("../../normalizers/built/pages");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
class DevPagesRouteMatcherProvider extends _filecacheroutematcherprovider.FileCacheRouteMatcherProvider {
constructor(pagesDir, extensions, reader, localeNormalizer){
super(pagesDir, reader), this.pagesDir = pagesDir, this.extensions = extensions, this.localeNormalizer = localeNormalizer;
// Match any route file that ends with `/${filename}.${extension}` under the
// pages directory.
this.expression = new RegExp(`\\.(?:${extensions.join('|')})$`);
this.normalizers = new _pages.DevPagesNormalizers(pagesDir, extensions);
}
test(filename) {
// If the file does not end in the correct extension it's not a match.
if (!this.expression.test(filename)) return false;
// Pages routes must exist in the pages directory without the `/api/`
// prefix. The pathnames being tested here though are the full filenames,
// so we need to include the pages directory.
// TODO: could path separator normalization be needed here?
if (filename.startsWith(_path.default.join(this.pagesDir, '/api/'))) return false;
for (const extension of this.extensions){
// We can also match if we have `pages/api.${extension}`, so check to
// see if it's a match.
if (filename === _path.default.join(this.pagesDir, `api.${extension}`)) {
return false;
}
}
return true;
}
async transform(files) {
const matchers = [];
for (const filename of files){
// If the file isn't a match for this matcher, then skip it.
if (!this.test(filename)) continue;
const pathname = this.normalizers.pathname.normalize(filename);
const page = this.normalizers.page.normalize(filename);
const bundlePath = this.normalizers.bundlePath.normalize(filename);
if (this.localeNormalizer) {
matchers.push(new _pagesroutematcher.PagesLocaleRouteMatcher({
kind: _routekind.RouteKind.PAGES,
pathname,
page,
bundlePath,
filename,
i18n: {}
}));
} else {
matchers.push(new _pagesroutematcher.PagesRouteMatcher({
kind: _routekind.RouteKind.PAGES,
pathname,
page,
bundlePath,
filename
}));
}
}
return matchers;
}
}
//# sourceMappingURL=dev-pages-route-matcher-provider.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,9 @@
import type { RouteMatcher } from '../../route-matchers/route-matcher';
import { CachedRouteMatcherProvider } from '../helpers/cached-route-matcher-provider';
import type { FileReader } from './helpers/file-reader/file-reader';
/**
* This will memoize the matchers when the file contents are the same.
*/
export declare abstract class FileCacheRouteMatcherProvider<M extends RouteMatcher = RouteMatcher> extends CachedRouteMatcherProvider<M, ReadonlyArray<string>> {
constructor(dir: string, reader: FileReader);
}

View File

@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "FileCacheRouteMatcherProvider", {
enumerable: true,
get: function() {
return FileCacheRouteMatcherProvider;
}
});
const _cachedroutematcherprovider = require("../helpers/cached-route-matcher-provider");
class FileCacheRouteMatcherProvider extends _cachedroutematcherprovider.CachedRouteMatcherProvider {
constructor(dir, reader){
super({
load: async ()=>reader.read(dir),
compare: (left, right)=>{
if (left.length !== right.length) return false;
// Assuming the file traversal order is deterministic...
for(let i = 0; i < left.length; i++){
if (left[i] !== right[i]) return false;
}
return true;
}
});
}
}
//# sourceMappingURL=file-cache-route-matcher-provider.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../src/server/route-matcher-providers/dev/file-cache-route-matcher-provider.ts"],"sourcesContent":["import type { RouteMatcher } from '../../route-matchers/route-matcher'\nimport { CachedRouteMatcherProvider } from '../helpers/cached-route-matcher-provider'\nimport type { FileReader } from './helpers/file-reader/file-reader'\n\n/**\n * This will memoize the matchers when the file contents are the same.\n */\nexport abstract class FileCacheRouteMatcherProvider<\n M extends RouteMatcher = RouteMatcher,\n> extends CachedRouteMatcherProvider<M, ReadonlyArray<string>> {\n constructor(dir: string, reader: FileReader) {\n super({\n load: async () => reader.read(dir),\n compare: (left, right) => {\n if (left.length !== right.length) return false\n\n // Assuming the file traversal order is deterministic...\n for (let i = 0; i < left.length; i++) {\n if (left[i] !== right[i]) return false\n }\n\n return true\n },\n })\n }\n}\n"],"names":["FileCacheRouteMatcherProvider","CachedRouteMatcherProvider","constructor","dir","reader","load","read","compare","left","right","length","i"],"mappings":";;;;+BAOsBA;;;eAAAA;;;4CANqB;AAMpC,MAAeA,sCAEZC,sDAA0B;IAClCC,YAAYC,GAAW,EAAEC,MAAkB,CAAE;QAC3C,KAAK,CAAC;YACJC,MAAM,UAAYD,OAAOE,IAAI,CAACH;YAC9BI,SAAS,CAACC,MAAMC;gBACd,IAAID,KAAKE,MAAM,KAAKD,MAAMC,MAAM,EAAE,OAAO;gBAEzC,wDAAwD;gBACxD,IAAK,IAAIC,IAAI,GAAGA,IAAIH,KAAKE,MAAM,EAAEC,IAAK;oBACpC,IAAIH,IAAI,CAACG,EAAE,KAAKF,KAAK,CAACE,EAAE,EAAE,OAAO;gBACnC;gBAEA,OAAO;YACT;QACF;IACF;AACF","ignoreList":[0]}

View File

@@ -0,0 +1,15 @@
import type { FileReader } from './file-reader';
/**
* CachedFileReader will deduplicate requests made to the same folder structure
* to scan for files.
*/
export declare class BatchedFileReader implements FileReader {
private readonly reader;
private batch?;
constructor(reader: FileReader);
private schedulePromise?;
private schedule;
private getOrCreateBatch;
private load;
read(dir: string): Promise<ReadonlyArray<string>>;
}

View File

@@ -0,0 +1,106 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "BatchedFileReader", {
enumerable: true,
get: function() {
return BatchedFileReader;
}
});
class BatchedFileReader {
constructor(reader){
this.reader = reader;
}
schedule(callback) {
if (!this.schedulePromise) {
this.schedulePromise = Promise.resolve();
}
this.schedulePromise.then(()=>{
process.nextTick(callback);
});
}
getOrCreateBatch() {
// If there is an existing batch and it's not completed, then reuse it.
if (this.batch && !this.batch.completed) {
return this.batch;
}
const batch = {
completed: false,
directories: [],
callbacks: []
};
this.batch = batch;
this.schedule(async ()=>{
batch.completed = true;
if (batch.directories.length === 0) return;
// Collect all the results for each of the directories. If any error
// occurs, send the results back to the loaders.
let values;
try {
values = await this.load(batch.directories);
} catch (err) {
// Reject all the callbacks.
for (const { reject } of batch.callbacks){
reject(err);
}
return;
}
// Loop over all the callbacks and send them their results.
for(let i = 0; i < batch.callbacks.length; i++){
const value = values[i];
if (value instanceof Error) {
batch.callbacks[i].reject(value);
} else {
batch.callbacks[i].resolve(value);
}
}
});
return batch;
}
async load(directories) {
// Make a unique array of directories. This is what lets us de-duplicate
// loads for the same directory.
const unique = [
...new Set(directories)
];
const results = await Promise.all(unique.map(async (directory)=>{
let files;
let error;
try {
files = await this.reader.read(directory);
} catch (err) {
if (err instanceof Error) error = err;
}
return {
directory,
files,
error
};
}));
return directories.map((directory)=>{
const found = results.find((result)=>result.directory === directory);
if (!found) return [];
if (found.files) return found.files;
if (found.error) return found.error;
return [];
});
}
async read(dir) {
// Get or create a new file reading batch.
const batch = this.getOrCreateBatch();
// Push this directory into the batch to resolve.
batch.directories.push(dir);
// Push the promise handles into the batch (under the same index) so it can
// be resolved later when it's scheduled.
const promise = new Promise((resolve, reject)=>{
batch.callbacks.push({
resolve,
reject
});
});
return promise;
}
}
//# sourceMappingURL=batched-file-reader.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,30 @@
import type { FileReader } from './file-reader';
import type { RecursiveReadDirOptions } from '../../../../../lib/recursive-readdir';
export type DefaultFileReaderOptions = Pick<RecursiveReadDirOptions, 'pathnameFilter' | 'ignorePartFilter'>;
/**
* Reads all the files in the directory and its subdirectories following any
* symbolic links.
*/
export declare class DefaultFileReader implements FileReader {
/**
* Filter to ignore files with absolute pathnames. If undefined, no files are
* ignored.
*/
private readonly options;
/**
* Creates a new file reader.
*
* @param pathnameFilter filter to ignore files with absolute pathnames, false to ignore
* @param ignoreFilter filter to ignore files and directories with absolute pathnames, false to ignore
* @param ignorePartFilter filter to ignore files and directories with the pathname part, false to ignore
*/
constructor(options: Readonly<DefaultFileReaderOptions>);
/**
* Reads all the files in the directory and its subdirectories following any
* symbolic links.
*
* @param dir the directory to read
* @returns a promise that resolves to the list of files
*/
read(dir: string): Promise<ReadonlyArray<string>>;
}

View File

@@ -0,0 +1,42 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "DefaultFileReader", {
enumerable: true,
get: function() {
return DefaultFileReader;
}
});
const _recursivereaddir = require("../../../../../lib/recursive-readdir");
class DefaultFileReader {
/**
* Creates a new file reader.
*
* @param pathnameFilter filter to ignore files with absolute pathnames, false to ignore
* @param ignoreFilter filter to ignore files and directories with absolute pathnames, false to ignore
* @param ignorePartFilter filter to ignore files and directories with the pathname part, false to ignore
*/ constructor(options){
this.options = options;
}
/**
* Reads all the files in the directory and its subdirectories following any
* symbolic links.
*
* @param dir the directory to read
* @returns a promise that resolves to the list of files
*/ async read(dir) {
return (0, _recursivereaddir.recursiveReadDir)(dir, {
pathnameFilter: this.options.pathnameFilter,
ignorePartFilter: this.options.ignorePartFilter,
// We don't need to sort the results because we're not depending on the
// order of the results.
sortPathnames: false,
// We want absolute pathnames because we're going to be comparing them
// with other absolute pathnames.
relativePathnames: false
});
}
}
//# sourceMappingURL=default-file-reader.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../../../src/server/route-matcher-providers/dev/helpers/file-reader/default-file-reader.ts"],"sourcesContent":["import type { FileReader } from './file-reader'\nimport type { RecursiveReadDirOptions } from '../../../../../lib/recursive-readdir'\nimport { recursiveReadDir } from '../../../../../lib/recursive-readdir'\n\nexport type DefaultFileReaderOptions = Pick<\n RecursiveReadDirOptions,\n 'pathnameFilter' | 'ignorePartFilter'\n>\n\n/**\n * Reads all the files in the directory and its subdirectories following any\n * symbolic links.\n */\nexport class DefaultFileReader implements FileReader {\n /**\n * Filter to ignore files with absolute pathnames. If undefined, no files are\n * ignored.\n */\n private readonly options: Readonly<DefaultFileReaderOptions>\n\n /**\n * Creates a new file reader.\n *\n * @param pathnameFilter filter to ignore files with absolute pathnames, false to ignore\n * @param ignoreFilter filter to ignore files and directories with absolute pathnames, false to ignore\n * @param ignorePartFilter filter to ignore files and directories with the pathname part, false to ignore\n */\n constructor(options: Readonly<DefaultFileReaderOptions>) {\n this.options = options\n }\n\n /**\n * Reads all the files in the directory and its subdirectories following any\n * symbolic links.\n *\n * @param dir the directory to read\n * @returns a promise that resolves to the list of files\n */\n public async read(dir: string): Promise<ReadonlyArray<string>> {\n return recursiveReadDir(dir, {\n pathnameFilter: this.options.pathnameFilter,\n ignorePartFilter: this.options.ignorePartFilter,\n\n // We don't need to sort the results because we're not depending on the\n // order of the results.\n sortPathnames: false,\n\n // We want absolute pathnames because we're going to be comparing them\n // with other absolute pathnames.\n relativePathnames: false,\n })\n }\n}\n"],"names":["DefaultFileReader","constructor","options","read","dir","recursiveReadDir","pathnameFilter","ignorePartFilter","sortPathnames","relativePathnames"],"mappings":";;;;+BAaaA;;;eAAAA;;;kCAXoB;AAW1B,MAAMA;IAOX;;;;;;GAMC,GACDC,YAAYC,OAA2C,CAAE;QACvD,IAAI,CAACA,OAAO,GAAGA;IACjB;IAEA;;;;;;GAMC,GACD,MAAaC,KAAKC,GAAW,EAAkC;QAC7D,OAAOC,IAAAA,kCAAgB,EAACD,KAAK;YAC3BE,gBAAgB,IAAI,CAACJ,OAAO,CAACI,cAAc;YAC3CC,kBAAkB,IAAI,CAACL,OAAO,CAACK,gBAAgB;YAE/C,uEAAuE;YACvE,wBAAwB;YACxBC,eAAe;YAEf,sEAAsE;YACtE,iCAAiC;YACjCC,mBAAmB;QACrB;IACF;AACF","ignoreList":[0]}

View File

@@ -0,0 +1,8 @@
export interface FileReader {
/**
* Reads the directory contents recursively.
*
* @param dir directory to read recursively from
*/
read(dir: string): Promise<ReadonlyArray<string>> | ReadonlyArray<string>;
}

View File

@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
//# sourceMappingURL=file-reader.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":[],"names":[],"mappings":"","ignoreList":[]}