Compare commits

...

15 commits

11 changed files with 191 additions and 164 deletions

View file

@ -31,7 +31,7 @@ steps:
# event:
# - tag
# ref:
# - refs/tags/v[0-9].[0-9].[0-9]
# - refs/tags/v[0-9]*.[0-9]*.[0-9]*
- name: prepare release
image: manuth/silverstripe-dev
commands:

View file

@ -7,4 +7,4 @@
"msjsdiag.debugger-for-chrome",
"neilbrayfield.php-docblocker"
]
}
}

18
.vscode/launch.json vendored
View file

@ -4,6 +4,24 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"args": [
"Watch"
],
"name": "Execute Watch Task",
"program": "${workspaceFolder}/node_modules/gulp/bin/gulp.js",
"request": "launch",
"skipFiles": [
"<node_internals>/**"
],
"type": "pwa-node",
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/gulpfile.ts",
"${workspaceFolder}/gulp/**/*.ts",
"!**/node_modules/**"
]
},
{
"type": "chrome",
"request": "launch",

20
.vscode/tasks.json vendored
View file

@ -34,17 +34,17 @@
{
"base": "$gulp-tsc",
"background": {
"activeOnStart": false,
"beginsPattern": "^(Starting compilation in watch mode|File change detected. Starting incremental compilation)",
"endsPattern": "^Found \\d+ errors. Watching for file changes."
"activeOnStart": true,
"beginsPattern": "(Starting compilation in watch mode|File change detected. Starting incremental compilation)",
"endsPattern": "Found \\d+ errors. Watching for file changes."
}
},
{
"base": "$node-sass",
"background": {
"activeOnStart": false,
"beginsPattern": "^Rebuilding scss-code.",
"endsPattern": "^Rebuilding scss-code finished."
"activeOnStart": true,
"beginsPattern": "Building scss-code.",
"endsPattern": "Building scss-code finished."
}
}
],
@ -63,16 +63,16 @@
"base": "$gulp-tsc",
"background": {
"activeOnStart": false,
"beginsPattern": "^(Starting compilation in watch mode|File change detected. Starting incremental compilation)",
"endsPattern": "^Found \\d+ errors. Watching for file changes."
"beginsPattern": "(Starting compilation in watch mode|File change detected. Starting incremental compilation)",
"endsPattern": "Found \\d+ errors. Watching for file changes."
}
},
{
"base": "$node-sass",
"background": {
"activeOnStart": false,
"beginsPattern": "^Rebuilding scss-code.",
"endsPattern": "^Rebuilding scss-code finished."
"beginsPattern": "Building scss-code.",
"endsPattern": "Building scss-code finished."
}
}
],

View file

@ -1,4 +1,4 @@
import Path = require("upath");
import { dirname, join } from "upath";
/**
* Provides settings for building the project.
@ -100,7 +100,7 @@ export class Settings
*/
public RootPath(...path: string[]): string
{
return Path.join(Path.dirname(__dirname), ...path);
return join(dirname(__dirname), ...path);
}
/**

View file

@ -1,19 +1,18 @@
import { Server, Socket } from "net";
import browserSync = require("browser-sync");
import browserify = require("browserify");
import log = require("fancy-log");
import FileSystem = require("fs-extra");
import { TaskFunction } from "gulp";
import gulp = require("gulp");
import logger = require("fancy-log");
import { emptyDir, mkdirp, pathExists, remove } from "fs-extra";
import { dest, parallel, series, src, TaskFunction, watch } from "gulp";
import gulpIf = require("gulp-if");
import rename = require("gulp-rename");
import sass = require("gulp-sass");
import terser = require("gulp-terser");
import merge = require("merge-stream");
import minimist = require("minimist");
import PromiseQueue = require("promise-queue");
import { parseArgsStringToArgv } from "string-argv";
import Path = require("upath");
import tsify = require("tsify");
import { changeExt, dirname, join, parse, relative } from "upath";
import buffer = require("vinyl-buffer");
import vinylSourceStream = require("vinyl-source-stream");
import Watchify = require("watchify");
@ -104,16 +103,16 @@ export async function Clean(): Promise<void>
for (let directory of directories)
{
await FileSystem.emptyDir(settings.RootPath(directory));
await emptyDir(settings.RootPath(directory));
}
if (await FileSystem.pathExists(settings.TestThemePath()))
if (await pathExists(settings.TestThemePath()))
{
await FileSystem.remove(settings.TestThemePath());
await remove(settings.TestThemePath());
}
await FileSystem.mkdirp(settings.TestThemePath());
await FileSystem.remove(settings.TestThemePath());
await mkdirp(settings.TestThemePath());
await remove(settings.TestThemePath());
// eslint-disable-next-line @typescript-eslint/no-var-requires
await require("create-symlink")(settings.RootPath(), settings.TestThemePath(), { type: "junction" });
}
@ -194,31 +193,39 @@ function BrowserSync(filePath?: string): TaskFunction
*/
export async function Build(): Promise<void>
{
if (settings.Watch)
{
log.info(watchStartMessage);
return new Promise(
(resolve, reject) =>
{
if (settings.Watch)
{
syncer.init({
open: false,
proxy: "http://localhost",
port: 3000,
ui: {
port: 3001
},
ghostMode: false,
online: false
});
syncer.init({
open: false,
proxy: "http://localhost",
port: 3000,
ui: {
port: 3001
},
ghostMode: false,
online: false
watch(settings.ThemeSource("**"), { usePolling: true }, series(Theme, BrowserSync("*.css")));
watch(settings.TemplateSource("**"), { usePolling: true }, series(Templates, BrowserSync()));
}
parallel(Library, Theme, Templates)(
(error) =>
{
if (error)
{
reject(error);
}
else
{
resolve();
}
});
});
gulp.watch(settings.ThemeSource("**"), { usePolling: true }, gulp.series(Theme, BrowserSync("*.css")));
gulp.watch(settings.TemplateSource("**"), { usePolling: true }, gulp.series(Templates, BrowserSync()));
}
await Promise.all(
[
Library(),
Theme(),
Templates()
]);
}
/**
@ -227,10 +234,11 @@ export async function Build(): Promise<void>
* @returns
* The pipeline to execute.
*/
export async function Library(): Promise<NodeJS.ReadWriteStream>
export function Library(): NodeJS.ReadWriteStream
{
let streams: Array<Promise<NodeJS.ReadWriteStream>> = [];
let queue = new PromiseQueue();
let errorMessages: string[] = [];
let streams: NodeJS.ReadWriteStream[] = [];
let queue: NodeJS.ReadWriteStream[] = [];
let tsConfigFile = settings.TypeScriptProjectRoot("tsconfig.json");
// eslint-disable-next-line @typescript-eslint/no-var-requires
let tsConfig = require(tsConfigFile);
@ -242,21 +250,28 @@ export async function Library(): Promise<NodeJS.ReadWriteStream>
debug: settings.Debug
};
{
let errorMessages: string[] = [];
let files = (tsConfig.files as string[]).map(
(file) => Path.relative(settings.TypeScriptSourceRoot(), settings.TypeScriptProjectRoot(file)));
let files = (tsConfig.files as string[]).map(
(file) => relative(settings.TypeScriptSourceRoot(), settings.TypeScriptProjectRoot(file)));
for (let file of files)
if (settings.Watch)
{
logger.info(watchStartMessage);
}
for (let file of files)
{
let builder = (): NodeJS.ReadWriteStream =>
{
let stream: NodeJS.ReadWriteStream;
let bundler = browserify(
{
...optionBase,
basedir: settings.LibraryPath(Path.dirname(file)),
basedir: settings.LibraryPath(dirname(file)),
entries: [
settings.TypeScriptSourceRoot(file)
],
standalone: Path.join(Path.dirname(file), Path.parse(file).name)
standalone: join(dirname(file), parse(file).name)
});
if (settings.Watch)
@ -265,90 +280,86 @@ export async function Library(): Promise<NodeJS.ReadWriteStream>
}
bundler.plugin(
// eslint-disable-next-line @typescript-eslint/no-var-requires
require("tsify"),
tsify,
{
project: tsConfigFile
});
let bundle = async (): Promise<NodeJS.ReadWriteStream> =>
{
return new Promise<NodeJS.ReadWriteStream>(
(resolve) =>
stream = bundler.bundle().on(
"error",
(error) =>
{
let message: string = error.message;
if (!errorMessages.includes(message))
{
let stream = bundler.bundle().on(
"error",
(error) =>
{
let message: string = error.message;
let result = new RegExp(`^(${error["fileName"]})\\((\\d+|\\d+(,\\d+){1,3})\\): .* TS([\\d]+): (.*)$`).exec(message);
errorMessages.push(message);
console.log(`${relative(process.cwd(), result[1])}(${result[2]}): ${result[4]} ${result[5]}`);
}
}
).pipe(
vinylSourceStream(changeExt(file, "js"))
).pipe(
buffer()
).pipe(
gulpIf(
!settings.Debug,
terser()
)
).pipe(
dest(settings.LibraryPath())
).on(
"end",
() =>
{
if (settings.Watch)
{
if (queue.includes(stream))
{
queue.splice(queue.indexOf(stream), 1);
}
if (!errorMessages.includes(message))
{
let result = new RegExp(`^(${error["fileName"]})\\((\\d+|\\d+(,\\d+){1,3})\\): .* TS([\\d]+): (.*)$`).exec(message);
errorMessages.push(message);
console.log(`${Path.relative(process.cwd(), result[1])}(${result[2]}): ${result[4]} ${result[5]}`);
}
if (queue.length === 0)
{
logger.info(watchFinishMessage(errorMessages.length));
if (errorMessages.length === 0)
{
syncer.reload("*.js");
}
).pipe(
vinylSourceStream(Path.changeExt(file, "js"))
).pipe(
buffer()
).pipe(
gulpIf(
!settings.Debug,
terser()
)
).pipe(
gulp.dest(settings.LibraryPath())
);
stream.on(
"end",
() =>
{
if (settings.Watch && ((queue.getQueueLength() + queue.getPendingLength()) === 1))
{
if (errorMessages.length === 0)
{
syncer.reload("*.js");
}
log.info(watchFinishMessage(errorMessages.length));
}
errorMessages.splice(0, errorMessages.length);
resolve(stream);
});
});
};
errorMessages.splice(0, errorMessages.length);
}
}
});
if (settings.Watch)
{
bundler.on(
bundler.once(
"update",
() =>
{
if ((queue.getQueueLength() + queue.getPendingLength()) === 0)
console.log(`Update called for ${file}: ${queue.length}`);
if (queue.length === 0)
{
log.info(incrementalMessage);
logger.info(incrementalMessage);
}
queue.add(
async () =>
{
return bundle();
});
queue.push(builder());
});
}
let build = (): Promise<NodeJS.ReadWriteStream> => queue.add(bundle);
build.displayName = Build.displayName;
build.description = Build.description;
streams.push(build());
}
return stream;
};
let stream = builder();
queue.push(stream);
streams.push(stream);
}
return merge(await Promise.all(streams)) as NodeJS.ReadWriteStream;
return merge(streams);
}
Library.description = "Builds the TypeScript- and JavaScript-library.";
@ -359,14 +370,14 @@ Library.description = "Builds the TypeScript- and JavaScript-library.";
* @returns
* The pipeline to execute.
*/
export async function Theme(): Promise<NodeJS.ReadWriteStream>
export function Theme(): NodeJS.ReadWriteStream
{
if (settings.Watch)
{
console.log("Rebuilding scss-code.");
logger.info("Building scss-code.");
}
return gulp.src(
return src(
settings.ThemeSource("main.scss"),
{
sourcemaps: settings.Debug,
@ -400,7 +411,7 @@ export async function Theme(): Promise<NodeJS.ReadWriteStream>
parsedPath.basename = "mantra";
})
).pipe(
gulp.dest(
dest(
settings.StylePath(),
settings.Debug ?
{
@ -413,7 +424,7 @@ export async function Theme(): Promise<NodeJS.ReadWriteStream>
{
if (settings.Watch)
{
console.log("Rebuilding scss-code finished.");
logger.info("Building scss-code finished.");
}
});
}
@ -428,9 +439,9 @@ Theme.description = "Builds the theme.";
*/
export function Templates(): NodeJS.ReadWriteStream
{
return gulp.src(
return src(
settings.TemplateSource("**")).pipe(
gulp.dest(settings.TemplatePath()));
dest(settings.TemplatePath()));
}
Templates.description = "Builds the templates.";
@ -461,7 +472,7 @@ export async function Stop(): Promise<void>
}
catch
{
log.info("The specified task is not running.");
logger.info("The specified task is not running.");
}
}

43
package-lock.json generated
View file

@ -74,6 +74,17 @@
}
}
},
"@es-joy/jsdoccomment": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.4.4.tgz",
"integrity": "sha512-ua4qDt9dQb4qt5OI38eCZcQZYE5Bq3P0GzgvDARdT8Lt0mAUpxKTPy8JGGqEvF77tG1irKDZ3WreeezEa3P43w==",
"dev": true,
"requires": {
"comment-parser": "^1.1.5",
"esquery": "^1.4.0",
"jsdoctypeparser": "^9.0.0"
}
},
"@eslint/eslintrc": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz",
@ -130,9 +141,9 @@
}
},
"@manuth/eslint-plugin-typescript": {
"version": "2.3.9",
"resolved": "https://registry.npmjs.org/@manuth/eslint-plugin-typescript/-/eslint-plugin-typescript-2.3.9.tgz",
"integrity": "sha512-FkomtLTmkza9sSDOGAOhESrTxgVsQqQbgWs4aWubWGMRnRsjYrNVeaq5sHJMy9Tcovn6hccqSOjAwWxdmIYjkg==",
"version": "2.3.10",
"resolved": "https://registry.npmjs.org/@manuth/eslint-plugin-typescript/-/eslint-plugin-typescript-2.3.10.tgz",
"integrity": "sha512-xxYj3W9ZtuzEpFt21NtpPW4PHdFLEsh7GDjJ6oxI3SdAzC8cKk4T1erqCOOiYDeZrhwv4YiACxFGM6gs/yXrCw==",
"dev": true,
"requires": {
"lodash.merge": "^4.6.2",
@ -782,12 +793,6 @@
"integrity": "sha1-akDsfr0kGO5p7jl+SOQhaSaKEL8=",
"dev": true
},
"@types/promise-queue": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@types/promise-queue/-/promise-queue-2.2.0.tgz",
"integrity": "sha512-9QLtid6GxEWqpF+QImxBRG6bSVOHtpAm2kXuIyEvZBbSOupLvqhhJv8uaHbS8kUL8FDjzH3RWcSyC/52WOVtGw==",
"dev": true
},
"@types/serve-static": {
"version": "1.13.9",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz",
@ -3713,13 +3718,15 @@
}
},
"eslint-plugin-jsdoc": {
"version": "32.3.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-32.3.4.tgz",
"integrity": "sha512-xSWfsYvffXnN0OkwLnB7MoDDDDjqcp46W7YlY1j7JyfAQBQ+WnGCfLov3gVNZjUGtK9Otj8mEhTZTqJu4QtIGA==",
"version": "34.0.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-34.0.1.tgz",
"integrity": "sha512-fXFyhM571aW1Eg5Z9INobK1VeMIcfflY4cnqDYFf5KRUwcR5R+TQIC6pU2C+4xA84s7lML3zi7UIbPOWBjU1YQ==",
"dev": true,
"requires": {
"@es-joy/jsdoccomment": "^0.4.4",
"comment-parser": "1.1.5",
"debug": "^4.3.1",
"esquery": "^1.4.0",
"jsdoctypeparser": "^9.0.0",
"lodash": "^4.17.21",
"regextras": "^0.7.1",
@ -7208,12 +7215,6 @@
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"dev": true
},
"promise-queue": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.5.tgz",
"integrity": "sha1-L29ffA9tCBCelnZZx5uIqe1ek7Q=",
"dev": true
},
"pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
@ -9086,9 +9087,9 @@
}
},
"tsify": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/tsify/-/tsify-5.0.3.tgz",
"integrity": "sha512-Cg/3efnvTrU7L4gnAfXt8p6dp+WefE28qItDKQj4lN0X9Jw2KS2EWKh5/dizXwfVNbT0guAoUce8CqCDWjFDLg==",
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/tsify/-/tsify-5.0.4.tgz",
"integrity": "sha512-XAZtQ5OMPsJFclkZ9xMZWkSNyMhMxEPsz3D2zu79yoKorH9j/DT4xCloJeXk5+cDhosEibu4bseMVjyPOAyLJA==",
"dev": true,
"requires": {
"convert-source-map": "^1.1.0",

View file

@ -19,7 +19,7 @@
},
"dependencies": {},
"devDependencies": {
"@manuth/eslint-plugin-typescript": "^2.3.9",
"@manuth/eslint-plugin-typescript": "^2.3.10",
"@manuth/tsconfig": "^1.2.9",
"@manuth/typescript-eslint-plugin": "^1.3.5",
"@types/bootstrap": "^5.0.13",
@ -35,22 +35,21 @@
"@types/jquery": "^3.5.5",
"@types/merge-stream": "^1.1.2",
"@types/minimist": "^1.2.1",
"@types/node": "^15.0.1",
"@types/promise-queue": "^2.2.0",
"@types/node": "^15.0.2",
"@types/vinyl-buffer": "^1.0.0",
"@types/vinyl-source-stream": "0.0.30",
"@types/watchify": "^3.11.0",
"@typescript-eslint/eslint-plugin": "^4.22.0",
"@typescript-eslint/eslint-plugin-tslint": "^4.22.0",
"@typescript-eslint/parser": "^4.22.0",
"@typescript-eslint/eslint-plugin": "^4.23.0",
"@typescript-eslint/eslint-plugin-tslint": "^4.23.0",
"@typescript-eslint/parser": "^4.23.0",
"bootstrap": "^5.0.0",
"browser-sync": "^2.26.14",
"browserify": "^17.0.0",
"create-symlink": "^1.0.0",
"eslint": "^7.25.0",
"eslint-plugin-deprecation": "^1.2.0",
"eslint": "^7.26.0",
"eslint-plugin-deprecation": "^1.2.1",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsdoc": "^32.3.3",
"eslint-plugin-jsdoc": "^34.0.1",
"fancy-log": "^1.3.3",
"fs-extra": "^10.0.0",
"gulp": "^4.0.2",
@ -63,10 +62,9 @@
"minimist": "^1.2.5",
"node-sass-tilde-importer": "^1.0.2",
"popper.js": "^1.16.0",
"promise-queue": "^2.2.5",
"string-argv": "^0.3.1",
"ts-node": "^9.1.1",
"tsify": "^5.0.3",
"tsify": "^5.0.4",
"tslint": "^6.1.3",
"typescript": "^4.2.4",
"typescript-tslint-plugin": "^1.0.1",

View file

@ -13,4 +13,4 @@
"exclude": [
"./src/tests/**/*"
]
}
}

View file

@ -1,4 +1,3 @@
<!doctype html>
<html class="h-100">
<head>
@ -57,4 +56,4 @@
$Form
</main>
</body>
</html>
</html>

View file

@ -1 +1 @@
$tagline-font-size: $small-font-size / 2;
$tagline-font-size: $small-font-size / 2;