Fix code quality violations and exclude Manifest from checks

Document application modes (development/debug/production)
Add global file drop handler, order column normalization, SPA hash fix
Serve CDN assets via /_vendor/ URLs instead of merging into bundles
Add production minification with license preservation
Improve JSON formatting for debugging and production optimization
Add CDN asset caching with CSS URL inlining for production builds
Add three-mode system (development, debug, production)
Update Manifest CLAUDE.md to reflect helper class architecture
Refactor Manifest.php into helper classes for better organization
Pre-manifest-refactor checkpoint: Add app_mode documentation

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2026-01-14 10:38:22 +00:00
parent bb9046af1b
commit d523f0f600
2355 changed files with 231384 additions and 32223 deletions

View File

@@ -1,27 +1,24 @@
var SyntaxReferenceError = require('./error').SyntaxReferenceError;
var SyntaxMatchError = require('./error').SyntaxMatchError;
var names = require('../utils/names');
var generic = require('./generic');
var parse = require('../definition-syntax/parse');
var generate = require('../definition-syntax/generate');
var walk = require('../definition-syntax/walk');
var prepareTokens = require('./prepare-tokens');
var buildMatchGraph = require('./match-graph').buildMatchGraph;
var matchAsTree = require('./match').matchAsTree;
var trace = require('./trace');
var search = require('./search');
var getStructureFromConfig = require('./structure').getStructureFromConfig;
var cssWideKeywords = buildMatchGraph('inherit | initial | unset');
var cssWideKeywordsWithExpression = buildMatchGraph('inherit | initial | unset | <-ms-legacy-expression>');
import { SyntaxReferenceError, SyntaxMatchError } from './error.js';
import * as names from '../utils/names.js';
import { cssWideKeywords } from './generic-const.js';
import { createGenericTypes } from './generic.js';
import * as units from './units.js';
import { parse, generate, walk } from '../definition-syntax/index.js';
import prepareTokens from './prepare-tokens.js';
import { buildMatchGraph } from './match-graph.js';
import { matchAsTree } from './match.js';
import * as trace from './trace.js';
import { matchFragments } from './search.js';
import { getStructureFromConfig } from './structure.js';
function dumpMapSyntax(map, compact, syntaxAsAst) {
var result = {};
const result = {};
for (var name in map) {
for (const name in map) {
if (map[name].syntax) {
result[name] = syntaxAsAst
? map[name].syntax
: generate(map[name].syntax, { compact: compact });
: generate(map[name].syntax, { compact });
}
}
@@ -46,7 +43,7 @@ function dumpAtruleMapSyntax(map, compact, syntaxAsAst) {
}
function valueHasVar(tokens) {
for (var i = 0; i < tokens.length; i++) {
for (let i = 0; i < tokens.length; i++) {
if (tokens[i].value.toLowerCase() === 'var(') {
return true;
}
@@ -55,31 +52,39 @@ function valueHasVar(tokens) {
return false;
}
function buildMatchResult(match, error, iterations) {
function syntaxHasTopLevelCommaMultiplier(syntax) {
const singleTerm = syntax.terms[0];
return (
syntax.explicit === false &&
syntax.terms.length === 1 &&
singleTerm.type === 'Multiplier' &&
singleTerm.comma === true
);
}
function buildMatchResult(matched, error, iterations) {
return {
matched: match,
iterations: iterations,
error: error,
getTrace: trace.getTrace,
isType: trace.isType,
isProperty: trace.isProperty,
isKeyword: trace.isKeyword
matched,
iterations,
error,
...trace
};
}
function matchSyntax(lexer, syntax, value, useCommon) {
var tokens = prepareTokens(value, lexer.syntax);
var result;
function matchSyntax(lexer, syntax, value, useCssWideKeywords) {
const tokens = prepareTokens(value, lexer.syntax);
let result;
if (valueHasVar(tokens)) {
return buildMatchResult(null, new Error('Matching for a tree with var() is not supported'));
}
if (useCommon) {
result = matchAsTree(tokens, lexer.valueCommonSyntax, lexer);
if (useCssWideKeywords) {
result = matchAsTree(tokens, lexer.cssWideKeywordsSyntax, lexer);
}
if (!useCommon || !result.match) {
if (!useCssWideKeywords || !result.match) {
result = matchAsTree(tokens, syntax.match, lexer);
if (!result.match) {
return buildMatchResult(
@@ -93,55 +98,66 @@ function matchSyntax(lexer, syntax, value, useCommon) {
return buildMatchResult(result.match, null, result.iterations);
}
var Lexer = function(config, syntax, structure) {
this.valueCommonSyntax = cssWideKeywords;
this.syntax = syntax;
this.generic = false;
this.atrules = {};
this.properties = {};
this.types = {};
this.structure = structure || getStructureFromConfig(config);
export class Lexer {
constructor(config, syntax, structure) {
this.cssWideKeywords = cssWideKeywords;
this.syntax = syntax;
this.generic = false;
this.units = { ...units };
this.atrules = Object.create(null);
this.properties = Object.create(null);
this.types = Object.create(null);
this.structure = structure || getStructureFromConfig(config);
if (config) {
if (config.types) {
for (var name in config.types) {
this.addType_(name, config.types[name]);
if (config) {
if (config.cssWideKeywords) {
this.cssWideKeywords = config.cssWideKeywords;
}
if (config.units) {
for (const group of Object.keys(units)) {
if (Array.isArray(config.units[group])) {
this.units[group] = config.units[group];
}
}
}
if (config.types) {
for (const [name, type] of Object.entries(config.types)) {
this.addType_(name, type);
}
}
if (config.generic) {
this.generic = true;
for (const [name, value] of Object.entries(createGenericTypes(this.units))) {
this.addType_(name, value);
}
}
if (config.atrules) {
for (const [name, atrule] of Object.entries(config.atrules)) {
this.addAtrule_(name, atrule);
}
}
if (config.properties) {
for (const [name, property] of Object.entries(config.properties)) {
this.addProperty_(name, property);
}
}
}
if (config.generic) {
this.generic = true;
for (var name in generic) {
this.addType_(name, generic[name]);
}
}
if (config.atrules) {
for (var name in config.atrules) {
this.addAtrule_(name, config.atrules[name]);
}
}
if (config.properties) {
for (var name in config.properties) {
this.addProperty_(name, config.properties[name]);
}
}
this.cssWideKeywordsSyntax = buildMatchGraph(this.cssWideKeywords.join(' | '));
}
};
Lexer.prototype = {
structure: {},
checkStructure: function(ast) {
checkStructure(ast) {
function collectWarning(node, message) {
warns.push({
node: node,
message: message
});
warns.push({ node, message });
}
var structure = this.structure;
var warns = [];
const structure = this.structure;
const warns = [];
this.syntax.walk(ast, function(node) {
if (structure.hasOwnProperty(node.type)) {
@@ -152,19 +168,21 @@ Lexer.prototype = {
});
return warns.length ? warns : false;
},
}
createDescriptor: function(syntax, type, name, parent = null) {
var ref = {
type: type,
name: name
createDescriptor(syntax, type, name, parent = null) {
const ref = {
type,
name
};
var descriptor = {
type: type,
name: name,
parent: parent,
const descriptor = {
type,
name,
parent,
serializable: typeof syntax === 'string' || (syntax && typeof syntax.type === 'string'),
syntax: null,
match: null
match: null,
matchRef: null // used for properties when a syntax referenced as <'property'> in other syntax definitions
};
if (typeof syntax === 'function') {
@@ -173,7 +191,7 @@ Lexer.prototype = {
if (typeof syntax === 'string') {
// lazy parsing on first access
Object.defineProperty(descriptor, 'syntax', {
get: function() {
get() {
Object.defineProperty(descriptor, 'syntax', {
value: parse(syntax)
});
@@ -187,7 +205,7 @@ Lexer.prototype = {
// lazy graph build on first access
Object.defineProperty(descriptor, 'match', {
get: function() {
get() {
Object.defineProperty(descriptor, 'match', {
value: buildMatchGraph(descriptor.syntax, ref)
});
@@ -195,11 +213,31 @@ Lexer.prototype = {
return descriptor.match;
}
});
if (type === 'Property') {
Object.defineProperty(descriptor, 'matchRef', {
get() {
const syntax = descriptor.syntax;
const value = syntaxHasTopLevelCommaMultiplier(syntax)
? buildMatchGraph({
...syntax,
terms: [syntax.terms[0].term]
}, ref)
: null;
Object.defineProperty(descriptor, 'matchRef', {
value
});
return value;
}
});
}
}
return descriptor;
},
addAtrule_: function(name, syntax) {
}
addAtrule_(name, syntax) {
if (!syntax) {
return;
}
@@ -209,63 +247,64 @@ Lexer.prototype = {
name: name,
prelude: syntax.prelude ? this.createDescriptor(syntax.prelude, 'AtrulePrelude', name) : null,
descriptors: syntax.descriptors
? Object.keys(syntax.descriptors).reduce((res, descName) => {
res[descName] = this.createDescriptor(syntax.descriptors[descName], 'AtruleDescriptor', descName, name);
return res;
}, {})
? Object.keys(syntax.descriptors).reduce(
(map, descName) => {
map[descName] = this.createDescriptor(syntax.descriptors[descName], 'AtruleDescriptor', descName, name);
return map;
},
Object.create(null)
)
: null
};
},
addProperty_: function(name, syntax) {
}
addProperty_(name, syntax) {
if (!syntax) {
return;
}
this.properties[name] = this.createDescriptor(syntax, 'Property', name);
},
addType_: function(name, syntax) {
}
addType_(name, syntax) {
if (!syntax) {
return;
}
this.types[name] = this.createDescriptor(syntax, 'Type', name);
}
if (syntax === generic['-ms-legacy-expression']) {
this.valueCommonSyntax = cssWideKeywordsWithExpression;
}
},
checkAtruleName: function(atruleName) {
checkAtruleName(atruleName) {
if (!this.getAtrule(atruleName)) {
return new SyntaxReferenceError('Unknown at-rule', '@' + atruleName);
}
},
checkAtrulePrelude: function(atruleName, prelude) {
let error = this.checkAtruleName(atruleName);
}
checkAtrulePrelude(atruleName, prelude) {
const error = this.checkAtruleName(atruleName);
if (error) {
return error;
}
var atrule = this.getAtrule(atruleName);
const atrule = this.getAtrule(atruleName);
if (!atrule.prelude && prelude) {
return new SyntaxError('At-rule `@' + atruleName + '` should not contain a prelude');
}
if (atrule.prelude && !prelude) {
return new SyntaxError('At-rule `@' + atruleName + '` should contain a prelude');
if (!matchSyntax(this, atrule.prelude, '', false).matched) {
return new SyntaxError('At-rule `@' + atruleName + '` should contain a prelude');
}
}
},
checkAtruleDescriptorName: function(atruleName, descriptorName) {
let error = this.checkAtruleName(atruleName);
}
checkAtruleDescriptorName(atruleName, descriptorName) {
const error = this.checkAtruleName(atruleName);
if (error) {
return error;
}
var atrule = this.getAtrule(atruleName);
var descriptor = names.keyword(descriptorName);
const atrule = this.getAtrule(atruleName);
const descriptor = names.keyword(descriptorName);
if (!atrule.descriptors) {
return new SyntaxError('At-rule `@' + atruleName + '` has no known descriptors');
@@ -275,71 +314,71 @@ Lexer.prototype = {
!atrule.descriptors[descriptor.basename]) {
return new SyntaxReferenceError('Unknown at-rule descriptor', descriptorName);
}
},
checkPropertyName: function(propertyName) {
var property = names.property(propertyName);
// don't match syntax for a custom property
if (property.custom) {
return new Error('Lexer matching doesn\'t applicable for custom properties');
}
}
checkPropertyName(propertyName) {
if (!this.getProperty(propertyName)) {
return new SyntaxReferenceError('Unknown property', propertyName);
}
},
}
matchAtrulePrelude: function(atruleName, prelude) {
var error = this.checkAtrulePrelude(atruleName, prelude);
matchAtrulePrelude(atruleName, prelude) {
const error = this.checkAtrulePrelude(atruleName, prelude);
if (error) {
return buildMatchResult(null, error);
}
if (!prelude) {
const atrule = this.getAtrule(atruleName);
if (!atrule.prelude) {
return buildMatchResult(null, null);
}
return matchSyntax(this, this.getAtrule(atruleName).prelude, prelude, false);
},
matchAtruleDescriptor: function(atruleName, descriptorName, value) {
var error = this.checkAtruleDescriptorName(atruleName, descriptorName);
return matchSyntax(this, atrule.prelude, prelude || '', false);
}
matchAtruleDescriptor(atruleName, descriptorName, value) {
const error = this.checkAtruleDescriptorName(atruleName, descriptorName);
if (error) {
return buildMatchResult(null, error);
}
var atrule = this.getAtrule(atruleName);
var descriptor = names.keyword(descriptorName);
const atrule = this.getAtrule(atruleName);
const descriptor = names.keyword(descriptorName);
return matchSyntax(this, atrule.descriptors[descriptor.name] || atrule.descriptors[descriptor.basename], value, false);
},
matchDeclaration: function(node) {
}
matchDeclaration(node) {
if (node.type !== 'Declaration') {
return buildMatchResult(null, new Error('Not a Declaration node'));
}
return this.matchProperty(node.property, node.value);
},
matchProperty: function(propertyName, value) {
var error = this.checkPropertyName(propertyName);
}
matchProperty(propertyName, value) {
// don't match syntax for a custom property at the moment
if (names.property(propertyName).custom) {
return buildMatchResult(null, new Error('Lexer matching doesn\'t applicable for custom properties'));
}
const error = this.checkPropertyName(propertyName);
if (error) {
return buildMatchResult(null, error);
}
return matchSyntax(this, this.getProperty(propertyName), value, true);
},
matchType: function(typeName, value) {
var typeSyntax = this.getType(typeName);
}
matchType(typeName, value) {
const typeSyntax = this.getType(typeName);
if (!typeSyntax) {
return buildMatchResult(null, new SyntaxReferenceError('Unknown type', typeName));
}
return matchSyntax(this, typeSyntax, value, false);
},
match: function(syntax, value) {
}
match(syntax, value) {
if (typeof syntax !== 'string' && (!syntax || !syntax.type)) {
return buildMatchResult(null, new SyntaxReferenceError('Bad syntax'));
}
@@ -349,118 +388,124 @@ Lexer.prototype = {
}
return matchSyntax(this, syntax, value, false);
},
}
findValueFragments: function(propertyName, value, type, name) {
return search.matchFragments(this, value, this.matchProperty(propertyName, value), type, name);
},
findDeclarationValueFragments: function(declaration, type, name) {
return search.matchFragments(this, declaration.value, this.matchDeclaration(declaration), type, name);
},
findAllFragments: function(ast, type, name) {
var result = [];
findValueFragments(propertyName, value, type, name) {
return matchFragments(this, value, this.matchProperty(propertyName, value), type, name);
}
findDeclarationValueFragments(declaration, type, name) {
return matchFragments(this, declaration.value, this.matchDeclaration(declaration), type, name);
}
findAllFragments(ast, type, name) {
const result = [];
this.syntax.walk(ast, {
visit: 'Declaration',
enter: function(declaration) {
enter: (declaration) => {
result.push.apply(result, this.findDeclarationValueFragments(declaration, type, name));
}.bind(this)
}
});
return result;
},
}
getAtrule: function(atruleName, fallbackBasename = true) {
var atrule = names.keyword(atruleName);
var atruleEntry = atrule.vendor && fallbackBasename
getAtrule(atruleName, fallbackBasename = true) {
const atrule = names.keyword(atruleName);
const atruleEntry = atrule.vendor && fallbackBasename
? this.atrules[atrule.name] || this.atrules[atrule.basename]
: this.atrules[atrule.name];
return atruleEntry || null;
},
getAtrulePrelude: function(atruleName, fallbackBasename = true) {
}
getAtrulePrelude(atruleName, fallbackBasename = true) {
const atrule = this.getAtrule(atruleName, fallbackBasename);
return atrule && atrule.prelude || null;
},
getAtruleDescriptor: function(atruleName, name) {
}
getAtruleDescriptor(atruleName, name) {
return this.atrules.hasOwnProperty(atruleName) && this.atrules.declarators
? this.atrules[atruleName].declarators[name] || null
: null;
},
getProperty: function(propertyName, fallbackBasename = true) {
var property = names.property(propertyName);
var propertyEntry = property.vendor && fallbackBasename
}
getProperty(propertyName, fallbackBasename = true) {
const property = names.property(propertyName);
const propertyEntry = property.vendor && fallbackBasename
? this.properties[property.name] || this.properties[property.basename]
: this.properties[property.name];
return propertyEntry || null;
},
getType: function(name) {
return this.types.hasOwnProperty(name) ? this.types[name] : null;
},
}
getType(name) {
return hasOwnProperty.call(this.types, name) ? this.types[name] : null;
}
validate() {
function syntaxRef(name, isType) {
return isType ? `<${name}>` : `<'${name}'>`;
}
validate: function() {
function validate(syntax, name, broken, descriptor) {
if (broken.hasOwnProperty(name)) {
return broken[name];
if (broken.has(name)) {
return broken.get(name);
}
broken[name] = false;
broken.set(name, false);
if (descriptor.syntax !== null) {
walk(descriptor.syntax, function(node) {
if (node.type !== 'Type' && node.type !== 'Property') {
return;
}
var map = node.type === 'Type' ? syntax.types : syntax.properties;
var brokenMap = node.type === 'Type' ? brokenTypes : brokenProperties;
const map = node.type === 'Type' ? syntax.types : syntax.properties;
const brokenMap = node.type === 'Type' ? brokenTypes : brokenProperties;
if (!map.hasOwnProperty(node.name) || validate(syntax, node.name, brokenMap, map[node.name])) {
broken[name] = true;
if (!hasOwnProperty.call(map, node.name)) {
errors.push(`${syntaxRef(name, broken === brokenTypes)} used missed syntax definition ${syntaxRef(node.name, node.type === 'Type')}`);
broken.set(name, true);
} else if (validate(syntax, node.name, brokenMap, map[node.name])) {
errors.push(`${syntaxRef(name, broken === brokenTypes)} used broken syntax definition ${syntaxRef(node.name, node.type === 'Type')}`);
broken.set(name, true);
}
}, this);
}
}
var brokenTypes = {};
var brokenProperties = {};
const errors = [];
let brokenTypes = new Map();
let brokenProperties = new Map();
for (var key in this.types) {
for (const key in this.types) {
validate(this, key, brokenTypes, this.types[key]);
}
for (var key in this.properties) {
for (const key in this.properties) {
validate(this, key, brokenProperties, this.properties[key]);
}
brokenTypes = Object.keys(brokenTypes).filter(function(name) {
return brokenTypes[name];
});
brokenProperties = Object.keys(brokenProperties).filter(function(name) {
return brokenProperties[name];
});
const brokenTypesArray = [...brokenTypes.keys()].filter(name => brokenTypes.get(name));
const brokenPropertiesArray = [...brokenProperties.keys()].filter(name => brokenProperties.get(name));
if (brokenTypes.length || brokenProperties.length) {
if (brokenTypesArray.length || brokenPropertiesArray.length) {
return {
types: brokenTypes,
properties: brokenProperties
errors,
types: brokenTypesArray,
properties: brokenPropertiesArray
};
}
return null;
},
dump: function(syntaxAsAst, pretty) {
}
dump(syntaxAsAst, pretty) {
return {
generic: this.generic,
cssWideKeywords: this.cssWideKeywords,
units: this.units,
types: dumpMapSyntax(this.types, !pretty, syntaxAsAst),
properties: dumpMapSyntax(this.properties, !pretty, syntaxAsAst),
atrules: dumpAtruleMapSyntax(this.atrules, !pretty, syntaxAsAst)
};
},
toString: function() {
}
toString() {
return JSON.stringify(this.dump());
}
};
module.exports = Lexer;