@c4a/extract-style 0.7.0 → 0.7.4

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.
Files changed (2) hide show
  1. package/index.js +111 -17
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -21982,6 +21982,8 @@ function keyTokens(key) {
21982
21982
  return key.replace(/([a-z0-9])([A-Z])/gu, "$1-$2").replace(/[^A-Za-z0-9]+/gu, "-").toLowerCase().split("-").filter(Boolean);
21983
21983
  }
21984
21984
  function sensitiveKey(key, value) {
21985
+ if (value === INDEXER_OUTPUT_REDACTION_MARKER)
21986
+ return false;
21985
21987
  const tokens = keyTokens(key);
21986
21988
  if (tokens.length === 0)
21987
21989
  return false;
@@ -22023,12 +22025,12 @@ function replaceWithCount(value, pattern, replacement, count) {
22023
22025
  function redactKnownText(value, count) {
22024
22026
  let output = value;
22025
22027
  output = replaceWithCount(output, /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/gu, INDEXER_OUTPUT_REDACTION_MARKER, count);
22026
- output = replaceWithCount(output, /(\bauthorization\s*:\s*(?:bearer|basic)\s+)[^\s,;]+/giu, (_match, prefix) => `${prefix}${INDEXER_OUTPUT_REDACTION_MARKER}`, count);
22028
+ output = replaceWithCount(output, new RegExp(`(\\bauthorization\\s*:\\s*(?:bearer|basic)\\s+)` + `(?!${escapeRegExp(INDEXER_OUTPUT_REDACTION_MARKER)})[^\\s,;]+`, "giu"), (_match, prefix) => `${prefix}${INDEXER_OUTPUT_REDACTION_MARKER}`, count);
22027
22029
  output = replaceWithCount(output, /([a-z][a-z0-9+.-]*:\/\/)[^\s/@:]+:[^\s/@]+@/giu, (_match, prefix) => `${prefix}${INDEXER_OUTPUT_REDACTION_MARKER}@`, count);
22028
- output = replaceWithCount(output, /([?&](?:access_token|refresh_token|api_key|password|secret)=)[^&#\s]+/giu, (_match, prefix) => `${prefix}${INDEXER_OUTPUT_REDACTION_MARKER}`, count);
22030
+ output = replaceWithCount(output, new RegExp(`([?&](?:access_token|refresh_token|api_key|password|secret)=)` + `(?!${escapeRegExp(INDEXER_OUTPUT_REDACTION_MARKER)})[^&#\\s]+`, "giu"), (_match, prefix) => `${prefix}${INDEXER_OUTPUT_REDACTION_MARKER}`, count);
22029
22031
  const key = "(?:[A-Za-z0-9_.-]*(?:password|passwd|pwd|secret|token|credential|cookie)[A-Za-z0-9_.-]*|api[-_]?key|access[-_]?(?:key|token)|private[-_]?key|client[-_]?secret|authorization)";
22030
22032
  const assignment = `(?:=\\s*|:\\s+(?=\\S)|:\\s*(?=["']))`;
22031
- output = replaceWithCount(output, new RegExp(`((?:["']?${key}["']?)\\s*${assignment})(?:"(?:\\\\.|[^"])*"|'(?:\\\\.|[^'])*'|[^\\s,;}\\]]+)`, "giu"), (_match, prefix) => `${prefix}"${INDEXER_OUTPUT_REDACTION_MARKER}"`, count);
22033
+ output = replaceWithCount(output, new RegExp(`((?:["']?${key}["']?)\\s*${assignment})` + `(?!["']?${escapeRegExp(INDEXER_OUTPUT_REDACTION_MARKER)})` + `(?:"(?:\\\\.|[^"])*"|'(?:\\\\.|[^'])*'|[^\\s,;}\\]]+)`, "giu"), (_match, prefix) => `${prefix}"${INDEXER_OUTPUT_REDACTION_MARKER}"`, count);
22032
22034
  return output;
22033
22035
  }
22034
22036
  function redactBlockedText(value, blocked, count) {
@@ -22296,6 +22298,25 @@ function createIndexerEvidenceAdapterFact(input) {
22296
22298
  FACT_PAYLOADS.set(fact2, payload);
22297
22299
  return fact2;
22298
22300
  }
22301
+ function indexerEvidenceAdapterFactPayloads(result) {
22302
+ const payloads = result.files.flatMap((file) => file.facts.map((fact2) => {
22303
+ const payload = FACT_PAYLOADS.get(fact2);
22304
+ if (payload === undefined) {
22305
+ throw new TypeError(`Evidence Adapter fact payload ${fact2.fact_ref} is no longer materialized in this process`);
22306
+ }
22307
+ if (indexerEvidenceAdapterProtocolDigest(payload) !== fact2.payload_digest) {
22308
+ throw new TypeError(`Evidence Adapter fact payload ${fact2.fact_ref} is stale`);
22309
+ }
22310
+ return { fact_ref: fact2.fact_ref, payload };
22311
+ })).sort((left, right) => compareCanonicalText(left.fact_ref, right.fact_ref));
22312
+ return assertIndexerOutputSafe({ channel: "ipc-envelope", value: payloads });
22313
+ }
22314
+ function materializeIndexerEvidenceAdapterResult(result) {
22315
+ return {
22316
+ result,
22317
+ fact_payloads: indexerEvidenceAdapterFactPayloads(result)
22318
+ };
22319
+ }
22299
22320
  function indexerEvidenceAdapterOutputDigest(value) {
22300
22321
  return indexerEvidenceAdapterProtocolDigest(value);
22301
22322
  }
@@ -22690,6 +22711,7 @@ var STATE_PSEUDOS = new Set([
22690
22711
  "visited"
22691
22712
  ]);
22692
22713
  var GENERIC_MODULE_NAMES = new Set(["global", "index", "style", "styles", "theme", "themes", "token", "tokens", "variable", "variables"]);
22714
+ var DYNAMIC_SELECTOR_TOKEN = "c4a_dynamic_";
22693
22715
  function locator2(path2, rule2, qualifiedItemPath) {
22694
22716
  return { path: path2, line: rule2.source?.start?.line ?? 1, column: rule2.source?.start?.column ?? 1, qualified_item_path: qualifiedItemPath };
22695
22717
  }
@@ -22724,6 +22746,53 @@ function moduleCandidate(path2) {
22724
22746
  const name = basename.replace(/\.module$/iu, "");
22725
22747
  return name.length > 0 && !GENERIC_MODULE_NAMES.has(name.toLowerCase()) ? name : null;
22726
22748
  }
22749
+ function maskScssSelectorInterpolation(selector) {
22750
+ let cursor = 0;
22751
+ let output = "";
22752
+ let dynamic = false;
22753
+ let ordinal = 0;
22754
+ while (cursor < selector.length) {
22755
+ const start = selector.indexOf("#{", cursor);
22756
+ if (start < 0) {
22757
+ output += selector.slice(cursor);
22758
+ break;
22759
+ }
22760
+ output += selector.slice(cursor, start);
22761
+ let index2 = start + 2;
22762
+ let depth = 1;
22763
+ let quote = null;
22764
+ while (index2 < selector.length && depth > 0) {
22765
+ const character = selector[index2];
22766
+ if (quote !== null) {
22767
+ if (character === "\\")
22768
+ index2 += 2;
22769
+ else {
22770
+ if (character === quote)
22771
+ quote = null;
22772
+ index2 += 1;
22773
+ }
22774
+ continue;
22775
+ }
22776
+ if (character === '"' || character === "'")
22777
+ quote = character;
22778
+ else if (character === "{")
22779
+ depth += 1;
22780
+ else if (character === "}")
22781
+ depth -= 1;
22782
+ index2 += 1;
22783
+ }
22784
+ if (depth !== 0)
22785
+ return null;
22786
+ output += `${DYNAMIC_SELECTOR_TOKEN}${ordinal}`;
22787
+ ordinal += 1;
22788
+ cursor = index2;
22789
+ dynamic = true;
22790
+ }
22791
+ return { text: output, dynamic };
22792
+ }
22793
+ function staticSelectorName(value) {
22794
+ return !value.includes(DYNAMIC_SELECTOR_TOKEN);
22795
+ }
22727
22796
  function parseSelectorNode(input) {
22728
22797
  const classNames = new Set;
22729
22798
  const idNames = new Set;
@@ -22731,20 +22800,25 @@ function parseSelectorNode(input) {
22731
22800
  const pseudoClasses = new Set;
22732
22801
  const attributeNames = new Set;
22733
22802
  input.selector.walkClasses((node2) => {
22734
- classNames.add(node2.value);
22803
+ if (staticSelectorName(node2.value))
22804
+ classNames.add(node2.value);
22735
22805
  });
22736
22806
  input.selector.walkIds((node2) => {
22737
- idNames.add(node2.value);
22807
+ if (staticSelectorName(node2.value))
22808
+ idNames.add(node2.value);
22738
22809
  });
22739
22810
  input.selector.walkTags((node2) => {
22740
- typeNames.add(node2.value);
22811
+ if (staticSelectorName(node2.value))
22812
+ typeNames.add(node2.value);
22741
22813
  });
22742
22814
  input.selector.walkPseudos((node2) => {
22743
- if (!node2.value.startsWith("::"))
22744
- pseudoClasses.add(node2.value.replace(/^:/u, ""));
22815
+ const value = node2.value.replace(/^:/u, "");
22816
+ if (!node2.value.startsWith("::") && staticSelectorName(value))
22817
+ pseudoClasses.add(value);
22745
22818
  });
22746
22819
  input.selector.walkAttributes((node2) => {
22747
- attributeNames.add(node2.attribute);
22820
+ if (staticSelectorName(node2.attribute))
22821
+ attributeNames.add(node2.attribute);
22748
22822
  });
22749
22823
  const qualifiedItemPath = `selector:${input.ordinal}`;
22750
22824
  const currentLocator = locator2(input.path, input.rule, qualifiedItemPath);
@@ -22752,7 +22826,7 @@ function parseSelectorNode(input) {
22752
22826
  const selectorRef = `${input.path}#${qualifiedItemPath}`;
22753
22827
  const catalog = {
22754
22828
  selector_ref: selectorRef,
22755
- selector_digest: indexerEvidenceAdapterProtocolDigest(selectorText),
22829
+ selector_digest: indexerEvidenceAdapterProtocolDigest(input.digestValue ?? selectorText),
22756
22830
  class_names: sorted(classNames),
22757
22831
  id_names: sorted(idNames),
22758
22832
  type_names: sorted(typeNames),
@@ -22780,8 +22854,9 @@ function parseSelectorNode(input) {
22780
22854
  addVariant("class-modifier", modifier);
22781
22855
  }
22782
22856
  const nestedModifier = /^&--([A-Za-z0-9_-]+)$/u.exec(selectorText.trim());
22783
- if (nestedModifier !== null)
22857
+ if (nestedModifier !== null && staticSelectorName(nestedModifier[1])) {
22784
22858
  addVariant("class-modifier", nestedModifier[1]);
22859
+ }
22785
22860
  const candidates = [];
22786
22861
  for (const name of classNames) {
22787
22862
  const root2 = classRoot(name);
@@ -22801,21 +22876,36 @@ function collectStyleSelectors(input) {
22801
22876
  if (inKeyframes(rule2))
22802
22877
  continue;
22803
22878
  const qualifiedItemPath = `selector:${selectors.length + 1}`;
22804
- if (rule2.selector.includes("#{")) {
22879
+ const masked = maskScssSelectorInterpolation(rule2.selector);
22880
+ if (masked === null) {
22805
22881
  unsupported = true;
22806
- diagnostics.push({ code: "style-selector-unsupported", severity: "error", locator: locator2(input.path, rule2, qualifiedItemPath), detail: "dynamic SCSS selector interpolation is unsupported" });
22882
+ diagnostics.push({ code: "style-selector-unsupported", severity: "error", locator: locator2(input.path, rule2, qualifiedItemPath), detail: "SCSS selector interpolation is malformed" });
22807
22883
  continue;
22808
22884
  }
22885
+ if (masked.dynamic) {
22886
+ diagnostics.push({
22887
+ code: "style-selector-dynamic-identity-omitted",
22888
+ severity: "warning",
22889
+ locator: locator2(input.path, rule2, qualifiedItemPath),
22890
+ detail: "dynamic SCSS selector identity is not expanded; only static selector evidence is cataloged"
22891
+ });
22892
+ }
22809
22893
  let root2;
22810
22894
  try {
22811
- root2 = import_postcss_selector_parser.default().astSync(rule2.selector);
22895
+ root2 = import_postcss_selector_parser.default().astSync(masked.text);
22812
22896
  } catch (error) {
22813
22897
  unsupported = true;
22814
22898
  diagnostics.push({ code: "style-selector-unsupported", severity: "error", locator: locator2(input.path, rule2, qualifiedItemPath), detail: error instanceof Error ? error.message : String(error) });
22815
22899
  continue;
22816
22900
  }
22817
- for (const selector of root2.nodes) {
22818
- const parsed = parseSelectorNode({ path: input.path, rule: rule2, selector, ordinal: selectors.length + 1 });
22901
+ for (const [selectorIndex, selector] of root2.nodes.entries()) {
22902
+ const parsed = parseSelectorNode({
22903
+ path: input.path,
22904
+ rule: rule2,
22905
+ selector,
22906
+ ordinal: selectors.length + 1,
22907
+ ...masked.dynamic ? { digestValue: { selector: rule2.selector, selector_ordinal: selectorIndex } } : {}
22908
+ });
22819
22909
  selectors.push(parsed.selector);
22820
22910
  variants.push(...parsed.variants);
22821
22911
  candidates.push(...parsed.candidates);
@@ -23039,11 +23129,15 @@ function styleSourcesToEvidenceAdapterResult(files, invocation) {
23039
23129
  }]
23040
23130
  });
23041
23131
  }
23132
+ function styleSourcesToEvidenceAdapterMaterialization(files, invocation) {
23133
+ return materializeIndexerEvidenceAdapterResult(styleSourcesToEvidenceAdapterResult(files, invocation));
23134
+ }
23042
23135
 
23043
23136
  // src/index.ts
23044
- var STYLE_EVIDENCE_ADAPTER_EXPORT = "styleSourcesToEvidenceAdapterResult";
23137
+ var STYLE_EVIDENCE_ADAPTER_EXPORT = "styleSourcesToEvidenceAdapterMaterialization";
23045
23138
  export {
23046
23139
  styleSourcesToEvidenceAdapterResult,
23140
+ styleSourcesToEvidenceAdapterMaterialization,
23047
23141
  parseStyleSources,
23048
23142
  STYLE_EVIDENCE_ADAPTER_EXPORT
23049
23143
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@c4a/extract-style",
3
- "version": "0.7.0",
3
+ "version": "0.7.4",
4
4
  "type": "module",
5
5
  "description": "Lightweight CSS and SCSS evidence adapter for Context",
6
6
  "license": "MIT",