Skip to content

Commit

Permalink
Fix initialization when Object.prototype is extended or polluted (f…
Browse files Browse the repository at this point in the history
…ixes #262)
  • Loading branch information
lahmatiy committed Oct 13, 2023
1 parent d56a79a commit 26a64c7
Show file tree
Hide file tree
Showing 13 changed files with 56 additions and 60 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/build.yml
Expand Up @@ -5,8 +5,7 @@ on:
pull_request:

env:
PRIMARY_NODEJS_VERSION: 16
REPORTER: "min"
PRIMARY_NODEJS_VERSION: 18

jobs:
lint:
Expand All @@ -33,7 +32,7 @@ jobs:
node-version: ${{ env.PRIMARY_NODEJS_VERSION }}
cache: "npm"
- run: npm ci
- run: npm run bundle-and-test
- run: npm run bundle-and-test -- -- --reporter min

unit-tests:
name: Unit tests
Expand All @@ -47,6 +46,8 @@ jobs:
- 12.20.0
- 14.13.0
- 16
- 18
- 20

steps:
- uses: actions/checkout@v2
Expand All @@ -56,10 +57,9 @@ jobs:
node-version: ${{ matrix.node_version }}
cache: "npm"
- run: npm ci
- run: npm run test
- run: npm run test -- --reporter min
if: ${{ matrix.node_version != '10' }}
- run: npm run esm-to-cjs-and-test

- run: npm run esm-to-cjs-and-test -- -- --reporter min
- run: npm run coverage
if: ${{ matrix.node_version == env.PRIMARY_NODEJS_VERSION }}
- name: Coveralls parallel
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -9,6 +9,7 @@
- Bumped `mdn/data` to `2.1.0`
- Added `<dashed-ident>` to generic types
- Added `TokenStream#lookupTypeNonSC()` method
- Fixed initialization when `Object.prototype` is extended or polluted (#262)
- Changed `parseWithFallback()` to rollback `tokenIndex` before calling a fallback
- Changed `Ratio` parsing:
- Left and right parts contain nodes instead of strings
Expand Down
6 changes: 3 additions & 3 deletions lib/__tests/definition-syntax-match.js
Expand Up @@ -48,19 +48,19 @@ function createSyntaxTest(testName, test) {
? { types: { ...defaultTypes }, properties: { ...defaultProperties} }
: { types: {}, properties: {} };

for (const name in genericSyntaxes) {
for (const name of Object.keys(genericSyntaxes)) {
syntaxes.types[name] = {
match: buildMatchGraph(genericSyntaxes[name])
};
}

for (const name in test.types) {
for (const name of Object.keys(test.types || {})) {
syntaxes.types[name] = {
match: buildMatchGraph(test.types[name])
};
}

for (const name in test.properties) {
for (const name of Object.keys(test.properties || {})) {
syntaxes.properties[name] = {
match: buildMatchGraph(test.properties[name])
};
Expand Down
8 changes: 3 additions & 5 deletions lib/__tests/fixture/definition-syntax-match.js
Expand Up @@ -5,11 +5,9 @@ import { JsonLocator } from '../helpers/JsonLocator.js';
const __dirname = 'fixtures/definition-syntax-match';

export function forEachTest(factory) {
for (const filename in tests) {
const file = tests[filename];

for (const key in file) {
factory(key, file[key]);
for (const file of Object.values(tests)) {
for (const [key, test] of Object.entries(file)) {
factory(key, test);
}
};
}
Expand Down
20 changes: 6 additions & 14 deletions lib/__tests/fixture/definition-syntax.js
Expand Up @@ -6,11 +6,8 @@ import { JsonLocator } from '../helpers/JsonLocator.js';
const __dirname = 'fixtures/definition-syntax';

export function forEachTest(factory) {
for (const filename in tests) {
const file = tests[filename];

for (const key in file) {
const test = file[key];
for (const file of Object.values(tests)) {
for (const test of Object.values(file)) {
const syntax = test.syntax;
const lexer = test.lexer ? createLexer(test.lexer) : defaultLexer;

Expand All @@ -36,9 +33,7 @@ export function forEachTest(factory) {
}

export function forEachAtrulePreludeTest(factory) {
for (const atruleName in atruleTests) {
const testset = atruleTests[atruleName];

for (const [atruleName, testset] of Object.entries(atruleTests)) {
if (testset.prelude) {
const test = testset.prelude;
for (const field in test) {
Expand All @@ -62,13 +57,10 @@ export function forEachAtrulePreludeTest(factory) {
}

export function forEachAtruleDescriptorTest(factory) {
for (const atruleName in atruleTests) {
const testset = atruleTests[atruleName];

for (const [atruleName, testset] of Object.entries(atruleTests)) {
if (testset.descriptors) {
for (const descriptorName in testset.descriptors) {
const test = testset.descriptors[descriptorName];
for (const field in test) {
for (const [descriptorName, test] of Object.entries(testset.descriptors)) {
for (const field of Object.keys(test)) {
if (field !== 'valid' && field !== 'invalid') {
continue;
}
Expand Down
4 changes: 1 addition & 3 deletions lib/__tests/fixture/tokenize.js
Expand Up @@ -20,9 +20,7 @@ function processTests(tests, key, type, locator) {
}

export function forEachTest(testType, factory) {
for (const filename in tests) {
const file = tests[filename];

for (const file of Object.values(tests)) {
Object.keys(file[testType]).forEach(key => factory(
file[testType][key].name,
file[testType][key].value,
Expand Down
8 changes: 8 additions & 0 deletions lib/__tests/helpers/setup.js
@@ -0,0 +1,8 @@
// Guard to mitigate the risk of reading non-own properties,
// which can be a potential issue when working with dictionaries
Object.defineProperty(Object.prototype, '__proto_pollute__', {
enumerable: true,
get() {
throw new Error('Attempted to read a non-own property');
}
});
26 changes: 13 additions & 13 deletions lib/data.js
Expand Up @@ -6,20 +6,20 @@ const mdnAtrules = require('mdn-data/css/at-rules.json');
const mdnProperties = require('mdn-data/css/properties.json');
const mdnSyntaxes = require('mdn-data/css/syntaxes.json');

const hasOwn = Object.hasOwn || ((object, property) => Object.prototype.hasOwnProperty.call(object, property));
const extendSyntax = /^\s*\|\s*/;

function preprocessAtrules(dict) {
const result = Object.create(null);

for (const atruleName in dict) {
const atrule = dict[atruleName];
for (const [atruleName, atrule] of Object.entries(dict)) {
let descriptors = null;

if (atrule.descriptors) {
descriptors = Object.create(null);

for (const descriptor in atrule.descriptors) {
descriptors[descriptor] = atrule.descriptors[descriptor].syntax;
for (const [name, descriptor] of Object.entries(atrule.descriptors)) {
descriptors[name] = descriptor.syntax;
}
}

Expand All @@ -33,16 +33,18 @@ function preprocessAtrules(dict) {
}

function patchDictionary(dict, patchDict) {
const result = {};
const result = Object.create(null);

// copy all syntaxes for an original dict
for (const key in dict) {
result[key] = dict[key].syntax || dict[key];
for (const [key, value] of Object.entries(dict)) {
if (value) {
result[key] = value.syntax || value;
}
}

// apply a patch
for (const key in patchDict) {
if (key in dict) {
for (const key of Object.keys(patchDict)) {
if (hasOwn(dict, key)) {
if (patchDict[key].syntax) {
result[key] = extendSyntax.test(patchDict[key].syntax)
? result[key] + ' ' + patchDict[key].syntax.trim()
Expand Down Expand Up @@ -80,10 +82,8 @@ function patchAtrules(dict, patchDict) {
}

// apply a patch
for (const key in patchDict) {
if (patchDict[key] && !hasOwnProperty.call(dict, key)) {
const atrulePatch = patchDict[key] || {};

for (const [key, atrulePatch] of Object.entries(patchDict)) {
if (atrulePatch && !hasOwn(dict, key)) {
result[key] = {
prelude: atrulePatch.prelude || null,
descriptors: atrulePatch.descriptors && patchDictionary({}, atrulePatch.descriptors)
Expand Down
3 changes: 1 addition & 2 deletions lib/generator/create.js
Expand Up @@ -32,8 +32,7 @@ function processChunk(chunk) {
export function createGenerator(config) {
const types = new Map();

for (let name in config.node) {
const item = config.node[name];
for (let [name, item] of Object.entries(config.node)) {
const fn = item.generate || item;

if (typeof fn === 'function') {
Expand Down
12 changes: 6 additions & 6 deletions lib/lexer/Lexer.js
Expand Up @@ -110,8 +110,8 @@ export class Lexer {
}

if (config.types) {
for (const name in config.types) {
this.addType_(name, config.types[name]);
for (const [name, type] of Object.entries(config.types)) {
this.addType_(name, type);
}
}

Expand All @@ -123,14 +123,14 @@ export class Lexer {
}

if (config.atrules) {
for (const name in config.atrules) {
this.addAtrule_(name, config.atrules[name]);
for (const [name, atrule] of Object.entries(config.atrules)) {
this.addAtrule_(name, atrule);
}
}

if (config.properties) {
for (const name in config.properties) {
this.addProperty_(name, config.properties[name]);
for (const [name, property] of Object.entries(config.properties)) {
this.addProperty_(name, property);
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions lib/parser/create.js
Expand Up @@ -60,14 +60,14 @@ function processConfig(config) {
node: fetchParseValues(config.node)
};

for (const name in config.parseContext) {
switch (typeof config.parseContext[name]) {
for (const [name, context] of Object.entries(config.parseContext)) {
switch (typeof context) {
case 'function':
parseConfig.context[name] = config.parseContext[name];
parseConfig.context[name] = context;
break;

case 'string':
parseConfig.context[name] = createParseContext(config.parseContext[name]);
parseConfig.context[name] = createParseContext(context);
break;
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/utils/clone.js
Expand Up @@ -3,7 +3,7 @@ import { List } from './List.js';
export function clone(node) {
const result = {};

for (const key in node) {
for (const key of Object.keys(node)) {
let value = node[key];

if (value) {
Expand Down
6 changes: 3 additions & 3 deletions package.json
Expand Up @@ -92,9 +92,9 @@
"lint-and-test": "npm run lint && npm test",
"update:docs": "node scripts/update-docs",
"review:syntax-patch": "node scripts/review-syntax-patch",
"test": "mocha lib/__tests --reporter ${REPORTER:-progress}",
"test:cjs": "mocha cjs/__tests --reporter ${REPORTER:-progress}",
"test:dist": "mocha dist/__tests --reporter ${REPORTER:-progress}",
"test": "mocha lib/__tests --require lib/__tests/helpers/setup.js --reporter progress",
"test:cjs": "mocha cjs/__tests --require lib/__tests/helpers/setup.js --reporter progress",
"test:dist": "mocha dist/__tests --reporter progress",
"coverage": "c8 --exclude lib/__tests --reporter=lcovonly npm test",
"prepublishOnly": "npm run lint-and-test && npm run build-and-test",
"hydrogen": "node --trace-hydrogen --trace-phase=Z --trace-deopt --code-comments --hydrogen-track-positions --redirect-code-traces --redirect-code-traces-to=code.asm --trace_hydrogen_file=code.cfg --print-opt-code bin/parse --stat -o /dev/null"
Expand Down

0 comments on commit 26a64c7

Please sign in to comment.