Skip to content

Commit

Permalink
feat: api for custom props available in stylesheet
Browse files Browse the repository at this point in the history
- local name in context stylesheet
- local name in definition stylesheet
- transformed name
- source location (meta, start, end)
  • Loading branch information
idoros committed Mar 4, 2024
1 parent 9120966 commit 521949c
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 3 deletions.
46 changes: 44 additions & 2 deletions packages/core/src/features/css-custom-property.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@ import type { Stylable } from '../stylable';
import { validateAllowedNodesUntil, stringifyFunction } from '../helpers/value';
import { globalValue, GLOBAL_FUNC } from '../helpers/global';
import { plugableRecord } from '../helpers/plugable-record';
import { createDiagnosticReporter } from '../diagnostics';
import { createDiagnosticReporter, Diagnostics } from '../diagnostics';
import type { StylableMeta } from '../stylable-meta';
import type { StylableResolver, CSSResolve } from '../stylable-resolver';
import {
type StylableResolver,
type CSSResolve,
createSymbolResolverWithCache,
} from '../stylable-resolver';
import type * as postcss from 'postcss';
// ToDo: refactor out - parse once and pass to hooks
import postcssValueParser from 'postcss-value-parser';
Expand Down Expand Up @@ -292,6 +296,44 @@ const UNKNOWN_LOCATION = {

export class StylablePublicApi {
constructor(private stylable: Stylable) {}

public getProperties(meta: StylableMeta) {
const results: Record<
string,
{
meta: StylableMeta;
localName: string;
targetName: string;
source: {
meta: StylableMeta;
start: postcss.Position;
end: postcss.Position;
};
}
> = {};

const topLevelDiagnostics = new Diagnostics();
const getResolvedSymbols = createSymbolResolverWithCache(
this.stylable.resolver,
topLevelDiagnostics
);
const { cssVar } = getResolvedSymbols(meta);
for (const [name, symbol] of Object.entries(cssVar)) {
const defAst = STSymbol.getSymbolAstNode(symbol.meta, symbol.symbol);
results[name] = {
meta: symbol.meta,
localName: symbol.symbol.name,
targetName: getTransformedName(symbol),
source: {
meta: symbol.meta,
start: defAst?.source?.start || UNKNOWN_LOCATION,
end: defAst?.source?.end || UNKNOWN_LOCATION,
},
};
}

return results;
}
}

function analyzeDeclValueVarCalls(context: FeatureContext, decl: postcss.Declaration) {
Expand Down
129 changes: 128 additions & 1 deletion packages/core/test/features/css-custom-property.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import {
diagnosticBankReportToStrings,
deindent,
} from '@stylable/core-test-kit';
import { expect } from 'chai';
import chai, { expect } from 'chai';
import chaiSubset from 'chai-subset';
import type { StylableMeta } from '../../src';

chai.use(chaiSubset);

const stImportDiagnostics = diagnosticBankReportToStrings(STImport.diagnostics);
const stSymbolDiagnostics = diagnosticBankReportToStrings(STSymbol.diagnostics);
Expand Down Expand Up @@ -1105,4 +1109,127 @@ describe(`features/css-custom-property`, () => {
);
});
});
describe('introspection', () => {
function expectSourceLocation({
source: { meta, start, end },
expected,
}: {
source: { meta: StylableMeta; start: { offset: number }; end: { offset: number } };
expected: string;
}) {
const actualSrc = meta.sourceAst.toString().slice(start.offset, end.offset);
expect(actualSrc).to.eql(expected);
}
describe('getProperties', () => {
it('should resolve all local properties', () => {
const { stylable, sheets } = testStylableCore(
deindent(`
@property --defInAtRule {
syntax: '<color>';
initial-value: green;
inherits: false;
}
.root {
--defineInPropName: green;
color: var(--defineInDeclValue);
}
`)
);

const { meta } = sheets['/entry.st.css'];

const properties = stylable.cssCustomProperty.getProperties(meta);

expect(properties).to.containSubset({
'--defInAtRule': {
meta,
localName: '--defInAtRule',
targetName: '--entry-defInAtRule',
},
'--defineInPropName': {
meta,
localName: '--defineInPropName',
targetName: '--entry-defineInPropName',
},
'--defineInDeclValue': {
meta,
localName: '--defineInDeclValue',
targetName: '--entry-defineInDeclValue',
},
});
expectSourceLocation({
source: properties['--defInAtRule'].source,
expected: `@property --defInAtRule {\n syntax: '<color>';\n initial-value: green;\n inherits: false;\n}`,
});
expectSourceLocation({
source: properties['--defineInPropName'].source,
expected: `--defineInPropName: green;`,
});
expectSourceLocation({
source: properties['--defineInDeclValue'].source,
expected: `color: var(--defineInDeclValue);`,
});
});
it('should resolve imported properties', () => {
const { stylable, sheets } = testStylableCore({
'deep.st.css': `
.x {
--deep: red;
}
`,
'proxy.st.css': `
@st-import [--deep as --deepReassign1] from './deep.st.css';
.x {
--proxy: var(--deepReassign1);
}
`,
'entry.st.css': deindent(`
@st-import [--proxy as --proxyReassign, --deepReassign1 as --deepReassign2] from './proxy.st.css';
.x {
--local: green;
}
`),
});

const { meta } = sheets['/entry.st.css'];
const { meta: proxyMeta } = sheets['/proxy.st.css'];
const { meta: deepMeta } = sheets['/deep.st.css'];

const properties = stylable.cssCustomProperty.getProperties(meta);

expect(properties).to.containSubset({
'--local': {
meta,
localName: '--local',
targetName: '--entry-local',
},
'--proxyReassign': {
meta: proxyMeta,
localName: '--proxy',
targetName: '--proxy-proxy',
},
'--deepReassign2': {
meta: deepMeta,
localName: '--deep',
targetName: '--deep-deep',
},
});
expectSourceLocation({
source: properties['--local'].source,
expected: `--local: green;`,
});
expectSourceLocation({
source: properties['--proxyReassign'].source,
expected: `--proxy: var(--deepReassign1);`,
});
expectSourceLocation({
source: properties['--deepReassign2'].source,
expected: `--deep: red;`,
});
});
});
});
});

0 comments on commit 521949c

Please sign in to comment.