cssstyle 0.2.31 → 0.2.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,35 +1,52 @@
1
1
  {
2
- "name": "cssstyle",
3
- "description": "CSSStyleDeclaration Object Model implementation",
4
- "keywords": ["CSS", "CSSStyleDeclaration", "StyleSheet"],
5
- "version": "0.2.31",
6
- "homepage": "https://github.com/chad3814/CSSStyleDeclaration",
7
- "maintainers": [{
8
- "name": "Chad Walker",
9
- "email": "chad@chad-cat-lore-eddie.com",
10
- "url": "https://github.com/chad3814"
11
- }],
12
- "contributors": [{
13
- "name": "Nikita Vasilyev",
14
- "email": "me@elv1s.ru"
15
- }, {
16
- "name": "Davide P. Cervone"
17
- }],
18
- "repository": "chad3814/CSSStyleDeclaration",
19
- "bugs": "https://github.com/chad3814/CSSStyleDeclaration/issues",
20
- "directories": {
21
- "lib": "./lib"
2
+ "name": "cssstyle",
3
+ "description": "CSSStyleDeclaration Object Model implementation",
4
+ "keywords": [
5
+ "CSS",
6
+ "CSSStyleDeclaration",
7
+ "StyleSheet"
8
+ ],
9
+ "version": "0.2.37",
10
+ "homepage": "https://github.com/chad3814/CSSStyleDeclaration",
11
+ "maintainers": [
12
+ {
13
+ "name": "Chad Walker",
14
+ "email": "chad@chad-cat-lore-eddie.com",
15
+ "url": "https://github.com/chad3814"
16
+ }
17
+ ],
18
+ "contributors": [
19
+ {
20
+ "name": "Nikita Vasilyev",
21
+ "email": "me@elv1s.ru"
22
22
  },
23
- "main": "./lib/CSSStyleDeclaration.js",
24
- "dependencies": {
25
- "cssom": "0.3.x"
23
+ {
24
+ "name": "Davide P. Cervone"
26
25
  },
27
- "devDependencies" : {
28
- "nodeunit": "~0.8.0"
29
- },
30
- "scripts": {
31
- "test": "./scripts/run_tests.sh",
32
- "prepublish": "node ./scripts/generate_properties.js"
33
- },
34
- "license": "MIT"
26
+ {
27
+ "name": "Forbes Lindesay"
28
+ }
29
+ ],
30
+ "repository": "chad3814/CSSStyleDeclaration",
31
+ "bugs": "https://github.com/chad3814/CSSStyleDeclaration/issues",
32
+ "directories": {
33
+ "lib": "./lib"
34
+ },
35
+ "main": "./lib/CSSStyleDeclaration.js",
36
+ "dependencies": {
37
+ "cssom": "0.3.x"
38
+ },
39
+ "devDependencies": {
40
+ "babel-generator": "~6.11.4",
41
+ "babel-traverse": "~6.13.0",
42
+ "babel-types": "~6.13.0",
43
+ "babylon": "~6.8.4",
44
+ "nodeunit": "~0.8.0",
45
+ "resolve": "~1.1.7"
46
+ },
47
+ "scripts": {
48
+ "test": "./scripts/run_tests.sh",
49
+ "prepublish": "node ./scripts/generate_properties.js"
50
+ },
51
+ "license": "MIT"
35
52
  }
@@ -2,30 +2,299 @@
2
2
 
3
3
  var fs = require('fs');
4
4
  var path = require('path');
5
+ var babylon = require('babylon');
6
+ var t = require('babel-types');
7
+ var generate = require('babel-generator').default;
8
+ var traverse = require('babel-traverse').default;
9
+ var resolve = require('resolve');
5
10
 
6
11
  var camelToDashed = require('../lib/parsers').camelToDashed;
7
12
 
8
- var property_files = fs.readdirSync(path.resolve(__dirname, '../lib/properties'));
13
+ var basename = path.basename;
14
+ var dirname = path.dirname;
15
+
16
+ var uniqueIndex = 0;
17
+ function getUniqueIndex() {
18
+ return uniqueIndex++;
19
+ }
20
+
21
+ var property_files = fs.readdirSync(path.resolve(__dirname, '../lib/properties')).filter(function (property) {
22
+ return property.substr(-3) === '.js';
23
+ });
9
24
  var out_file = fs.createWriteStream(path.resolve(__dirname, '../lib/properties.js'), {encoding: 'utf-8'});
10
25
 
11
26
  out_file.write('\'use strict\';\n\n// autogenerated\n\n');
12
27
  out_file.write('/*\n *\n * http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSS2Properties\n */\n\n');
13
- out_file.write('module.exports = function (prototype) {\n');
14
-
15
- property_files.forEach(function (property) {
16
- var dashed;
17
- if (property.substr(-3) === '.js') {
18
- property = path.basename(property, '.js');
19
- dashed = camelToDashed(property);
20
- out_file.write(' var '+property+' = require(\'./properties/' + property + '\').definition;\n');
21
- out_file.write(' Object.defineProperty(prototype, \'' + property + '\', '+property+')\n');
22
- if (property !== dashed) {
23
- out_file.write(' Object.defineProperty(prototype, \'' + dashed + '\', '+property+')\n');
28
+
29
+ function isModuleDotExports(node) {
30
+ return (
31
+ t.isMemberExpression(node, {computed: false}) &&
32
+ t.isIdentifier(node.object, {name: 'module'}) &&
33
+ t.isIdentifier(node.property, {name: 'exports'})
34
+ );
35
+ }
36
+ function isRequire(node, filename) {
37
+ if (
38
+ t.isCallExpression(node) &&
39
+ t.isIdentifier(node.callee, {name: 'require'}) &&
40
+ node.arguments.length === 1 &&
41
+ t.isStringLiteral(node.arguments[0])
42
+ ) {
43
+ var relative = node.arguments[0].value;
44
+ var fullPath = resolve.sync(relative, {basedir: dirname(filename)});
45
+ return {relative: relative, fullPath: fullPath};
46
+ } else {
47
+ return false;
48
+ }
49
+ }
50
+
51
+ // step 1: parse all files and figure out their dependencies
52
+ var parsedFilesByPath = {};
53
+ property_files.map(function (property) {
54
+ var filename = path.resolve(__dirname, '../lib/properties/' + property);
55
+ var src = fs.readFileSync(filename, 'utf8');
56
+ property = basename(property, '.js');
57
+ var ast = babylon.parse(src);
58
+ var dependencies = [];
59
+ traverse(ast, {
60
+ enter(path) {
61
+ var r;
62
+ if (r = isRequire(path.node, filename)) {
63
+ dependencies.push(r.fullPath);
24
64
  }
25
- }
65
+ }
66
+ });
67
+ parsedFilesByPath[filename] = {
68
+ filename: filename,
69
+ property: property,
70
+ ast: ast,
71
+ dependencies: dependencies,
72
+ };
26
73
  });
27
74
 
28
- out_file.write('};\n');
75
+ // step 2: serialize the files in an order where dependencies are always above
76
+ // the files they depend on
77
+ var externalDependencies = [];
78
+ var parsedFiles = [];
79
+ var addedFiles = {};
80
+ function addFile(filename, dependencyPath) {
81
+ if (dependencyPath.indexOf(filename) !== -1) {
82
+ throw new Error(
83
+ 'Circular dependency: ' +
84
+ dependencyPath.slice(dependencyPath.indexOf(filename)).concat([filename]).join(' -> ')
85
+ );
86
+ }
87
+ var file = parsedFilesByPath[filename];
88
+ if (addedFiles[filename]) {
89
+ return;
90
+ }
91
+ if (!file) {
92
+ externalDependencies.push(filename);
93
+ } else {
94
+ file.dependencies.forEach(function (dependency) {
95
+ addFile(dependency, dependencyPath.concat([filename]));
96
+ });
97
+ parsedFiles.push(parsedFilesByPath[filename]);
98
+ }
99
+ addedFiles[filename] = true;
100
+ }
101
+ Object.keys(parsedFilesByPath).forEach(function (filename) {
102
+ addFile(filename, []);
103
+ });
104
+ // Step 3: add files to output
105
+ // renaming exports to local variables `moduleName_export_exportName`
106
+ // and updating require calls as appropriate
107
+ var moduleExportsByPath = {};
108
+ var statements = [];
109
+ externalDependencies.forEach(function (filename, i) {
110
+ var id = t.identifier(
111
+ 'external_dependency_' +
112
+ basename(filename, '.js').replace(/[^A-Za-z]/g, '') +
113
+ '_' + i
114
+ );
115
+ moduleExportsByPath[filename] = {defaultExports: id};
116
+ var relativePath = path.relative(path.resolve(__dirname + '/../lib'), filename);
117
+ if (relativePath[0] !== '.') {
118
+ relativePath = './' + relativePath;
119
+ }
120
+ statements.push(t.variableDeclaration(
121
+ 'var',
122
+ [
123
+ t.variableDeclarator(
124
+ id,
125
+ t.callExpression(
126
+ t.identifier('require'),
127
+ [
128
+ t.stringLiteral(
129
+ relativePath
130
+ )
131
+ ]
132
+ )
133
+ )
134
+ ]
135
+ ));
136
+ });
137
+ function getRequireValue(node, file) {
138
+ var r;
139
+ // replace require("./foo").bar with the named export from foo
140
+ if (
141
+ t.isMemberExpression(node, {computed: false}) &&
142
+ (r = isRequire(node.object, file.filename))
143
+ ) {
144
+ var e = moduleExportsByPath[r.fullPath];
145
+ if (!e) {
146
+ return;
147
+ }
148
+ if (!e.namedExports) {
149
+ return t.memberExpression(
150
+ e.defaultExports,
151
+ node.property
152
+ );
153
+ }
154
+ if (!e.namedExports[node.property.name]) {
155
+ throw new Error(r.relative + ' does not export ' + node.property.name);
156
+ }
157
+ return e.namedExports[node.property.name];
158
+
159
+ // replace require("./foo") with the default export of foo
160
+ } else if (r = isRequire(node, file.filename)) {
161
+ var e = moduleExportsByPath[r.fullPath];
162
+ if (!e) {
163
+ if (/^\.\.\//.test(r.relative)) {
164
+ node.arguments[0].value = r.relative.substr(1);
165
+ }
166
+ return;
167
+ }
168
+ return e.defaultExports;
169
+ }
170
+ }
171
+ parsedFiles.forEach(function (file) {
172
+ var namedExports = {};
173
+ var localVariableMap = {};
174
+
175
+ traverse(file.ast, {
176
+ enter(path) {
177
+ // replace require calls with the corresponding value
178
+ var r;
179
+ if (r = getRequireValue(path.node, file)) {
180
+ path.replaceWith(r);
181
+ return;
182
+ }
183
+
184
+ // if we see `var foo = require('bar')` we can just inline the variable
185
+ // representing `require('bar')` wherever `foo` was used.
186
+ if (
187
+ t.isVariableDeclaration(path.node) &&
188
+ path.node.declarations.length === 1 &&
189
+ t.isIdentifier(path.node.declarations[0].id) &&
190
+ (r = getRequireValue(path.node.declarations[0].init, file))
191
+ ) {
192
+ var newName = 'compiled_local_variable_reference_' + getUniqueIndex();
193
+ path.scope.rename(
194
+ path.node.declarations[0].id.name,
195
+ newName
196
+ );
197
+ localVariableMap[newName] = r;
198
+ path.remove();
199
+ return;
200
+ }
201
+
202
+ // rename all top level variables to keep them local to the module
203
+ if (
204
+ t.isVariableDeclaration(path.node) &&
205
+ t.isProgram(path.parent)
206
+ ) {
207
+ path.node.declarations.forEach(function (declaration) {
208
+ path.scope.rename(
209
+ declaration.id.name,
210
+ file.property + '_local_var_' + declaration.id.name
211
+ );
212
+ });
213
+ return;
214
+ }
215
+
216
+ // replace module.exports.bar with a variable for the named export
217
+ if (
218
+ t.isMemberExpression(path.node, {computed: false}) &&
219
+ isModuleDotExports(path.node.object)
220
+ ) {
221
+ var name = path.node.property.name;
222
+ var identifier = t.identifier(file.property + '_export_' + name);
223
+ path.replaceWith(identifier);
224
+ namedExports[name] = identifier;
225
+ }
226
+ }
227
+ });
228
+ traverse(file.ast, {
229
+ enter(path) {
230
+ if (
231
+ t.isIdentifier(path.node) &&
232
+ Object.prototype.hasOwnProperty.call(localVariableMap, path.node.name)
233
+ ) {
234
+ path.replaceWith(localVariableMap[path.node.name]);
235
+ }
236
+ }
237
+ });
238
+ var defaultExports = t.objectExpression(Object.keys(namedExports).map(function (name) {
239
+ return t.objectProperty(t.identifier(name), namedExports[name]);
240
+ }));
241
+ moduleExportsByPath[file.filename] = {
242
+ namedExports: namedExports,
243
+ defaultExports: defaultExports
244
+ };
245
+ statements.push(t.variableDeclaration(
246
+ 'var',
247
+ Object.keys(namedExports).map(function (name) {
248
+ return t.variableDeclarator(namedExports[name]);
249
+ })
250
+ ))
251
+ statements.push.apply(statements, file.ast.program.body);
252
+ });
253
+ var propertyDefinitions = [];
254
+ parsedFiles.forEach(function (file) {
255
+ var dashed = camelToDashed(file.property);
256
+ propertyDefinitions.push(
257
+ t.objectProperty(
258
+ t.identifier(file.property),
259
+ t.identifier(file.property + '_export_definition')
260
+ )
261
+ );
262
+ if (file.property !== dashed) {
263
+ propertyDefinitions.push(
264
+ t.objectProperty(
265
+ t.stringLiteral(dashed),
266
+ t.identifier(file.property + '_export_definition')
267
+ )
268
+ );
269
+ }
270
+ });
271
+ var definePropertiesCall = t.callExpression(
272
+ t.memberExpression(
273
+ t.identifier('Object'),
274
+ t.identifier('defineProperties')
275
+ ),
276
+ [
277
+ t.identifier('prototype'),
278
+ t.objectExpression(
279
+ propertyDefinitions
280
+ )
281
+ ]
282
+ );
283
+ statements.push(t.expressionStatement(
284
+ t.assignmentExpression(
285
+ '=',
286
+ t.memberExpression(
287
+ t.identifier('module'),
288
+ t.identifier('exports')
289
+ ),
290
+ t.functionExpression(
291
+ null,
292
+ [t.identifier('prototype')],
293
+ t.blockStatement([t.expressionStatement(definePropertiesCall)])
294
+ )
295
+ )
296
+ ));
297
+ out_file.write(generate(t.program(statements)).code + '\n')
29
298
  out_file.end(function (err) {
30
299
  if (err) {
31
300
  throw err;
package/tests/tests.js CHANGED
@@ -281,6 +281,18 @@ module.exports = {
281
281
  test.ok('opacity: 1;' === style.cssText, 'cssText is not "opacity: 1;": ' + style.cssText);
282
282
  test.done();
283
283
  },
284
+ 'Width and height of auto should work': function (test) {
285
+ var style = new cssstyle.CSSStyleDeclaration();
286
+ test.expect(4);
287
+ style.width = "auto";
288
+ test.equal(style.cssText,'width: auto;', 'cssText is not "width: auto;": ' + style.cssText);
289
+ test.equal(style.width,'auto', 'width is not "auto": ' + style.width);
290
+ style = new cssstyle.CSSStyleDeclaration();
291
+ style.height = "auto";
292
+ test.equal(style.cssText,'height: auto;', 'cssText is not "height: auto;": ' + style.cssText);
293
+ test.equal(style.height,'auto', 'height is not "auto": ' + style.height);
294
+ test.done();
295
+ },
284
296
  'Padding and margin should set/clear shorthand properties': function (test) {
285
297
  var style = new cssstyle.CSSStyleDeclaration();
286
298
  var parts = ["Top","Right","Bottom","Left"];
@@ -288,9 +300,9 @@ module.exports = {
288
300
  style[name] = v;
289
301
  for (var i = 0; i < 4; i++) {
290
302
  var part = name + parts[i];
291
- test.ok(V[i] === style[part], part + ' is not "' + V[i] + '": ' + style[part]);
303
+ test.equal(V[i],style[part], part + ' is not "' + V[i] + '": "' + style[part] + '"');
292
304
  }
293
- test.ok(v === style[name], name + ' is not "' + v + '": ' + style[name]);
305
+ test.equal(v,style[name], name + ' is not "' + v + '": "' + style[name] + '"');
294
306
  style[name] = "";
295
307
  };
296
308
  test.expect(50);
@@ -308,6 +320,26 @@ module.exports = {
308
320
  testParts("margin","",["","","",""]);
309
321
  test.done();
310
322
  },
323
+ 'Padding and margin shorthands should set main properties': function (test) {
324
+ var style = new cssstyle.CSSStyleDeclaration();
325
+ var parts = ["Top","Right","Bottom","Left"];
326
+ var testParts = function (name,v,V) {
327
+ var expect;
328
+ for (var i = 0; i < 4; i++) {
329
+ style[name] = v;
330
+ style[name+parts[i]] = V;
331
+ expect = v.split(/ /);
332
+ expect[i] = V;
333
+ expect = expect.join(" ");
334
+ test.equal(expect,style[name], name + ' is not "' + expect + '": "' + style[name] + '"');
335
+ }
336
+ };
337
+ test.expect(12);
338
+ testParts("padding","1px 2px 3px 4px","10px");
339
+ testParts("margin","1px 2px 3px 4px","10px");
340
+ testParts("margin","1px 2px 3px 4px","auto");
341
+ test.done();
342
+ },
311
343
  'Setting a value to 0 should return the string value': function (test) {
312
344
  var style = new cssstyle.CSSStyleDeclaration();
313
345
  test.expect(1);
@@ -350,5 +382,24 @@ module.exports = {
350
382
  style.backgroundImage = 'url("http://some/url/here3.png")';
351
383
  test.ok('url(http://some/url/here3.png)' === style.backgroundImage, 'background-image wasn\'t url(http://some/url/here3.png): ' + style.backgroundImage);
352
384
  test.done();
385
+ },
386
+ 'Make sure setting 0 to a padding or margin works': function (test) {
387
+ var style = new cssstyle.CSSStyleDeclaration();
388
+ test.expect(2);
389
+ style.padding = 0;
390
+ test.equal(style.cssText, 'padding: 0px;', 'padding is not 0px');
391
+ style.margin = '1em';
392
+ style.marginTop = '0'
393
+ test.equal(style.marginTop, '0px', 'margin-top is not 0px');
394
+ test.done();
395
+ },
396
+ 'Make sure setting null to background works': function (test) {
397
+ var style = new cssstyle.CSSStyleDeclaration();
398
+ test.expect(2);
399
+ style.background = 'red';
400
+ test.equal(style.cssText, 'background: red;', 'background is not red');
401
+ style.background = null;
402
+ test.equal(style.cssText, '', 'cssText is not empty');
403
+ test.done();
353
404
  }
354
405
  };