Skip to content

Commit af91b93

Browse files
committed
Update handling of nested Sass
Resolves #13 Resolves #14
1 parent 8fe24a6 commit af91b93

14 files changed

+316
-115
lines changed

package.json

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,22 +42,24 @@
4242
"trailingComma": "all"
4343
},
4444
"dependencies": {
45-
"@types/lodash": "^4.14.118",
4645
"icss-utils": "^4.0.0",
4746
"lodash": "^4.17.11",
48-
"postcss": "^7.0.5",
49-
"postcss-icss-selectors": "^2.0.3"
47+
"postcss": "^7.0.7",
48+
"postcss-icss-selectors": "^2.0.3",
49+
"postcss-nested": "^4.1.1",
50+
"strip-css-singleline-comments": "^1.1.0"
5051
},
5152
"devDependencies": {
52-
"@types/jest": "^23.3.9",
53-
"@types/node": "^10.12.6",
54-
"husky": "^1.1.3",
53+
"@types/jest": "^23.3.12",
54+
"@types/lodash": "^4.14.119",
55+
"@types/node": "^10.12.18",
56+
"husky": "^1.3.1",
5557
"jest": "^23.6.0",
56-
"prettier": "^1.15.2",
58+
"prettier": "^1.15.3",
5759
"pretty-quick": "^1.8.0",
58-
"ts-jest": "^23.10.4",
59-
"tslint": "^5.11.0",
60-
"typescript": "^3.1.6"
60+
"ts-jest": "^23.10.5",
61+
"tslint": "^5.12.0",
62+
"typescript": "^3.2.2"
6163
},
6264
"peerDependencies": {
6365
"typescript": "^3.0.0"
File renamed without changes.

src/@types/postcss-nested.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
declare module 'postcss-nested' {
2+
import { Plugin } from 'postcss';
3+
const plugin: Plugin<any>;
4+
export = plugin;
5+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
declare module 'strip-css-singleline-comments/sync' {
2+
const strip: (s: string) => string;
3+
export = strip;
4+
}

src/helpers/__tests__/__snapshots__/cssSnapshots.test.ts.snap

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`utils / cssSnapshots createExports should create an exports file 1`] = `
3+
exports[`utils / cssSnapshots with file 'empty.module.scss' createExports should create an exports file 1`] = `
4+
"declare const classes: {
5+
6+
};
7+
export default classes;
8+
"
9+
`;
10+
11+
exports[`utils / cssSnapshots with file 'empty.module.scss' getClasses should return an object matching expected CSS 1`] = `Object {}`;
12+
13+
exports[`utils / cssSnapshots with file 'test.module.css' createExports should create an exports file 1`] = `
414
"declare const classes: {
515
'classA': string;
616
'ClassB': string;
@@ -14,13 +24,40 @@ export default classes;
1424
"
1525
`;
1626

17-
exports[`utils / cssSnapshots createExports should create an exports file 2`] = `
27+
exports[`utils / cssSnapshots with file 'test.module.css' getClasses should return an object matching expected CSS 1`] = `
28+
Object {
29+
"ClassB": "file__ClassB---2bPVi",
30+
"childA": "file__childA---1hjQD",
31+
"childB": "file__childB---pq4Ks",
32+
"class-c": "file__class-c---DZ1TD",
33+
"classA": "file__classA---2xcnJ",
34+
"nestedChild": "file__nestedChild---2d15b",
35+
"parent": "file__parent---1ATMj",
36+
}
37+
`;
38+
39+
exports[`utils / cssSnapshots with file 'test.module.scss' createExports should create an exports file 1`] = `
1840
"declare const classes: {
1941
'local-class-inside-global': string;
2042
'local-class': string;
2143
'local-class-2': string;
2244
'local-class-inside-local': string;
45+
'nested-class-parent': string;
46+
'child-class': string;
47+
'nested-class-parent--extended': string;
2348
};
2449
export default classes;
2550
"
2651
`;
52+
53+
exports[`utils / cssSnapshots with file 'test.module.scss' getClasses should return an object matching expected CSS 1`] = `
54+
Object {
55+
"child-class": "file__child-class---1mwoB",
56+
"local-class": "file__local-class---3KegX",
57+
"local-class-2": "file__local-class-2---2h6qz",
58+
"local-class-inside-global": "file__local-class-inside-global---2xH_Y",
59+
"local-class-inside-local": "file__local-class-inside-local---QdL6b",
60+
"nested-class-parent": "file__nested-class-parent---_ft7G",
61+
"nested-class-parent--extended": "file__nested-class-parent--extended---1642l",
62+
}
63+
`;

src/helpers/__tests__/cssSnapshots.test.ts

Lines changed: 25 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,49 +3,37 @@ import { IICSSExports } from 'icss-utils';
33
import { join } from 'path';
44
import { createExports, getClasses } from '../cssSnapshots';
55

6-
describe('utils / cssSnapshots', () => {
7-
let classesA: IICSSExports;
8-
let classesB: IICSSExports;
6+
const testFileNames = [
7+
'test.module.css',
8+
'test.module.scss',
9+
'empty.module.scss',
10+
];
911

10-
beforeAll(() => {
11-
const testFileA = readFileSync(
12-
join(__dirname, 'fixtures/testA.module.css'),
13-
'utf8',
14-
);
15-
const testFileB = readFileSync(
16-
join(__dirname, 'fixtures/testB.module.scss'),
12+
describe('utils / cssSnapshots', () => {
13+
testFileNames.map((filename) => {
14+
let classes: IICSSExports;
15+
const testFile = readFileSync(
16+
join(__dirname, 'fixtures', filename),
1717
'utf8',
1818
);
19-
classesA = getClasses(testFileA);
20-
classesB = getClasses(testFileB);
21-
});
2219

23-
describe('getClasses', () => {
24-
it('should return an object matching expected CSS classes', () => {
25-
expect(classesA).toEqual({
26-
ClassB: 'file__ClassB---2bPVi',
27-
childA: 'file__childA---1hjQD',
28-
childB: 'file__childB---pq4Ks',
29-
'class-c': 'file__class-c---DZ1TD',
30-
classA: 'file__classA---2xcnJ',
31-
nestedChild: 'file__nestedChild---2d15b',
32-
parent: 'file__parent---1ATMj',
33-
});
34-
expect(classesB).toEqual({
35-
'local-class': 'file__local-class---3KegX',
36-
'local-class-2': 'file__local-class-2---2h6qz',
37-
'local-class-inside-global': 'file__local-class-inside-global---2xH_Y',
38-
'local-class-inside-local': 'file__local-class-inside-local---QdL6b',
39-
});
20+
beforeAll(() => {
21+
classes = getClasses(testFile);
4022
});
41-
});
4223

43-
describe('createExports', () => {
44-
it('should create an exports file', () => {
45-
const exportsA = createExports(classesA, {});
46-
const exportsB = createExports(classesB, {});
47-
expect(exportsA).toMatchSnapshot();
48-
expect(exportsB).toMatchSnapshot();
24+
describe(`with file '${filename}'`, () => {
25+
describe('getClasses', () => {
26+
it('should return an object matching expected CSS', () => {
27+
expect(classes).toMatchSnapshot();
28+
});
29+
});
30+
31+
describe('createExports', () => {
32+
it('should create an exports file', () => {
33+
const exports = createExports(classes, {});
34+
expect(exports).toMatchSnapshot();
35+
});
36+
});
4937
});
5038
});
5139
});

src/helpers/__tests__/fixtures/empty.module.scss

Whitespace-only changes.

src/helpers/__tests__/fixtures/testB.module.scss renamed to src/helpers/__tests__/fixtures/test.module.scss

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,14 @@
1313
.local-class-inside-local {
1414
}
1515
}
16+
17+
.nested-class-parent {
18+
.child-class {
19+
}
20+
&--extended {
21+
}
22+
}
23+
24+
// .commented-parent-class {
25+
// .commented-child-class
26+
// }

src/helpers/cssSnapshots.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,25 @@
11
import { extractICSS, IICSSExports } from 'icss-utils';
22
import * as postcss from 'postcss';
33
import * as postcssIcssSelectors from 'postcss-icss-selectors';
4+
import * as postcssNested from 'postcss-nested';
5+
import * as strip from 'strip-css-singleline-comments/sync';
46
import * as ts_module from 'typescript/lib/tsserverlibrary';
57
import { transformClasses } from './classTransforms';
68

7-
const processor = postcss(postcssIcssSelectors({ mode: 'local' }));
9+
const processor = postcss(
10+
postcssNested,
11+
postcssIcssSelectors({ mode: 'local' }),
12+
);
813

9-
export const getClasses = (css: string) =>
10-
extractICSS(processor.process(css).root).icssExports;
14+
export const getClasses = (css: string) => {
15+
try {
16+
const cleanCss = strip(css);
17+
const processedCss = processor.process(cleanCss);
18+
return extractICSS(processedCss.root).icssExports;
19+
} catch (e) {
20+
return {};
21+
}
22+
};
1123
const classNameToProperty = (className: string) => `'${className}': string;`;
1224
const flattenClassNames = (
1325
previousValue: string[] = [],
@@ -18,7 +30,7 @@ export const createExports = (classes: IICSSExports, options: IOptions) => `\
1830
declare const classes: {
1931
${Object.keys(classes)
2032
.map(transformClasses(options.camelCase))
21-
.reduce(flattenClassNames)
33+
.reduce(flattenClassNames, [])
2234
.map(classNameToProperty)
2335
.join('\n ')}
2436
};

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ function init({ typescript: ts }: { typescript: typeof ts_module }) {
6666
containingFile,
6767
reusedNames,
6868
) => {
69-
const resolvedModules: ts_module.ResolvedModuleFull[] = _resolveModuleNames(
69+
const resolvedModules = _resolveModuleNames(
7070
moduleNames,
7171
containingFile,
7272
reusedNames,

tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@
1616
"strictNullChecks": true,
1717
"target": "es5"
1818
},
19-
"include": ["src"]
19+
"include": ["src"],
20+
"exclude": ["node_modules", "**/__tests__/**"]
2021
}

0 commit comments

Comments
 (0)