Website Structure
This commit is contained in:
parent
62812f2090
commit
71f0676a62
22365 changed files with 4265753 additions and 791 deletions
239
Frontend-Learner/node_modules/postcss-discard-comments/src/index.js
generated
vendored
Normal file
239
Frontend-Learner/node_modules/postcss-discard-comments/src/index.js
generated
vendored
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
'use strict';
|
||||
const CommentRemover = require('./lib/commentRemover');
|
||||
const commentParser = require('./lib/commentParser');
|
||||
const selectorParser = require('postcss-selector-parser');
|
||||
|
||||
/** @typedef {object} Options
|
||||
* @property {boolean=} removeAll
|
||||
* @property {boolean=} removeAllButFirst
|
||||
* @property {(s: string) => boolean=} remove
|
||||
*/
|
||||
/**
|
||||
* @type {import('postcss').PluginCreator<Options>}
|
||||
* @param {Options} opts
|
||||
* @return {import('postcss').Plugin}
|
||||
*/
|
||||
function pluginCreator(opts = {}) {
|
||||
const remover = new CommentRemover(opts);
|
||||
const matcherCache = new Map();
|
||||
const parserCache = new Map();
|
||||
const replacerCache = new Map();
|
||||
|
||||
/**
|
||||
* @param {string} source
|
||||
* @return {[number, number, number][]}
|
||||
*/
|
||||
function getTokens(source) {
|
||||
if (parserCache.has(source)) {
|
||||
return parserCache.get(source);
|
||||
}
|
||||
|
||||
const tokens = commentParser(source);
|
||||
|
||||
parserCache.set(source, tokens);
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} source
|
||||
* @return {[number, number, number][]}
|
||||
*/
|
||||
function matchesComments(source) {
|
||||
if (matcherCache.has(source)) {
|
||||
return matcherCache.get(source);
|
||||
}
|
||||
|
||||
const result = getTokens(source).filter(([type]) => type);
|
||||
|
||||
matcherCache.set(source, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | undefined} rawSource
|
||||
* @param {(s: string) => string[]} space
|
||||
* @param {string=} separator
|
||||
* @return {string}
|
||||
*/
|
||||
function replaceComments(rawSource, space, separator = ' ') {
|
||||
const source = rawSource || '';
|
||||
const key = source + '@|@' + separator;
|
||||
|
||||
if (replacerCache.has(key)) {
|
||||
return replacerCache.get(key);
|
||||
}
|
||||
|
||||
if (source.indexOf('/*') === -1) {
|
||||
const normalized = space(source).join(' ');
|
||||
|
||||
replacerCache.set(key, normalized);
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
const parts = [];
|
||||
|
||||
for (const [type, start, end] of getTokens(source)) {
|
||||
if (!type) {
|
||||
parts.push(source.slice(start, end));
|
||||
continue;
|
||||
}
|
||||
|
||||
const contents = source.slice(start, end);
|
||||
|
||||
if (remover.canRemove(contents)) {
|
||||
parts.push(separator);
|
||||
continue;
|
||||
}
|
||||
|
||||
parts.push('/*' + contents + '*/');
|
||||
}
|
||||
|
||||
const parsed = parts.join('');
|
||||
|
||||
const result = space(parsed).join(' ');
|
||||
|
||||
replacerCache.set(key, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | undefined} rawSource
|
||||
* @param {(s: string) => string[]} space
|
||||
* @return {string}
|
||||
*/
|
||||
function replaceCommentsInSelector(rawSource, space) {
|
||||
const source = rawSource || '';
|
||||
const key = source + '@|@';
|
||||
|
||||
if (replacerCache.has(key)) {
|
||||
return replacerCache.get(key);
|
||||
}
|
||||
if (source.indexOf('/*') === -1) {
|
||||
const normalized = space(source).join(' ');
|
||||
|
||||
replacerCache.set(key, normalized);
|
||||
|
||||
return normalized;
|
||||
}
|
||||
const processed = selectorParser((ast) => {
|
||||
ast.walk((node) => {
|
||||
if (node.type === 'comment') {
|
||||
const contents = node.value.slice(2, -2);
|
||||
if (remover.canRemove(contents)) {
|
||||
node.remove();
|
||||
}
|
||||
}
|
||||
const rawSpaceAfter = replaceComments(node.rawSpaceAfter, space, '');
|
||||
const rawSpaceBefore = replaceComments(node.rawSpaceBefore, space, '');
|
||||
// If comments are not removed, the result of trim will be returned,
|
||||
// so if we compare and there are no changes, skip it.
|
||||
if (rawSpaceAfter !== node.rawSpaceAfter.trim()) {
|
||||
node.rawSpaceAfter = rawSpaceAfter;
|
||||
}
|
||||
if (rawSpaceBefore !== node.rawSpaceBefore.trim()) {
|
||||
node.rawSpaceBefore = rawSpaceBefore;
|
||||
}
|
||||
});
|
||||
}).processSync(source);
|
||||
|
||||
const result = space(processed).join(' ');
|
||||
|
||||
replacerCache.set(key, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return {
|
||||
postcssPlugin: 'postcss-discard-comments',
|
||||
|
||||
OnceExit(css, { list }) {
|
||||
css.walk((node) => {
|
||||
if (node.type === 'comment' && remover.canRemove(node.text)) {
|
||||
node.remove();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof node.raws.between === 'string') {
|
||||
node.raws.between = replaceComments(node.raws.between, list.space);
|
||||
}
|
||||
|
||||
if (node.type === 'decl') {
|
||||
if (node.raws.value && node.raws.value.raw) {
|
||||
if (node.raws.value.value === node.value) {
|
||||
node.value = replaceComments(node.raws.value.raw, list.space);
|
||||
} else {
|
||||
node.value = replaceComments(node.value, list.space);
|
||||
}
|
||||
|
||||
/** @type {null | {value: string, raw: string}} */ (
|
||||
node.raws.value
|
||||
) = null;
|
||||
}
|
||||
|
||||
if (node.raws.important) {
|
||||
node.raws.important = replaceComments(
|
||||
node.raws.important,
|
||||
list.space
|
||||
);
|
||||
|
||||
const b = matchesComments(node.raws.important);
|
||||
|
||||
node.raws.important = b.length ? node.raws.important : '!important';
|
||||
} else {
|
||||
node.value = replaceComments(node.value, list.space);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.type === 'rule') {
|
||||
if (node.raws.selector && node.raws.selector.raw) {
|
||||
node.raws.selector.raw = replaceCommentsInSelector(
|
||||
node.raws.selector.raw,
|
||||
list.space
|
||||
);
|
||||
} else if (node.selector && node.selector.includes('/*')) {
|
||||
node.selector = replaceCommentsInSelector(
|
||||
node.selector,
|
||||
list.space
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.type === 'atrule') {
|
||||
if (node.raws.afterName) {
|
||||
const commentsReplaced = replaceComments(
|
||||
node.raws.afterName,
|
||||
list.space
|
||||
);
|
||||
|
||||
if (!commentsReplaced.length) {
|
||||
node.raws.afterName = commentsReplaced + ' ';
|
||||
} else {
|
||||
node.raws.afterName = ' ' + commentsReplaced + ' ';
|
||||
}
|
||||
}
|
||||
|
||||
if (node.raws.params && node.raws.params.raw) {
|
||||
node.raws.params.raw = replaceComments(
|
||||
node.raws.params.raw,
|
||||
list.space
|
||||
);
|
||||
} else if (node.params && node.params.includes('/*')) {
|
||||
node.params = replaceComments(node.params, list.space);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pluginCreator.postcss = true;
|
||||
module.exports = pluginCreator;
|
||||
95
Frontend-Learner/node_modules/postcss-discard-comments/src/lib/commentParser.js
generated
vendored
Normal file
95
Frontend-Learner/node_modules/postcss-discard-comments/src/lib/commentParser.js
generated
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
'use strict';
|
||||
|
||||
// State machine states reused between parses for better perf
|
||||
const STATES = {
|
||||
NORMAL: 0,
|
||||
IN_SINGLE_QUOTE: 1,
|
||||
IN_DOUBLE_QUOTE: 2,
|
||||
IN_COMMENT: 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* CSS Comment Parser with context awareness
|
||||
* Properly handles comments inside strings, URLs, and escaped characters
|
||||
*
|
||||
* @param {string} input
|
||||
* @return {[number, number, number][]}
|
||||
*/
|
||||
module.exports = function commentParser(input) {
|
||||
/** @type {[number, number, number][]} */
|
||||
const tokens = [];
|
||||
const length = input.length;
|
||||
let pos = 0;
|
||||
|
||||
let state = STATES.NORMAL;
|
||||
let tokenStart = 0;
|
||||
let commentStart = 0;
|
||||
|
||||
while (pos < length) {
|
||||
const char = input[pos];
|
||||
const nextChar = pos + 1 < length ? input[pos + 1] : '';
|
||||
|
||||
switch (state) {
|
||||
case STATES.NORMAL:
|
||||
if (char === '/' && nextChar === '*') {
|
||||
// Found comment start - add non-comment token if needed
|
||||
if (pos > tokenStart) {
|
||||
tokens.push([0, tokenStart, pos]);
|
||||
}
|
||||
commentStart = pos;
|
||||
state = STATES.IN_COMMENT;
|
||||
pos += 2; // Skip /*
|
||||
continue;
|
||||
} else if (char === '"') {
|
||||
state = STATES.IN_DOUBLE_QUOTE;
|
||||
} else if (char === "'") {
|
||||
state = STATES.IN_SINGLE_QUOTE;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATES.IN_SINGLE_QUOTE:
|
||||
if (char === '\\' && nextChar) {
|
||||
// Skip escaped character
|
||||
pos += 2;
|
||||
continue;
|
||||
} else if (char === "'") {
|
||||
state = STATES.NORMAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATES.IN_DOUBLE_QUOTE:
|
||||
if (char === '\\' && nextChar) {
|
||||
// Skip escaped character
|
||||
pos += 2;
|
||||
continue;
|
||||
} else if (char === '"') {
|
||||
state = STATES.NORMAL;
|
||||
}
|
||||
break;
|
||||
|
||||
case STATES.IN_COMMENT:
|
||||
if (char === '*' && nextChar === '/') {
|
||||
// Found comment end
|
||||
tokens.push([1, commentStart + 2, pos]);
|
||||
tokenStart = pos + 2;
|
||||
state = STATES.NORMAL;
|
||||
pos += 2; // Skip */
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
pos++;
|
||||
}
|
||||
|
||||
// Handle remaining content
|
||||
if (state === STATES.IN_COMMENT) {
|
||||
// Unclosed comment - treat as comment to end
|
||||
tokens.push([1, commentStart + 2, length]);
|
||||
} else if (tokenStart < length) {
|
||||
// Add final non-comment token
|
||||
tokens.push([0, tokenStart, length]);
|
||||
}
|
||||
|
||||
return tokens;
|
||||
};
|
||||
32
Frontend-Learner/node_modules/postcss-discard-comments/src/lib/commentRemover.js
generated
vendored
Normal file
32
Frontend-Learner/node_modules/postcss-discard-comments/src/lib/commentRemover.js
generated
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
'use strict';
|
||||
|
||||
/** @param {import('../index.js').Options} options */
|
||||
function CommentRemover(options) {
|
||||
this.options = options;
|
||||
}
|
||||
/**
|
||||
* @param {string} comment
|
||||
* @return {boolean | undefined}
|
||||
*/
|
||||
CommentRemover.prototype.canRemove = function (comment) {
|
||||
const remove = this.options.remove;
|
||||
|
||||
if (remove) {
|
||||
return remove(comment);
|
||||
} else {
|
||||
const isImportant = comment.indexOf('!') === 0;
|
||||
|
||||
if (!isImportant) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.options.removeAll || this._hasFirst) {
|
||||
return true;
|
||||
} else if (this.options.removeAllButFirst && !this._hasFirst) {
|
||||
this._hasFirst = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = CommentRemover;
|
||||
Loading…
Add table
Add a link
Reference in a new issue