cssstyle 0.2.34 → 0.3.1

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,57 @@
1
1
  {
2
- "name": "cssstyle",
3
- "description": "CSSStyleDeclaration Object Model implementation",
4
- "keywords": ["CSS", "CSSStyleDeclaration", "StyleSheet"],
5
- "version": "0.2.34",
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.3.1",
10
+ "homepage": "https://github.com/jsakas/CSSStyleDeclaration",
11
+ "maintainers": [
12
+ {
13
+ "name": "Jon Sakas",
14
+ "email": "jon.sakas@gmail.com",
15
+ "url": "http://jon.sakas.co/"
16
+ }
17
+ ],
18
+ "contributors": [
19
+ {
20
+ "name": "Chad Walker",
21
+ "email": "chad@chad-cat-lore-eddie.com",
22
+ "url": "https://github.com/chad3814"
22
23
  },
23
- "main": "./lib/CSSStyleDeclaration.js",
24
- "dependencies": {
25
- "cssom": "0.3.x"
24
+ {
25
+ "name": "Nikita Vasilyev",
26
+ "email": "me@elv1s.ru"
26
27
  },
27
- "devDependencies" : {
28
- "nodeunit": "~0.8.0"
28
+ {
29
+ "name": "Davide P. Cervone"
29
30
  },
30
- "scripts": {
31
- "test": "./scripts/run_tests.sh",
32
- "prepublish": "node ./scripts/generate_properties.js"
33
- },
34
- "license": "MIT"
31
+ {
32
+ "name": "Forbes Lindesay"
33
+ }
34
+ ],
35
+ "repository": "jsakas/CSSStyleDeclaration",
36
+ "bugs": "https://github.com/jsakas/CSSStyleDeclaration/issues",
37
+ "directories": {
38
+ "lib": "./lib"
39
+ },
40
+ "main": "./lib/CSSStyleDeclaration.js",
41
+ "dependencies": {
42
+ "cssom": "0.3.x"
43
+ },
44
+ "devDependencies": {
45
+ "babel-generator": "~6.11.4",
46
+ "babel-traverse": "~6.13.0",
47
+ "babel-types": "~6.13.0",
48
+ "babylon": "~6.8.4",
49
+ "nodeunit": "~0.8.0",
50
+ "resolve": "~1.1.7"
51
+ },
52
+ "scripts": {
53
+ "test": "./scripts/run_tests.sh",
54
+ "prepublish": "node ./scripts/generate_properties.js"
55
+ },
56
+ "license": "MIT"
35
57
  }
@@ -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"];
@@ -380,5 +392,33 @@ module.exports = {
380
392
  style.marginTop = '0'
381
393
  test.equal(style.marginTop, '0px', 'margin-top is not 0px');
382
394
  test.done();
395
+ },
396
+ 'Make sure setting ex units to a padding or margin works': function (test) {
397
+ var style = new cssstyle.CSSStyleDeclaration();
398
+ test.expect(2);
399
+ style.padding = '1ex';
400
+ test.equal(style.cssText, 'padding: 1ex;', 'padding is not 1ex');
401
+ style.margin = '1em';
402
+ style.marginTop = '0.5ex'
403
+ test.equal(style.marginTop, '0.5ex', 'margin-top is not 0.5ex');
404
+ test.done();
405
+ },
406
+ 'Make sure setting null to background works': function (test) {
407
+ var style = new cssstyle.CSSStyleDeclaration();
408
+ test.expect(2);
409
+ style.background = 'red';
410
+ test.equal(style.cssText, 'background: red;', 'background is not red');
411
+ style.background = null;
412
+ test.equal(style.cssText, '', 'cssText is not empty');
413
+ test.done();
414
+ },
415
+ 'Flex properties should keep their values': function (test) {
416
+ var style = new cssstyle.CSSStyleDeclaration();
417
+ test.expect(2);
418
+ style.flexDirection = 'column';
419
+ test.equal(style.cssText, 'flex-direction: column;', 'flex-direction is not column');
420
+ style.flexDirection = 'row';
421
+ test.equal(style.cssText, 'flex-direction: row;', 'flex-direction is not column');
422
+ test.done();
383
423
  }
384
424
  };
package/.npmignore DELETED
@@ -1 +0,0 @@
1
- node_module