happy-css-modules 3.0.1 → 3.1.0
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 +1 -1
- package/src/emitter/dts.test.ts +3 -3
- package/src/emitter/dts.ts +59 -37
- package/src/emitter/index.test.ts +3 -3
- package/src/locator/index.test.ts +143 -48
- package/src/locator/index.ts +51 -23
- package/src/locator/postcss.test.ts +135 -26
- package/src/locator/postcss.ts +120 -36
- package/src/test-util/util.ts +23 -18
- package/src/transformer/less-transformer.test.ts +25 -15
- package/src/transformer/postcss-transformer.test.ts +5 -3
- package/src/transformer/scss-transformer.test.ts +38 -19
- package/dist/cli.d.ts +0 -6
- package/dist/cli.js +0 -121
- package/dist/cli.js.map +0 -1
- package/dist/cli.test.d.ts +0 -1
- package/dist/cli.test.js +0 -66
- package/dist/cli.test.js.map +0 -1
- package/dist/config.d.ts +0 -1
- package/dist/config.js +0 -2
- package/dist/config.js.map +0 -1
- package/dist/emitter/dts.d.ts +0 -14
- package/dist/emitter/dts.js +0 -111
- package/dist/emitter/dts.js.map +0 -1
- package/dist/emitter/dts.test.d.ts +0 -1
- package/dist/emitter/dts.test.js +0 -205
- package/dist/emitter/dts.test.js.map +0 -1
- package/dist/emitter/file-system.d.ts +0 -6
- package/dist/emitter/file-system.js +0 -26
- package/dist/emitter/file-system.js.map +0 -1
- package/dist/emitter/file-system.test.d.ts +0 -1
- package/dist/emitter/file-system.test.js +0 -34
- package/dist/emitter/file-system.test.js.map +0 -1
- package/dist/emitter/index.d.ts +0 -34
- package/dist/emitter/index.js +0 -49
- package/dist/emitter/index.js.map +0 -1
- package/dist/emitter/index.test.d.ts +0 -1
- package/dist/emitter/index.test.js +0 -68
- package/dist/emitter/index.test.js.map +0 -1
- package/dist/emitter/source-map.d.ts +0 -8
- package/dist/emitter/source-map.js +0 -16
- package/dist/emitter/source-map.js.map +0 -1
- package/dist/emitter/source-map.test.d.ts +0 -1
- package/dist/emitter/source-map.test.js +0 -13
- package/dist/emitter/source-map.test.js.map +0 -1
- package/dist/index.d.ts +0 -5
- package/dist/index.js +0 -6
- package/dist/index.js.map +0 -1
- package/dist/integration-test/go-to-definition.test.d.ts +0 -1
- package/dist/integration-test/go-to-definition.test.js +0 -334
- package/dist/integration-test/go-to-definition.test.js.map +0 -1
- package/dist/library/source-map/index.d.ts +0 -8
- package/dist/library/source-map/index.js +0 -5
- package/dist/library/source-map/index.js.map +0 -1
- package/dist/locator/index.d.ts +0 -44
- package/dist/locator/index.js +0 -147
- package/dist/locator/index.js.map +0 -1
- package/dist/locator/index.test.d.ts +0 -1
- package/dist/locator/index.test.js +0 -299
- package/dist/locator/index.test.js.map +0 -1
- package/dist/locator/postcss.d.ts +0 -53
- package/dist/locator/postcss.js +0 -169
- package/dist/locator/postcss.js.map +0 -1
- package/dist/locator/postcss.test.d.ts +0 -1
- package/dist/locator/postcss.test.js +0 -196
- package/dist/locator/postcss.test.js.map +0 -1
- package/dist/logger.d.ts +0 -9
- package/dist/logger.js +0 -28
- package/dist/logger.js.map +0 -1
- package/dist/regression-test/issue-168.test.d.ts +0 -1
- package/dist/regression-test/issue-168.test.js +0 -30
- package/dist/regression-test/issue-168.test.js.map +0 -1
- package/dist/resolver/index.d.ts +0 -22
- package/dist/resolver/index.js +0 -44
- package/dist/resolver/index.js.map +0 -1
- package/dist/resolver/index.test.d.ts +0 -1
- package/dist/resolver/index.test.js +0 -16
- package/dist/resolver/index.test.js.map +0 -1
- package/dist/resolver/node-resolver.d.ts +0 -2
- package/dist/resolver/node-resolver.js +0 -6
- package/dist/resolver/node-resolver.js.map +0 -1
- package/dist/resolver/node-resolver.test.d.ts +0 -1
- package/dist/resolver/node-resolver.test.js +0 -25
- package/dist/resolver/node-resolver.test.js.map +0 -1
- package/dist/resolver/relative-resolver.d.ts +0 -2
- package/dist/resolver/relative-resolver.js +0 -5
- package/dist/resolver/relative-resolver.js.map +0 -1
- package/dist/resolver/relative-resolver.test.d.ts +0 -1
- package/dist/resolver/relative-resolver.test.js +0 -12
- package/dist/resolver/relative-resolver.test.js.map +0 -1
- package/dist/resolver/webpack-resolver.d.ts +0 -24
- package/dist/resolver/webpack-resolver.js +0 -91
- package/dist/resolver/webpack-resolver.js.map +0 -1
- package/dist/resolver/webpack-resolver.test.d.ts +0 -1
- package/dist/resolver/webpack-resolver.test.js +0 -89
- package/dist/resolver/webpack-resolver.test.js.map +0 -1
- package/dist/runner.d.ts +0 -76
- package/dist/runner.js +0 -120
- package/dist/runner.js.map +0 -1
- package/dist/runner.test.d.ts +0 -1
- package/dist/runner.test.js +0 -287
- package/dist/runner.test.js.map +0 -1
- package/dist/test-util/jest/resolver.cjs +0 -31
- package/dist/test-util/jest/resolver.cjs.map +0 -1
- package/dist/test-util/jest/resolver.d.cts +0 -16
- package/dist/test-util/tsserver.d.ts +0 -31
- package/dist/test-util/tsserver.js +0 -112
- package/dist/test-util/tsserver.js.map +0 -1
- package/dist/test-util/util.d.ts +0 -28
- package/dist/test-util/util.js +0 -81
- package/dist/test-util/util.js.map +0 -1
- package/dist/transformer/index.d.ts +0 -30
- package/dist/transformer/index.js +0 -25
- package/dist/transformer/index.js.map +0 -1
- package/dist/transformer/index.test.d.ts +0 -1
- package/dist/transformer/index.test.js +0 -66
- package/dist/transformer/index.test.js.map +0 -1
- package/dist/transformer/less-transformer.d.ts +0 -2
- package/dist/transformer/less-transformer.js +0 -45
- package/dist/transformer/less-transformer.js.map +0 -1
- package/dist/transformer/less-transformer.test.d.ts +0 -1
- package/dist/transformer/less-transformer.test.js +0 -124
- package/dist/transformer/less-transformer.test.js.map +0 -1
- package/dist/transformer/postcss-transformer.d.ts +0 -12
- package/dist/transformer/postcss-transformer.js +0 -32
- package/dist/transformer/postcss-transformer.js.map +0 -1
- package/dist/transformer/postcss-transformer.test.d.ts +0 -1
- package/dist/transformer/postcss-transformer.test.js +0 -176
- package/dist/transformer/postcss-transformer.test.js.map +0 -1
- package/dist/transformer/scss-transformer.d.ts +0 -2
- package/dist/transformer/scss-transformer.js +0 -40
- package/dist/transformer/scss-transformer.js.map +0 -1
- package/dist/transformer/scss-transformer.test.d.ts +0 -1
- package/dist/transformer/scss-transformer.test.js +0 -130
- package/dist/transformer/scss-transformer.test.js.map +0 -1
- package/dist/util.d.ts +0 -21
- package/dist/util.js +0 -72
- package/dist/util.js.map +0 -1
- package/dist/util.test.d.ts +0 -1
- package/dist/util.test.js +0 -74
- package/dist/util.test.js.map +0 -1
package/package.json
CHANGED
package/src/emitter/dts.test.ts
CHANGED
|
@@ -211,9 +211,9 @@ describe('generateDtsContentWithSourceMap', () => {
|
|
|
211
211
|
});
|
|
212
212
|
test('emit other directory', async () => {
|
|
213
213
|
createFixtures({
|
|
214
|
-
'/test/1.css': `.a {}`,
|
|
214
|
+
'/test/src/1.css': `.a {}`,
|
|
215
215
|
});
|
|
216
|
-
const result = await locator.load(
|
|
216
|
+
const result = await locator.load(getFixturePath('/test/src/1.css'));
|
|
217
217
|
const { dtsContent, sourceMap } = generateDtsContentWithSourceMap(
|
|
218
218
|
getFixturePath('/test/src/1.css'),
|
|
219
219
|
getFixturePath('/test/dist/1.css.d.ts'),
|
|
@@ -224,7 +224,7 @@ describe('generateDtsContentWithSourceMap', () => {
|
|
|
224
224
|
);
|
|
225
225
|
expect(dtsContent).toMatchInlineSnapshot(`
|
|
226
226
|
"declare const styles:
|
|
227
|
-
& Readonly<
|
|
227
|
+
& Readonly<{ "a": string }>
|
|
228
228
|
;
|
|
229
229
|
export default styles;
|
|
230
230
|
"
|
package/src/emitter/dts.ts
CHANGED
|
@@ -28,18 +28,26 @@ function dashesCamelCase(str: string): string {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
function formatTokens(tokens: Token[], localsConvention: LocalsConvention): Token[] {
|
|
31
|
+
function formatToken(token: Token, formatter: (str: string) => string): Token {
|
|
32
|
+
if ('importedName' in token && typeof token.importedName === 'string') {
|
|
33
|
+
return { ...token, name: formatter(token.name), importedName: formatter(token.importedName) };
|
|
34
|
+
} else {
|
|
35
|
+
return { ...token, name: formatter(token.name) };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
31
39
|
const result: Token[] = [];
|
|
32
40
|
for (const token of tokens) {
|
|
33
41
|
if (localsConvention === 'camelCaseOnly') {
|
|
34
|
-
result.push(
|
|
42
|
+
result.push(formatToken(token, camelcase));
|
|
35
43
|
} else if (localsConvention === 'camelCase') {
|
|
36
44
|
result.push(token);
|
|
37
|
-
result.push(
|
|
45
|
+
result.push(formatToken(token, camelcase));
|
|
38
46
|
} else if (localsConvention === 'dashesOnly') {
|
|
39
|
-
result.push(
|
|
47
|
+
result.push(formatToken(token, dashesCamelCase));
|
|
40
48
|
} else if (localsConvention === 'dashes') {
|
|
41
49
|
result.push(token);
|
|
42
|
-
result.push(
|
|
50
|
+
result.push(formatToken(token, dashesCamelCase));
|
|
43
51
|
} else {
|
|
44
52
|
result.push(token); // asIs
|
|
45
53
|
}
|
|
@@ -62,41 +70,55 @@ function generateTokenDeclarations(
|
|
|
62
70
|
// This is due to the sourcemap specification. Therefore, we output multiple type definitions
|
|
63
71
|
// with the same name and assign a separate original position to each.
|
|
64
72
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
let originalLocation = token.originalLocation;
|
|
74
|
+
if (originalLocation.filePath === undefined) {
|
|
75
|
+
// If the original location is not specified, fallback to the source file.
|
|
76
|
+
originalLocation = {
|
|
77
|
+
filePath,
|
|
78
|
+
start: { line: 1, column: 1 },
|
|
79
|
+
end: { line: 1, column: 1 },
|
|
80
|
+
};
|
|
81
|
+
}
|
|
74
82
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
`"${token.name}"`,
|
|
85
|
-
token.name,
|
|
86
|
-
),
|
|
87
|
-
': string }>',
|
|
88
|
-
])
|
|
89
|
-
: // Imported tokens in non-external files are typed by dynamic import.
|
|
90
|
-
// See https://github.com/mizdra/happy-css-modules/issues/106.
|
|
91
|
-
new SourceNode(null, null, null, [
|
|
92
|
-
'& Readonly<Pick<(typeof import(',
|
|
93
|
-
`"${getRelativePath(filePath, originalLocation.filePath)}"`,
|
|
94
|
-
'))["default"], ',
|
|
83
|
+
result.push(
|
|
84
|
+
originalLocation.filePath === filePath || isExternalFile(originalLocation.filePath)
|
|
85
|
+
? new SourceNode(null, null, null, [
|
|
86
|
+
'& Readonly<{ ',
|
|
87
|
+
new SourceNode(
|
|
88
|
+
originalLocation.start.line ?? null,
|
|
89
|
+
// The SourceNode's column is 0-based, but the originalLocation's column is 1-based.
|
|
90
|
+
originalLocation.start.column - 1 ?? null,
|
|
91
|
+
getRelativePath(sourceMapFilePath, originalLocation.filePath),
|
|
95
92
|
`"${token.name}"`,
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
93
|
+
token.name,
|
|
94
|
+
),
|
|
95
|
+
': string }>',
|
|
96
|
+
])
|
|
97
|
+
: typeof token.importedName === 'string'
|
|
98
|
+
? new SourceNode(null, null, null, [
|
|
99
|
+
`& Readonly<{ `,
|
|
100
|
+
new SourceNode(
|
|
101
|
+
originalLocation.start.line ?? null,
|
|
102
|
+
// The SourceNode's column is 0-based, but the originalLocation's column is 1-based.
|
|
103
|
+
originalLocation.start.column - 1 ?? null,
|
|
104
|
+
getRelativePath(sourceMapFilePath, originalLocation.filePath),
|
|
105
|
+
`"${token.name}"`,
|
|
106
|
+
token.name,
|
|
107
|
+
),
|
|
108
|
+
`: (typeof import(`,
|
|
109
|
+
`"${getRelativePath(filePath, originalLocation.filePath)}"`,
|
|
110
|
+
`))["default"]["${token.importedName}"] }>`,
|
|
111
|
+
])
|
|
112
|
+
: // Imported tokens in non-external files are typed by dynamic import.
|
|
113
|
+
// See https://github.com/mizdra/happy-css-modules/issues/106.
|
|
114
|
+
new SourceNode(null, null, null, [
|
|
115
|
+
'& Readonly<Pick<(typeof import(',
|
|
116
|
+
`"${getRelativePath(filePath, originalLocation.filePath)}"`,
|
|
117
|
+
'))["default"], ',
|
|
118
|
+
`"${token.name}"`,
|
|
119
|
+
'>>',
|
|
120
|
+
]),
|
|
121
|
+
);
|
|
100
122
|
}
|
|
101
123
|
return result;
|
|
102
124
|
}
|
|
@@ -25,7 +25,7 @@ test('isSubDirectoryFile', () => {
|
|
|
25
25
|
describe('emitGeneratedFiles', () => {
|
|
26
26
|
const defaultArgs = {
|
|
27
27
|
filePath: getFixturePath('/test/1.css'),
|
|
28
|
-
tokens: [fakeToken({ name: 'foo',
|
|
28
|
+
tokens: [fakeToken({ name: 'foo', originalLocation: { start: { line: 1, column: 1 } } })],
|
|
29
29
|
emitDeclarationMap: true,
|
|
30
30
|
dtsFormatOptions: undefined,
|
|
31
31
|
cwd: getFixturePath('/test'),
|
|
@@ -55,7 +55,7 @@ describe('emitGeneratedFiles', () => {
|
|
|
55
55
|
expect(await exists(getFixturePath('/test/1.css.d.ts.map'))).toBeFalsy();
|
|
56
56
|
});
|
|
57
57
|
test('skips writing to disk if the generated files are the same', async () => {
|
|
58
|
-
const tokens1 = [fakeToken({ name: 'foo',
|
|
58
|
+
const tokens1 = [fakeToken({ name: 'foo', originalLocation: { start: { line: 1, column: 1 } } })];
|
|
59
59
|
await emitGeneratedFiles({ ...defaultArgs, tokens: tokens1 });
|
|
60
60
|
const mtimeForDts1 = (await stat(getFixturePath('/test/1.css.d.ts'))).mtime;
|
|
61
61
|
const mtimeForSourceMap1 = (await stat(getFixturePath('/test/1.css.d.ts.map'))).mtime;
|
|
@@ -68,7 +68,7 @@ describe('emitGeneratedFiles', () => {
|
|
|
68
68
|
expect(mtimeForSourceMap1).toEqual(mtimeForSourceMap2); // skipped
|
|
69
69
|
|
|
70
70
|
await waitForAsyncTask(1); // so that mtime changes.
|
|
71
|
-
const tokens2 = [fakeToken({ name: 'bar',
|
|
71
|
+
const tokens2 = [fakeToken({ name: 'bar', originalLocation: { start: { line: 1, column: 1 } } })];
|
|
72
72
|
await emitGeneratedFiles({ ...defaultArgs, tokens: tokens2 });
|
|
73
73
|
const mtimeForDts3 = (await stat(getFixturePath('/test/1.css.d.ts'))).mtime;
|
|
74
74
|
const mtimeForSourceMap3 = (await stat(getFixturePath('/test/1.css.d.ts.map'))).mtime;
|
|
@@ -22,15 +22,19 @@ test('basic', async () => {
|
|
|
22
22
|
tokens: [
|
|
23
23
|
{
|
|
24
24
|
name: "a",
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
originalLocation: {
|
|
26
|
+
filePath: "<fixtures>/test/1.css",
|
|
27
|
+
start: { line: 1, column: 1 },
|
|
28
|
+
end: { line: 1, column: 2 },
|
|
29
|
+
},
|
|
28
30
|
},
|
|
29
31
|
{
|
|
30
32
|
name: "b",
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
originalLocation: {
|
|
34
|
+
filePath: "<fixtures>/test/1.css",
|
|
35
|
+
start: { line: 2, column: 1 },
|
|
36
|
+
end: { line: 2, column: 2 },
|
|
37
|
+
},
|
|
34
38
|
},
|
|
35
39
|
],
|
|
36
40
|
}
|
|
@@ -74,27 +78,35 @@ test('tracks other files when `@import` is present', async () => {
|
|
|
74
78
|
tokens: [
|
|
75
79
|
{
|
|
76
80
|
name: "a",
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
originalLocation: {
|
|
82
|
+
filePath: "<fixtures>/test/2.css",
|
|
83
|
+
start: { line: 1, column: 1 },
|
|
84
|
+
end: { line: 1, column: 2 },
|
|
85
|
+
},
|
|
80
86
|
},
|
|
81
87
|
{
|
|
82
88
|
name: "b",
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
89
|
+
originalLocation: {
|
|
90
|
+
filePath: "<fixtures>/test/3.css",
|
|
91
|
+
start: { line: 1, column: 1 },
|
|
92
|
+
end: { line: 1, column: 2 },
|
|
93
|
+
},
|
|
86
94
|
},
|
|
87
95
|
{
|
|
88
96
|
name: "c",
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
97
|
+
originalLocation: {
|
|
98
|
+
filePath: "<fixtures>/test/4.css",
|
|
99
|
+
start: { line: 1, column: 1 },
|
|
100
|
+
end: { line: 1, column: 2 },
|
|
101
|
+
},
|
|
92
102
|
},
|
|
93
103
|
{
|
|
94
104
|
name: "d",
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
105
|
+
originalLocation: {
|
|
106
|
+
filePath: "<fixtures>/test/5-recursive.css",
|
|
107
|
+
start: { line: 1, column: 1 },
|
|
108
|
+
end: { line: 1, column: 2 },
|
|
109
|
+
},
|
|
98
110
|
},
|
|
99
111
|
],
|
|
100
112
|
}
|
|
@@ -120,16 +132,69 @@ test('does not track other files by `composes`', async () => {
|
|
|
120
132
|
tokens: [
|
|
121
133
|
{
|
|
122
134
|
name: "a",
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
135
|
+
originalLocation: {
|
|
136
|
+
filePath: "<fixtures>/test/1.css",
|
|
137
|
+
start: { line: 1, column: 1 },
|
|
138
|
+
end: { line: 1, column: 2 },
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
}
|
|
143
|
+
`);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test('tracks other files when `@value` is present', async () => {
|
|
147
|
+
createFixtures({
|
|
148
|
+
'/test/1.css': dedent`
|
|
149
|
+
@value a from './2.css';
|
|
150
|
+
@value b from '3.css';
|
|
151
|
+
@value c from '${getFixturePath('/test/4.css')}';
|
|
152
|
+
`,
|
|
153
|
+
'/test/2.css': dedent`
|
|
154
|
+
@value a: 1;
|
|
155
|
+
`,
|
|
156
|
+
'/test/3.css': dedent`
|
|
157
|
+
@value b: 2;
|
|
158
|
+
`,
|
|
159
|
+
'/test/4.css': dedent`
|
|
160
|
+
@value c: 3;
|
|
161
|
+
`,
|
|
162
|
+
});
|
|
163
|
+
const result = await locator.load(getFixturePath('/test/1.css'));
|
|
164
|
+
expect(result).toMatchInlineSnapshot(`
|
|
165
|
+
{
|
|
166
|
+
dependencies: ["<fixtures>/test/2.css", "<fixtures>/test/3.css", "<fixtures>/test/4.css"],
|
|
167
|
+
tokens: [
|
|
168
|
+
{
|
|
169
|
+
name: "a",
|
|
170
|
+
originalLocation: {
|
|
171
|
+
filePath: "<fixtures>/test/2.css",
|
|
172
|
+
start: { line: 1, column: 8 },
|
|
173
|
+
end: { line: 1, column: 9 },
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
name: "b",
|
|
178
|
+
originalLocation: {
|
|
179
|
+
filePath: "<fixtures>/test/3.css",
|
|
180
|
+
start: { line: 1, column: 8 },
|
|
181
|
+
end: { line: 1, column: 9 },
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: "c",
|
|
186
|
+
originalLocation: {
|
|
187
|
+
filePath: "<fixtures>/test/4.css",
|
|
188
|
+
start: { line: 1, column: 8 },
|
|
189
|
+
end: { line: 1, column: 9 },
|
|
190
|
+
},
|
|
126
191
|
},
|
|
127
192
|
],
|
|
128
193
|
}
|
|
129
194
|
`);
|
|
130
195
|
});
|
|
131
196
|
|
|
132
|
-
test('
|
|
197
|
+
test('unique tokens', async () => {
|
|
133
198
|
createFixtures({
|
|
134
199
|
'/test/1.css': dedent`
|
|
135
200
|
/* duplicate import */
|
|
@@ -142,9 +207,6 @@ test('normalizes tokens', async () => {
|
|
|
142
207
|
.a {} /* class selector that duplicates the import source */
|
|
143
208
|
.b {}
|
|
144
209
|
`,
|
|
145
|
-
'/test/3.css': dedent`
|
|
146
|
-
.c {}
|
|
147
|
-
`,
|
|
148
210
|
});
|
|
149
211
|
const result = await locator.load(getFixturePath('/test/1.css'));
|
|
150
212
|
expect(result).toMatchInlineSnapshot(`
|
|
@@ -153,17 +215,35 @@ test('normalizes tokens', async () => {
|
|
|
153
215
|
tokens: [
|
|
154
216
|
{
|
|
155
217
|
name: "a",
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
218
|
+
originalLocation: {
|
|
219
|
+
filePath: "<fixtures>/test/2.css",
|
|
220
|
+
start: { line: 1, column: 1 },
|
|
221
|
+
end: { line: 1, column: 2 },
|
|
222
|
+
},
|
|
161
223
|
},
|
|
162
224
|
{
|
|
163
225
|
name: "b",
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
226
|
+
originalLocation: {
|
|
227
|
+
filePath: "<fixtures>/test/2.css",
|
|
228
|
+
start: { line: 2, column: 1 },
|
|
229
|
+
end: { line: 2, column: 2 },
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
name: "a",
|
|
234
|
+
originalLocation: {
|
|
235
|
+
filePath: "<fixtures>/test/1.css",
|
|
236
|
+
start: { line: 4, column: 1 },
|
|
237
|
+
end: { line: 4, column: 2 },
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
name: "a",
|
|
242
|
+
originalLocation: {
|
|
243
|
+
filePath: "<fixtures>/test/1.css",
|
|
244
|
+
start: { line: 5, column: 1 },
|
|
245
|
+
end: { line: 5, column: 2 },
|
|
246
|
+
},
|
|
167
247
|
},
|
|
168
248
|
],
|
|
169
249
|
}
|
|
@@ -233,16 +313,27 @@ describe('supports sourcemap', () => {
|
|
|
233
313
|
tokens: [
|
|
234
314
|
{
|
|
235
315
|
name: "nesting",
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
316
|
+
originalLocation: {
|
|
317
|
+
filePath: "<fixtures>/test/1.scss",
|
|
318
|
+
start: { line: 1, column: 1 },
|
|
319
|
+
end: { line: 1, column: 8 },
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
name: "nesting",
|
|
324
|
+
originalLocation: {
|
|
325
|
+
filePath: "<fixtures>/test/1.scss",
|
|
326
|
+
start: { line: 3, column: 3 },
|
|
327
|
+
end: { line: 3, column: 10 },
|
|
328
|
+
},
|
|
240
329
|
},
|
|
241
330
|
{
|
|
242
331
|
name: "nesting_child",
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
332
|
+
originalLocation: {
|
|
333
|
+
filePath: "<fixtures>/test/1.scss",
|
|
334
|
+
start: { line: 3, column: 3 },
|
|
335
|
+
end: { line: 3, column: 16 },
|
|
336
|
+
},
|
|
246
337
|
},
|
|
247
338
|
],
|
|
248
339
|
}
|
|
@@ -272,18 +363,22 @@ describe('supports sourcemap', () => {
|
|
|
272
363
|
tokens: [
|
|
273
364
|
{
|
|
274
365
|
name: "selector_list_a_1",
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
366
|
+
originalLocation: {
|
|
367
|
+
filePath: "<fixtures>/test/1.css",
|
|
368
|
+
start: { line: 1, column: 1 },
|
|
369
|
+
end: { line: 1, column: 18 },
|
|
370
|
+
},
|
|
278
371
|
},
|
|
279
372
|
{
|
|
280
373
|
name: "selector_list_a_2",
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
374
|
+
originalLocation: {
|
|
375
|
+
filePath: "<fixtures>/test/1.css",
|
|
376
|
+
start: { line: 1, column: 1 },
|
|
377
|
+
end: { line: 1, column: 18 },
|
|
378
|
+
},
|
|
284
379
|
},
|
|
285
|
-
{ name: "selector_list_b_1",
|
|
286
|
-
{ name: "selector_list_b_2",
|
|
380
|
+
{ name: "selector_list_b_1", originalLocation: {} },
|
|
381
|
+
{ name: "selector_list_b_2", originalLocation: {} },
|
|
287
382
|
],
|
|
288
383
|
}
|
|
289
384
|
`);
|
package/src/locator/index.ts
CHANGED
|
@@ -4,7 +4,15 @@ import type { Resolver } from '../resolver/index.js';
|
|
|
4
4
|
import { createDefaultResolver } from '../resolver/index.js';
|
|
5
5
|
import { createDefaultTransformer, type Transformer } from '../transformer/index.js';
|
|
6
6
|
import { unique, uniqueBy } from '../util.js';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
getOriginalLocationOfClassSelector,
|
|
9
|
+
getOriginalLocationOfAtValue,
|
|
10
|
+
generateLocalTokenNames,
|
|
11
|
+
parseAtImport,
|
|
12
|
+
type Location,
|
|
13
|
+
collectNodes,
|
|
14
|
+
parseAtValue,
|
|
15
|
+
} from './postcss.js';
|
|
8
16
|
|
|
9
17
|
export { collectNodes, type Location } from './postcss.js';
|
|
10
18
|
|
|
@@ -20,8 +28,10 @@ function isIgnoredSpecifier(specifier: string): boolean {
|
|
|
20
28
|
export type Token = {
|
|
21
29
|
/** The token name. */
|
|
22
30
|
name: string;
|
|
23
|
-
/** The
|
|
24
|
-
|
|
31
|
+
/** The name of the imported token. */
|
|
32
|
+
importedName?: string;
|
|
33
|
+
/** The original location of the token in the source file. */
|
|
34
|
+
originalLocation: Location;
|
|
25
35
|
};
|
|
26
36
|
|
|
27
37
|
type CacheEntry = {
|
|
@@ -37,22 +47,6 @@ export type LoadResult = {
|
|
|
37
47
|
tokens: Token[];
|
|
38
48
|
};
|
|
39
49
|
|
|
40
|
-
function normalizeTokens(tokens: Token[]): Token[] {
|
|
41
|
-
const tokenNameToOriginalLocations = new Map<string, Location[]>();
|
|
42
|
-
for (const token of tokens) {
|
|
43
|
-
tokenNameToOriginalLocations.set(
|
|
44
|
-
token.name,
|
|
45
|
-
uniqueBy([...(tokenNameToOriginalLocations.get(token.name) ?? []), ...token.originalLocations], (location) =>
|
|
46
|
-
JSON.stringify(location),
|
|
47
|
-
),
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
return Array.from(tokenNameToOriginalLocations.entries()).map(([name, originalLocations]) => ({
|
|
51
|
-
name,
|
|
52
|
-
originalLocations,
|
|
53
|
-
}));
|
|
54
|
-
}
|
|
55
|
-
|
|
56
50
|
export type LocatorOptions = {
|
|
57
51
|
/** The function to transform source code. */
|
|
58
52
|
transformer?: Transformer | undefined;
|
|
@@ -158,7 +152,7 @@ export class Locator {
|
|
|
158
152
|
|
|
159
153
|
const tokens: Token[] = [];
|
|
160
154
|
|
|
161
|
-
const { atImports, classSelectors } = collectNodes(ast);
|
|
155
|
+
const { atImports, atValues, classSelectors } = collectNodes(ast);
|
|
162
156
|
|
|
163
157
|
// Load imported sheets recursively.
|
|
164
158
|
for (const atImport of atImports) {
|
|
@@ -180,17 +174,51 @@ export class Locator {
|
|
|
180
174
|
// NOTE: This method has false positives. However, it works as expected in many cases.
|
|
181
175
|
if (!localTokenNames.includes(classSelector.value)) continue;
|
|
182
176
|
|
|
183
|
-
const originalLocation =
|
|
177
|
+
const originalLocation = getOriginalLocationOfClassSelector(rule, classSelector);
|
|
184
178
|
|
|
185
179
|
tokens.push({
|
|
186
180
|
name: classSelector.value,
|
|
187
|
-
|
|
181
|
+
originalLocation,
|
|
188
182
|
});
|
|
189
183
|
}
|
|
190
184
|
|
|
185
|
+
for (const atValue of atValues) {
|
|
186
|
+
const parsedAtValue = parseAtValue(atValue);
|
|
187
|
+
|
|
188
|
+
if (parsedAtValue.type === 'valueDeclaration') {
|
|
189
|
+
tokens.push({
|
|
190
|
+
name: parsedAtValue.tokenName,
|
|
191
|
+
originalLocation: getOriginalLocationOfAtValue(atValue, parsedAtValue),
|
|
192
|
+
});
|
|
193
|
+
} else if (parsedAtValue.type === 'valueImportDeclaration') {
|
|
194
|
+
if (isIgnoredSpecifier(parsedAtValue.from)) continue;
|
|
195
|
+
// eslint-disable-next-line no-await-in-loop
|
|
196
|
+
const from = await this.resolver(parsedAtValue.from, { request: filePath });
|
|
197
|
+
// eslint-disable-next-line no-await-in-loop
|
|
198
|
+
const result = await this._load(from);
|
|
199
|
+
dependencies.push(from, ...result.dependencies);
|
|
200
|
+
for (const token of result.tokens) {
|
|
201
|
+
const matchedImport = parsedAtValue.imports.find((i) => i.importedTokenName === token.name);
|
|
202
|
+
if (!matchedImport) continue;
|
|
203
|
+
if (matchedImport.localTokenName === matchedImport.importedTokenName) {
|
|
204
|
+
tokens.push({
|
|
205
|
+
name: matchedImport.localTokenName,
|
|
206
|
+
originalLocation: token.originalLocation,
|
|
207
|
+
});
|
|
208
|
+
} else {
|
|
209
|
+
tokens.push({
|
|
210
|
+
name: matchedImport.localTokenName,
|
|
211
|
+
importedName: matchedImport.importedTokenName,
|
|
212
|
+
originalLocation: token.originalLocation,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
191
219
|
const result: LoadResult = {
|
|
192
220
|
dependencies: unique(dependencies).filter((dep) => dep !== filePath),
|
|
193
|
-
tokens:
|
|
221
|
+
tokens: uniqueBy(tokens, (token) => JSON.stringify(token)),
|
|
194
222
|
};
|
|
195
223
|
this.cache.set(filePath, { mtime, result });
|
|
196
224
|
return result;
|