diff --git a/packages/cli/README.md b/packages/cli/README.md index fdd73fa3b..1e3e94ea3 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -110,7 +110,9 @@ export interface BuildOptions { minify?: boolean; /** should generate .d.ts definitions for every stylesheet */ dts?: boolean; - /** should generate .d.ts.map files for every .d.ts mapping back to the source .st.css */ + /** should generate .d.ts.map files for every .d.ts mapping back to the source .st.css. + * It will use the origin file path unless `outputSources` is true, then it will use the outputted file path as the source-map source. + */ dtsSourceMap?: boolean; /** should emit diagnostics */ diagnostics?: boolean; diff --git a/packages/cli/src/build-single-file.ts b/packages/cli/src/build-single-file.ts index 309068e7a..fbe0389f3 100644 --- a/packages/cli/src/build-single-file.ts +++ b/packages/cli/src/build-single-file.ts @@ -175,7 +175,12 @@ export function buildSingleFile({ // .d.ts.map // if not explicitly defined, assumed true with "--dts" parent scope if (dtsSourceMap !== false) { - const dtsMappingContent = generateDTSSourceMap(dtsContent, res.meta); + const dtsMappingContent = generateDTSSourceMap( + dtsContent, + res.meta, + relative(dirname(outSrcPath), dirname(outputSources ? outSrcPath : filePath)) + ); + const dtsMapPath = outSrcPath + '.d.ts.map'; generated.add(dtsMapPath); diff --git a/packages/cli/src/config/resolve-options.ts b/packages/cli/src/config/resolve-options.ts index cd991f3df..d6ec7383f 100644 --- a/packages/cli/src/config/resolve-options.ts +++ b/packages/cli/src/config/resolve-options.ts @@ -57,7 +57,7 @@ export function getCliArguments(): Arguments { .option('dtsSourceMap', { type: 'boolean', description: - 'output source maps for stylable definition files for sources (.st.css.d.ts.map)', + 'output source maps for stylable definition files for sources (.st.css.d.ts.map). It will use the origin file path unless `--stcss` is set, then it will use the outputted file path as the source-map source', defaultDescription: 'true if "--dts" option is enabled, otherwise false', }) .option('useNamespaceReference', { diff --git a/packages/cli/test/cli.spec.ts b/packages/cli/test/cli.spec.ts index 35e80e347..d598454b5 100644 --- a/packages/cli/test/cli.spec.ts +++ b/packages/cli/test/cli.spec.ts @@ -164,6 +164,55 @@ describe('Stylable Cli', function () { ).to.equal(true); }); + it('build .st.css.d.ts source-map and target the source file path relatively', () => { + const srcContent = '.root{color:red}'; + populateDirectorySync(tempDir.path, { + 'package.json': `{"name": "test", "version": "0.0.0"}`, + src: { 'style.st.css': srcContent }, + }); + + runCliSync(['--rootDir', tempDir.path, '--srcDir', './src', '--outDir', 'dist', '--dts']); + + const dirContent = loadDirSync(tempDir.path); + const dtsSourceMapContent = dirContent['dist/style.st.css.d.ts.map']; + + expect( + dtsSourceMapContent.startsWith('{\n "version": 3,\n "file": "style.st.css.d.ts"') + ).to.equal(true); + expect(dtsSourceMapContent).to.contain( + `"sources": [\n ${JSON.stringify(join('..', 'src', 'style.st.css'))}\n ]` + ); + }); + + it('build .st.css.d.ts source-map and target the output source file path', () => { + const srcContent = '.root{color:red}'; + populateDirectorySync(tempDir.path, { + 'package.json': `{"name": "test", "version": "0.0.0"}`, + src: { 'style.st.css': srcContent }, + 'stylable.config.js': ` + exports.stcConfig = { + options: { + outDir: './dist', + srcDir: './src', + outputSources: true, + cjs: false, + dts: true, + } + }; + `, + }); + + runCliSync(['--rootDir', tempDir.path]); + + const dirContent = loadDirSync(tempDir.path); + const dtsSourceMapContent = dirContent['dist/style.st.css.d.ts.map']; + + expect( + dtsSourceMapContent.startsWith('{\n "version": 3,\n "file": "style.st.css.d.ts"') + ).to.equal(true); + expect(dtsSourceMapContent).to.contain(`"sources": [\n "style.st.css"\n ]`); + }); + it('build .st.css.d.ts alongside source files with source-maps on by default (config file)', () => { const srcContent = '.root{color:red}'; populateDirectorySync(tempDir.path, { diff --git a/packages/module-utils/src/generate-dts-sourcemaps.ts b/packages/module-utils/src/generate-dts-sourcemaps.ts index 46f082a95..69fc491a2 100644 --- a/packages/module-utils/src/generate-dts-sourcemaps.ts +++ b/packages/module-utils/src/generate-dts-sourcemaps.ts @@ -1,4 +1,4 @@ -import { basename } from 'path'; +import { basename, join } from 'path'; import { ClassSymbol, StylableMeta, valueMapping } from '@stylable/core'; import { STSymbol, CSSKeyframes } from '@stylable/core/dist/features'; import { processDeclarationFunctions } from '@stylable/core/dist/process-declaration-functions'; @@ -240,7 +240,11 @@ function getClassSourceName(targetName: string, classTokens: ClassesToken): stri return; } -export function generateDTSSourceMap(dtsContent: string, meta: StylableMeta) { +export function generateDTSSourceMap( + dtsContent: string, + meta: StylableMeta, + sourceDirPath?: string +) { const tokens = tokenizeDTS(dtsContent); const mapping: Record = {}; const lines = dtsContent.split('\n'); @@ -312,7 +316,7 @@ export function generateDTSSourceMap(dtsContent: string, meta: StylableMeta) { { version: 3, file: `${stylesheetName}.d.ts`, - sources: [stylesheetName], + sources: [sourceDirPath ? join(sourceDirPath, stylesheetName) : stylesheetName], names: [], mappings: Object.values(mapping) .map((segment) => (segment.length ? segment.map((s) => encode(s)).join(',') : '')) diff --git a/packages/module-utils/test/sourcemap.spec.ts b/packages/module-utils/test/sourcemap.spec.ts index 1505e23d7..f390f88ea 100644 --- a/packages/module-utils/test/sourcemap.spec.ts +++ b/packages/module-utils/test/sourcemap.spec.ts @@ -2,6 +2,7 @@ import { generateStylableResult } from '@stylable/core-test-kit'; import { generateDTSSourceMap, generateDTSContent } from '@stylable/module-utils'; import { expect } from 'chai'; import deindent from 'deindent'; +import { join } from 'path'; import { SourceMapConsumer } from 'source-map'; function getPosition(content: string, query: string) { @@ -42,6 +43,8 @@ describe('.d.ts source-maps', () => { const dtsText = generateDTSContent(res); const sourcemapText = generateDTSSourceMap(dtsText, res.meta); + expect(JSON.parse(sourcemapText).sources).to.eql(['entry.st.css']); + sourceMapConsumer = await new SourceMapConsumer(sourcemapText); const originalPosition = sourceMapConsumer.originalPositionFor( getPosition(dtsText, 'root":') // source mapping starts after the first double quote @@ -50,6 +53,23 @@ describe('.d.ts source-maps', () => { expect(originalPosition).to.eql({ line: 1, column: 0, source: 'entry.st.css', name: null }); }); + it('should generate source maps and set specific file path as the source file path', () => { + const res = generateStylableResult({ + entry: `/entry.st.css`, + files: { + '/entry.st.css': { + namespace: 'entry', + content: ``, + }, + }, + }); + + const dtsText = generateDTSContent(res); + const sourcemapText = generateDTSSourceMap(dtsText, res.meta, 'src'); + + expect(JSON.parse(sourcemapText).sources).to.eql([join('src', 'entry.st.css')]); + }); + it('maps the "root" class in the ".d.ts" to its position in the original ".st.css" file', async () => { const res = generateStylableResult({ entry: `/entry.st.css`,