Fix bin/publish: copy docs.dist from project root

Fix bin/publish: use correct .env path for rspade_system
Fix bin/publish script: prevent grep exit code 1 from terminating script

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-10-21 02:08:33 +00:00
commit f6fac6c4bc
79758 changed files with 10547827 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
class BuildCallbackPlugin {
/**
* Create a new plugin instance.
*
* @param {(stats: import("webpack").Stats) => any|Promise<any>} callback
*/
constructor(callback) {
this.callback = callback;
}
/**
* Apply the plugin.
*
* @param {import("webpack").Compiler} compiler
*/
apply(compiler) {
compiler.hooks.done.tapPromise('BuildCallbackPlugin', async stats => {
return await this.callback(stats);
});
}
}
module.exports = BuildCallbackPlugin;

View File

@@ -0,0 +1,236 @@
const _ = require('lodash');
const chalk = require('chalk');
const Table = require('cli-table3');
const readline = require('readline');
const stripAnsi = require('strip-ansi');
const { formatSize } = require('webpack/lib/SizeFormatHelpers');
const { version } = require('../../package.json');
/**
* @typedef {object} BuildOutputOptions
* @property {boolean} clearConsole
* @property {boolean} showRelated
**/
/**
* @typedef {object} StatsAsset
* @property {string} name
* @property {number} size
* @property {StatsAsset[]|{}} related
**/
/**
* @typedef {object} StatsData
* @property {StatsAsset[]} assets
**/
class BuildOutputPlugin {
/**
*
* @param {BuildOutputOptions} options
*/
constructor(options) {
this.options = options;
this.patched = false;
}
/**
* Apply the plugin.
*
* @param {import("webpack").Compiler} compiler
*/
apply(compiler) {
// TODO: Refactor setup to allow removing this check
if (process.env.NODE_ENV === 'test') {
return;
}
compiler.hooks.done.tap('BuildOutputPlugin', stats => {
if (stats.hasErrors()) {
return false;
}
if (this.options.clearConsole) {
this.clearConsole();
}
let data = stats.toJson({
assets: true,
builtAt: true,
hash: true,
performance: true,
relatedAssets: this.options.showRelated
});
this.heading(`Laravel Mix v${version}`);
console.log(chalk.green.bold(`✔ Compiled Successfully in ${data.time}ms`));
if (data.assets.length) {
console.log(this.statsTable(data));
}
});
}
/**
* Print a block section heading.
*
* @param {string} text
*/
heading(text) {
console.log();
console.log(chalk.bgBlue.white.bold(this.section(text)));
console.log();
}
/**
* Create a block section.
*
* @param {string} text
*/
section(text) {
const padLength = 3;
const padding = ' '.repeat(padLength);
text = `${padding}${text}${padding}`;
const line = ' '.repeat(text.length);
return `${line}\n${text}\n${line}`;
}
/**
* Generate the stats table.
*
* @param {StatsData} data
* @returns {string}
*/
statsTable(data) {
const assets = this.sortAssets(data);
const table = new Table({
head: [chalk.bold('File'), chalk.bold('Size')],
colWidths: [35],
colAligns: ['right'],
style: {
head: [],
compact: true
}
});
for (const asset of assets) {
table.push([chalk.green(asset.name), formatSize(asset.size)]);
}
this.extendTableWidth(table);
this.monkeyPatchTruncate();
return table.toString();
}
/**
*
* @param {StatsData} data
*/
sortAssets(data) {
let assets = data.assets;
assets = _.flatMap(assets, asset => [
asset,
...(Array.isArray(asset.related) ? asset.related : [])
]);
assets = _.orderBy(assets, ['name', 'size'], ['asc', 'asc']);
return assets;
}
/**
* Clear the entire screen.
*/
clearConsole() {
const blank = '\n'.repeat(process.stdout.rows);
console.log(blank);
readline.cursorTo(process.stdout, 0, 0);
readline.clearScreenDown(process.stdout);
}
/**
* Extend the width of the table
*
* Currently only increases the file column size
*
* @param {import("cli-table3").Table} table
* @param {number|null} targetWidth
* @param {number} maxWidth
*/
extendTableWidth(table, targetWidth = null, maxWidth = Infinity) {
targetWidth = targetWidth === null ? process.stdout.columns : targetWidth;
if (!targetWidth) {
return;
}
const tableWidth = this.calculateTableWidth(table);
const fileColIncrease = Math.min(targetWidth - tableWidth, maxWidth - tableWidth);
if (fileColIncrease <= 0) {
return;
}
// @ts-ignore
table.options.colWidths[0] += fileColIncrease;
}
// Yeah, I know.
monkeyPatchTruncate() {
if (this.patched) {
return;
}
this.patched = true;
// @ts-ignore
const utils = require('cli-table3/src/utils');
const oldTruncate = utils.truncate;
// cli-table3 can only do truncation at the end
// We want the asset name to be truncated at the beginning if it's too long
// FIXME: We really should set truncation location via a paramter or something
// (or PR support for alignment-based truncation)
/**
*
* @param {string} str
* @param {number} desiredLength
* @param {string} truncateChar
*/
utils.truncate = (str, desiredLength, truncateChar) => {
if (stripAnsi(str).length > desiredLength) {
str = `${str.substr(-desiredLength + 2)}`;
}
return oldTruncate(str, desiredLength, truncateChar);
};
}
/**
* Calculate the width of the CLI Table
*
* `table.width` does not report the correct width
* because it includes ANSI control characters
*
* @internal
* @param {import("cli-table3").Table} table
*/
calculateTableWidth(table) {
const firstRow = table.toString().split('\n')[0];
return stripAnsi(firstRow).length;
}
}
module.exports = BuildOutputPlugin;

View File

@@ -0,0 +1,67 @@
// @ts-check
/**
* This plugin ensures that vue styles are always appended to the end of CSS files
*/
class AppendVueStylesPlugin {
/** @param {import("webpack").Compiler} compiler */
apply(compiler) {
const name = 'AppendVueStylesPlugin';
compiler.hooks.compilation.tap(name, compilation => {
compilation.hooks.optimizeChunks.tap(name, chunks => {
this.reorderModules(compilation.chunkGraph, chunks);
});
});
}
/**
*
* @param {import("webpack").ChunkGraph} graph
* @param {Iterable<import("webpack").Chunk>} chunks
*/
reorderModules(graph, chunks) {
const queue = this.collectCssChunks(graph, chunks);
// Find the last module in the bundle
let largestIndex = 0;
for (const { module, group } of queue) {
largestIndex = Math.max(largestIndex, group.getModulePostOrderIndex(module));
}
// Push all vue assets after it in their original order
for (const { module, group } of queue) {
if (module.identifier().includes('?vue')) {
group.setModulePostOrderIndex(
module,
largestIndex + group.getModulePostOrderIndex(module)
);
}
}
}
/**
* @param {import("webpack").ChunkGraph} graph
* @param {Iterable<import("webpack").Chunk>} chunks
*/
collectCssChunks(graph, chunks) {
const queue = [];
for (const chunk of chunks) {
for (const module of graph.getChunkModulesIterable(chunk)) {
if (module.type !== 'css/mini-extract') {
continue;
}
for (const group of chunk.groupsIterable) {
queue.push({ module, chunk, group });
}
}
}
return queue;
}
}
module.exports = AppendVueStylesPlugin;

View File

@@ -0,0 +1,115 @@
let Log = require('../Log');
let collect = require('collect.js');
class CustomTasksPlugin {
/**
*
* @param {import('../Mix')} mix
*/
constructor(mix) {
this.mix = mix || global.Mix;
}
/**
* Apply the plugin.
*
* @param {import("webpack").Compiler} compiler
*/
apply(compiler) {
compiler.hooks.done.tapPromise(this.constructor.name, async stats => {
await this.runTasks(stats);
if (this.mix.components.get('version') && !this.mix.isUsing('hmr')) {
this.applyVersioning();
}
if (this.mix.inProduction()) {
await this.minifyAssets();
}
if (this.mix.isWatching()) {
this.mix.tasks.forEach(task => task.watch(this.mix.isPolling()));
}
this.mix.manifest.refresh();
});
}
/**
* Add asset to the webpack stats.
*
* @param {import("../File")} asset
* @param {import("webpack").Stats} stats
*/
async addAsset(asset, stats) {
// Skip adding directories to the manifest
// TODO: We should probably add the directory but skip hashing
if (asset.isDirectory()) {
return;
}
const path = asset.pathFromPublic();
// Add the asset to the manifest
this.mix.manifest.add(path);
// Update the Webpack assets list for better terminal output.
stats.compilation.assets[path] = {
size: () => asset.size(),
emitted: true
};
}
/**
* Execute potentially asynchronous tasks sequentially.
*
* @param stats
*/
async runTasks(stats) {
let assets = []
for (const task of this.mix.tasks) {
await Promise.resolve(task.run());
assets.push(...task.assets)
}
await Promise.allSettled(assets.map(asset => this.addAsset(asset, stats)));
}
/**
* Minify the given asset file.
*/
async minifyAssets() {
const assets = collect(this.mix.tasks)
.where('constructor.name', '!==', 'VersionFilesTask')
.where('constructor.name', '!==', 'CopyFilesTask')
.flatMap(({ assets }) => assets);
const tasks = assets.map(async asset => {
try {
await asset.minify();
} catch (e) {
Log.error(
`Whoops! We had trouble minifying "${asset.relativePath()}". ` +
`Perhaps you need to use mix.babel() instead?`
);
throw e;
}
});
await Promise.allSettled(tasks);
}
/**
* Version all files that are present in the manifest.
*/
applyVersioning() {
for (const [key, value] of Object.entries(this.mix.manifest.get())) {
this.mix.manifest.hash(key)
}
}
}
module.exports = CustomTasksPlugin;

View File

@@ -0,0 +1,28 @@
class ManifestPlugin {
/**
*
* @param {import("../Mix")} mix
*/
constructor(mix) {
// TODO: Simplify in Mix 7 -- Here for backwards compat if a plugin creates this class directly
this.mix = mix || global.Mix;
}
/**
* Apply the plugin.
*
* @param {import("webpack").Compiler} compiler
*/
apply(compiler) {
compiler.hooks.emit.tapAsync('ManifestPlugin', (curCompiler, callback) => {
let stats = curCompiler.getStats().toJson();
// Handle the creation of the mix-manifest.json file.
this.mix.manifest.transform(stats).refresh();
callback();
});
}
}
module.exports = ManifestPlugin;

View File

@@ -0,0 +1,84 @@
let dotenv = require('dotenv');
let expand = require('dotenv-expand');
/** @internal */
class MixDefinitionsPlugin {
/**
*
* @param {string} envPath
* @param {Record<string, string>} [additionalEnv]
*/
constructor(envPath, additionalEnv = {}) {
this.envPath = envPath;
this.additionalEnv = additionalEnv;
}
/**
*
* @param {import('webpack').Compiler} compiler
*/
apply(compiler) {
this.plugin.apply(compiler);
}
/**
* Build all MIX_ definitions for Webpack's DefinePlugin.
*/
get env() {
// Load .env, if it exists, into process.env
expand(dotenv.config({ path: this.envPath }));
// Take everything from process.env that beings with MIX_
const regex = /^MIX_/i;
const existing = Object.fromEntries(
Object.entries(process.env).filter(([key]) => regex.test(key))
);
// Merge in env vaiues from:
// - process.env
// - the .env file
// - the additional env provided to the plugin
return {
...existing,
...this.additionalEnv
};
}
/**
* Build up the necessary definitions and add them to the DefinePlugin.
*/
get plugin() {
const { EnvironmentPlugin } = require('webpack');
return new EnvironmentPlugin(this.env);
}
/**
* Build all MIX_ definitions for Webpack's DefinePlugin.
* This is no longer used but here for backwards compat.
*
* @deprecated
* @param {Record<string, string>} additionalEnv
*/
getDefinitions(additionalEnv) {
return Object.fromEntries(
Object.entries({ ...this.env, ...additionalEnv }).map(([key, value]) => {
return [`process.env.${key}`, JSON.stringify(value)];
})
);
}
/**
* Build up the necessary definitions and add them to the DefinePlugin.
*
* Here for backwards compat only
* @deprecated
* @param {Record<string, string>} additionalEnv
*/
static build(additionalEnv) {
return new MixDefinitionsPlugin(global.Mix.paths.root('.env'), additionalEnv)
.plugin;
}
}
module.exports = MixDefinitionsPlugin;

View File

@@ -0,0 +1,41 @@
let File = require('../File');
let path = require('path');
class MockEntryPlugin {
/**
* @param {import('../Mix')} mix
*/
constructor(mix) {
// TODO: Remove in Mix 7 -- Here for backwards compat if a plugin requires this file
this.mix = mix || global.Mix;
}
/**
* Handle the deletion of the temporary mix.js
* output file that was generated by webpack.
*
* This file is created when the user hasn't
* requested any JavaScript compilation, but
* webpack still requires an entry.
*
* @param {import("webpack").Compiler} compiler
*/
apply(compiler) {
compiler.hooks.done.tap('MockEntryPlugin', stats => {
const assets = stats.toJson().assets || [];
const temporaryOutputFile = assets.find(asset => asset.name === 'mix.js');
if (!temporaryOutputFile) {
return;
}
delete stats.compilation.assets[temporaryOutputFile.name];
File.find(
path.resolve(this.mix.config.publicPath, temporaryOutputFile.name)
).delete();
});
}
}
module.exports = MockEntryPlugin;