Comparing version 1.8.0 to 1.9.0
@@ -8,2 +8,9 @@ # Change Log | ||
## [1.9.0] - 2024-05-20 | ||
### Changed | ||
- `SsgConfig.outDir` is now `SsgConfig.getOutputPath(context)` | ||
- All steps configs now extend `SsgConfig` to benefit from output path resolution. | ||
## [1.8.0] - 2024-05-18 | ||
@@ -15,3 +22,2 @@ | ||
## [1.7.7] - 2024-05-17 | ||
@@ -18,0 +24,0 @@ |
@@ -1,3 +0,3 @@ | ||
import { SsgContext } from './SsgContext.js'; | ||
import { SsgContext } from "./SsgContext.js"; | ||
import { SsgFile } from "./util"; | ||
export type OutputFunc = (context: SsgContext, outputFile: SsgFile) => Promise<void>; |
@@ -1,3 +0,8 @@ | ||
export type SsgConfig = { | ||
outDir: string; | ||
}; | ||
import { SsgContext } from "./SsgContext"; | ||
export interface SsgConfig<C extends SsgContext = SsgContext> { | ||
/** | ||
* @param context | ||
* @return the file where to output. | ||
*/ | ||
getOutputPath(context: C): string; | ||
} |
@@ -0,1 +1,2 @@ | ||
/// <reference types="node" /> | ||
import { Logger } from "./Logger.js"; | ||
@@ -36,13 +37,16 @@ import { SsgFile } from "./util"; | ||
/** | ||
* Reads a file and assign it to the context input. | ||
* Reads a file and assign it to the context's `file`. | ||
* | ||
* @param fileName | ||
* @abstract | ||
* @param filePath | ||
*/ | ||
getInputFrom(fileName: string): SsgFile; | ||
read(filePath: string): SsgFile; | ||
/** | ||
* Reads or create (if not found) a file and assign it to the context output. | ||
* Reads a file and assign it to the context's `file`. | ||
* | ||
* By default, (if the file is not found), output contents are equal to input contents. | ||
* @abstract | ||
* @param filePath | ||
* @param encoding | ||
*/ | ||
getOutputFrom(filePath: string): SsgFile; | ||
newOutput(filePath: string, encoding?: BufferEncoding): SsgFile; | ||
} |
@@ -40,13 +40,4 @@ /// <reference types="node" /> | ||
pop(): SsgContext; | ||
getOutputFrom(filePath: string): SsgFile; | ||
getInputFrom(filePath: string): SsgFile; | ||
createOutput(filePath: string, encoding: BufferEncoding): SsgFile; | ||
/** | ||
* Reads a file in this context. | ||
* | ||
* @param fileName The name of the file. | ||
* @returns {SsgFile} | ||
* @protected | ||
*/ | ||
protected readFile(fileName: string): SsgFile; | ||
read(filePath: string): SsgFile; | ||
newOutput(filePath: string, encoding?: BufferEncoding): SsgFile; | ||
} |
@@ -79,24 +79,12 @@ import { ObjectUtil } from "./util/ObjectUtil.js"; | ||
} | ||
getOutputFrom(filePath) { | ||
var _a; | ||
let outFile; | ||
try { | ||
outFile = this.readFile(filePath); | ||
this.logger.debug("Read output file", outFile.name); | ||
} | ||
catch (e) { | ||
if (e.code === "ENOENT") { | ||
outFile = this.createOutput(filePath, ((_a = this._file) === null || _a === void 0 ? void 0 : _a.encoding) || "utf-8"); | ||
} | ||
else { | ||
throw e; | ||
} | ||
} | ||
return outFile; | ||
} | ||
getInputFrom(filePath) { | ||
this.file = this.readFile(filePath); | ||
read(filePath) { | ||
this.debug("Reading", filePath); | ||
this.file = filePath.endsWith(".html") | ||
? HtmlSsgFile.read(this, filePath) | ||
: SsgFile.read(this, filePath); | ||
return this.file; | ||
} | ||
createOutput(filePath, encoding) { | ||
newOutput(filePath, encoding) { | ||
var _a; | ||
if (encoding === void 0) { encoding = ((_a = this._file) === null || _a === void 0 ? void 0 : _a.encoding) || "utf-8"; } | ||
let outFile; | ||
@@ -124,16 +112,4 @@ let lang; | ||
} | ||
/** | ||
* Reads a file in this context. | ||
* | ||
* @param fileName The name of the file. | ||
* @returns {SsgFile} | ||
* @protected | ||
*/ | ||
readFile(fileName) { | ||
return fileName.endsWith(".html") | ||
? HtmlSsgFile.read(this, fileName) | ||
: SsgFile.read(this, fileName); | ||
} | ||
} | ||
SsgContextImpl.CONTEXT_PREFIX = "$context."; | ||
SsgContextImpl.DEFAULT_NAME = "Ssg"; |
@@ -13,3 +13,3 @@ import { SsgStep } from "../SsgStep.js"; | ||
protected contentsConfigs: ContentStepConfig<C>[]; | ||
protected output: OutputFunc; | ||
protected write: OutputFunc; | ||
/** | ||
@@ -22,5 +22,5 @@ * Logger name | ||
* @param contentsConfigs The content roots and associated replacements to perform. | ||
* @param output The function that writes the output contents once they are ready. | ||
* @param write The function that writes the output contents once they are ready. | ||
*/ | ||
constructor(contentsConfigs: ContentStepConfig<C>[], output: OutputFunc); | ||
constructor(contentsConfigs: ContentStepConfig<C>[], write: OutputFunc); | ||
execute(context: C): Promise<ContentStepResult>; | ||
@@ -27,0 +27,0 @@ protected processRoots(context: C, contentsConfig: ContentStepConfig): Promise<number>; |
@@ -10,7 +10,7 @@ import fs from "fs"; | ||
* @param contentsConfigs The content roots and associated replacements to perform. | ||
* @param output The function that writes the output contents once they are ready. | ||
* @param write The function that writes the output contents once they are ready. | ||
*/ | ||
constructor(contentsConfigs, output) { | ||
constructor(contentsConfigs, write) { | ||
this.contentsConfigs = contentsConfigs; | ||
this.output = output; | ||
this.write = write; | ||
/** | ||
@@ -61,13 +61,17 @@ * Logger name | ||
async processFile(context, filePath, contentsConfig) { | ||
context.debug("Processing file", filePath); | ||
context.file = context.getInputFrom(filePath); | ||
const outputPath = contentsConfig.getOutputFile(context); | ||
const outputFile = context.getOutputFrom(outputPath); | ||
context.file = context.read(filePath); | ||
const processed = this.shouldProcess(context, contentsConfig); | ||
if (processed) { | ||
context.debug("Processing", filePath); | ||
for (const replacement of contentsConfig.replacements) { | ||
await replacement.execute(context); | ||
} | ||
await this.output(context, outputFile); | ||
const outputPath = contentsConfig.getOutputPath(context); | ||
const output = context.newOutput(outputPath); | ||
context.debug("Writing", output.name); | ||
await this.write(context, output); | ||
} | ||
else { | ||
context.debug("Not orocessing", filePath); | ||
} | ||
return processed; | ||
@@ -86,3 +90,3 @@ } | ||
let inputHasChanged; | ||
const outputPath = contentsConfig.getOutputFile(context); | ||
const outputPath = contentsConfig.getOutputPath(context); | ||
const outputExists = fs.existsSync(outputPath); | ||
@@ -89,0 +93,0 @@ if (outputExists) { |
import { SsgContext } from "../../SsgContext"; | ||
import { ReplaceCommand } from "./replace"; | ||
export type ContentStepConfig<C extends SsgContext = SsgContext> = { | ||
import { SsgConfig } from "../../SsgConfig"; | ||
export interface ContentStepConfig<C extends SsgContext = SsgContext> extends SsgConfig { | ||
/** | ||
@@ -12,7 +13,2 @@ * The glob roots of contents to process. | ||
replacements: ReplaceCommand<C>[]; | ||
/** | ||
* @param context | ||
* @return the file where to output. | ||
*/ | ||
getOutputFile(context: C): string; | ||
}; | ||
} |
import { RegexReplaceCommand } from "../../RegexReplaceCommand.js"; | ||
import { RegexReplacer } from "../../RegexReplacer.js"; | ||
import { SsgContext } from "../../../../../SsgContext.js"; | ||
/** | ||
* Replaces by a value or another, depending on the evaluation of an expression. | ||
* Syntax is SSI-like: | ||
* <!--#if expr="someVar=someValue" -->result if true<!--#else-->result if false<!--#endif--> | ||
*/ | ||
export declare class SsiIfReplaceCommand extends RegexReplaceCommand { | ||
@@ -5,0 +10,0 @@ protected readonly replacer: { |
import { RegexReplaceCommand } from "../../RegexReplaceCommand.js"; | ||
/** | ||
* Replaces by a value or another, depending on the evaluation of an expression. | ||
* Syntax is SSI-like: | ||
* <!--#if expr="someVar=someValue" -->result if true<!--#else-->result if false<!--#endif--> | ||
*/ | ||
export class SsiIfReplaceCommand extends RegexReplaceCommand { | ||
@@ -3,0 +8,0 @@ constructor() { |
@@ -1,4 +0,8 @@ | ||
import { RegexReplaceCommand } from '../../RegexReplaceCommand.js'; | ||
import { RegexReplacer } from '../../RegexReplacer.js'; | ||
import { SsgContext } from '../../../../../SsgContext.js'; | ||
import { RegexReplaceCommand } from "../../RegexReplaceCommand.js"; | ||
import { RegexReplacer } from "../../RegexReplacer.js"; | ||
import { SsgContext } from "../../../../../SsgContext.js"; | ||
/** | ||
* Replaces a <!--*#config timefmt="someFormat"--><!--#flastmod virtual="\$DOCUMENT_URI"\s*--> | ||
* by the datetime of modification of the current file. | ||
*/ | ||
export declare class SsiLastModifiedReplaceCommand extends RegexReplaceCommand { | ||
@@ -5,0 +9,0 @@ protected options: Intl.DateTimeFormatOptions; |
@@ -1,2 +0,6 @@ | ||
import { RegexReplaceCommand } from '../../RegexReplaceCommand.js'; | ||
import { RegexReplaceCommand } from "../../RegexReplaceCommand.js"; | ||
/** | ||
* Replaces a <!--*#config timefmt="someFormat"--><!--#flastmod virtual="\$DOCUMENT_URI"\s*--> | ||
* by the datetime of modification of the current file. | ||
*/ | ||
export class SsiLastModifiedReplaceCommand extends RegexReplaceCommand { | ||
@@ -3,0 +7,0 @@ constructor(options) { |
@@ -5,2 +5,6 @@ import { SsgStep } from './SsgStep.js'; | ||
import { SsgConfig } from '../SsgConfig'; | ||
export interface CopyStepConfig extends SsgConfig { | ||
readonly copies: string[]; | ||
readonly options?: IOptions; | ||
} | ||
export type CopyStepResult = { | ||
@@ -13,8 +17,6 @@ files: string[]; | ||
export declare class CopyStep<C extends SsgContext = SsgContext> implements SsgStep<C, CopyStepResult> { | ||
protected copies: string[]; | ||
protected config: SsgConfig; | ||
protected options?: IOptions | undefined; | ||
protected config: CopyStepConfig; | ||
readonly name = "copy"; | ||
constructor(copies: string[], config: SsgConfig, options?: IOptions | undefined); | ||
constructor(config: CopyStepConfig); | ||
execute(context: SsgContext): Promise<CopyStepResult>; | ||
} |
@@ -1,3 +0,4 @@ | ||
import { FileUtil } from '../util/index.js'; | ||
import * as process from 'process'; | ||
import { FileUtil } from "../util"; | ||
import path from "path"; | ||
/** | ||
@@ -7,14 +8,13 @@ * Perform copies to out directory. | ||
export class CopyStep { | ||
constructor(copies, config, options) { | ||
this.copies = copies; | ||
constructor(config) { | ||
this.config = config; | ||
this.options = options; | ||
this.name = 'copy'; | ||
} | ||
async execute(context) { | ||
const copies = this.copies; | ||
const dest = this.config.outDir; | ||
const copies = this.config.copies; | ||
const destPath = this.config.getOutputPath(context); | ||
const dest = path.dirname(destPath); | ||
try { | ||
context.log('Copying to', dest, copies); | ||
const copiedFiles = await FileUtil.ssgCopy(dest, copies, this.options); | ||
const copiedFiles = await FileUtil.ssgCopy(dest, copies, this.config.options); | ||
const cwd = process.cwd(); | ||
@@ -21,0 +21,0 @@ const files = copiedFiles.map(file => file.startsWith(cwd) ? file.substring(cwd.length + 1) : file); |
@@ -5,2 +5,16 @@ import { SsgStep } from "./SsgStep.js"; | ||
import { SsgFile } from "../util"; | ||
export interface DirectoryStepConfig extends SsgConfig { | ||
/** | ||
* A list of directories to look into. | ||
*/ | ||
readonly rootDirs: string[]; | ||
/** | ||
* A list of directories to avoid looking into. | ||
*/ | ||
readonly excludedDirs: string[]; | ||
/** | ||
* The name of the file containing the <--#echo var="directories"--> tag | ||
*/ | ||
readonly templateFileName: string; | ||
} | ||
export interface DirectoryResult { | ||
@@ -15,6 +29,3 @@ directoryCount: number; | ||
export declare abstract class DirectoryStep<C extends SsgContext = SsgContext> implements SsgStep<C, DirectoryResult> { | ||
readonly rootDirs: string[]; | ||
protected excludedDirs: string[]; | ||
protected templateFileName: string; | ||
protected config: SsgConfig; | ||
protected config: DirectoryStepConfig; | ||
readonly name: string; | ||
@@ -24,9 +35,6 @@ /** | ||
* | ||
* @param rootDirs A list of directories to look into. | ||
* @param excludedDirs A list of directories to avoid looking into. | ||
* @param templateFileName The name of the file containing the <--#echo var="directories"--> tag | ||
* @param config The SSG configuration. | ||
* @param config The step configuration. | ||
* @param name The step name ("directory" by default) | ||
*/ | ||
constructor(rootDirs: string[], excludedDirs: string[], templateFileName: string, config: SsgConfig, name?: string); | ||
constructor(config: DirectoryStepConfig, name?: string); | ||
/** | ||
@@ -33,0 +41,0 @@ * Execute the directory step by: |
@@ -1,2 +0,1 @@ | ||
import path from "path"; | ||
import { FileUtil } from "../util"; | ||
@@ -12,12 +11,6 @@ /** | ||
* | ||
* @param rootDirs A list of directories to look into. | ||
* @param excludedDirs A list of directories to avoid looking into. | ||
* @param templateFileName The name of the file containing the <--#echo var="directories"--> tag | ||
* @param config The SSG configuration. | ||
* @param config The step configuration. | ||
* @param name The step name ("directory" by default) | ||
*/ | ||
constructor(rootDirs, excludedDirs, templateFileName, config, name = "directory") { | ||
this.rootDirs = rootDirs; | ||
this.excludedDirs = excludedDirs; | ||
this.templateFileName = templateFileName; | ||
constructor(config, name = "directory") { | ||
this.config = config; | ||
@@ -33,7 +26,7 @@ this.name = name; | ||
async execute(context) { | ||
context.file = context.getInputFrom(this.templateFileName); | ||
const outputFilePath = path.join(this.config.outDir, this.templateFileName); | ||
const outputFile = context.getOutputFrom(outputFilePath); | ||
const dirNames = (await this.findDirs(this.rootDirs)) | ||
.filter(dirName => !this.excludedDirs.includes(dirName)); | ||
context.file = context.read(this.config.templateFileName); | ||
const outputFilePath = this.config.getOutputPath(context); | ||
const outputFile = context.newOutput(outputFilePath); | ||
const dirNames = (await this.findDirs(this.config.rootDirs)) | ||
.filter(dirName => !this.config.excludedDirs.includes(dirName)); | ||
await this.processDirs(context, dirNames, outputFile); | ||
@@ -56,3 +49,3 @@ return { directoryCount: dirNames.length }; | ||
const dirs = (await this.findDirs([baseDir + "/"])) | ||
.filter(dirName => !this.excludedDirs.includes(dirName)); | ||
.filter(dirName => !this.config.excludedDirs.includes(dirName)); | ||
for (const dir of dirs) { | ||
@@ -59,0 +52,0 @@ subDirs = subDirs.concat(await this.findDirs([dir + "/*/"])); |
@@ -1,5 +0,5 @@ | ||
import { TestRunner } from '@javarome/testscript'; | ||
let runner = new TestRunner(["**/*Test.ts"], ['node_modules/**/*.*']); | ||
import { TestRunner } from "@javarome/testscript"; | ||
let runner = new TestRunner(["**/*Test.ts"], ["node_modules/**/*.*"]); | ||
runner.run().then(result => { | ||
console.log('Executed', result.suites.length, 'test suites in', runner.durationStr(result.duration)); | ||
}); |
@@ -5,3 +5,3 @@ { | ||
"author": "Jérôme Beau <javarome@gmail.com> (https://javarome.com)", | ||
"version": "1.8.0", | ||
"version": "1.9.0", | ||
"description": "Static Site Generation TypeScript API", | ||
@@ -8,0 +8,0 @@ "exports": "./dist/src/index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
84632
2086